Skip to content

Commit cd73223

Browse files
authored
feat(python): make Python cleaning more selective (#4108)
Take a more selective approach to cleaning, removing files that are *expected* to be generated, rather than removing everything except explicitly-listed "keep" files. Files *can* still be listed to be kept, but don't have to be unless they're expected to be generated. This will allow libraries with a mixture of handwritten and generated code to add new handwritten files without the configuration file being updated, except for the (hopefully rare) cases where a new handwritten file "looks like" a generated file (in terms of which directory it's in and its name). This change does not modify the migration tool to reduce the size of the "keep" list yet, but that can happen later if and when we want it to. (There's a balance between removing unnecessary entries by hand, and putting the work into figuring out what's unnecessary automatically.)
1 parent 0c0b82b commit cd73223

11 files changed

Lines changed: 1257 additions & 2 deletions

File tree

doc/config-schema.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ This document describes the schema for the librarian.yaml.
6363
| `transport` | string | Transport is the transport protocol, such as "grpc+rest" or "grpc". |
6464
| `dart` | [DartPackage](#dartpackage-configuration) (optional) | Dart contains Dart-specific default configuration. |
6565
| `rust` | [RustDefault](#rustdefault-configuration) (optional) | Rust contains Rust-specific default configuration. |
66+
| `python` | [PythonDefault](#pythondefault-configuration) (optional) | Python contains Python-specific default configuration. |
6667

6768
## Library Configuration
6869

@@ -136,10 +137,17 @@ This document describes the schema for the librarian.yaml.
136137
| `module_path_version` | string | ModulePathVersion is the version of the Go module path. |
137138
| `nested_module` | string | NestedModule is the name of a nested module directory. |
138139

140+
## PythonDefault Configuration
141+
142+
| Field | Type | Description |
143+
| :--- | :--- | :--- |
144+
| `common_gapic_paths` | list of string | CommonGAPICPaths contains paths which are generated for any package containing a GAPIC API. These are relative to the package's output directory, and the string "{neutral-source}" is replaced with the path to the version-neutral source code (e.g. "google/cloud/run"). If a library defines its own common_gapic_paths, they will be appended to the defaults. |
145+
139146
## PythonPackage Configuration
140147

141148
| Field | Type | Description |
142149
| :--- | :--- | :--- |
150+
| (embedded) | [PythonDefault](#pythondefault-configuration) | |
143151
| `opt_args` | list of string | OptArgs contains additional options passed to the generator, where the options are common to all apis. Example: ["warehouse-package-name=google-cloud-batch"] |
144152
| `opt_args_by_api` | map[string][]string | OptArgsByAPI contains additional options passed to the generator, where the options vary by api. In each entry, the key is the api (API path) and the value is the list of options to pass when generating that API. Example: {"google/cloud/secrets/v1beta": ["python-gapic-name=secretmanager"]} |
145153
| `proto_only_apis` | list of string | ProtoOnlyAPIs contains the list of API paths which are proto-only, so should use regular protoc Python generation instead of GAPIC. |

internal/config/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ type Default struct {
144144

145145
// Rust contains Rust-specific default configuration.
146146
Rust *RustDefault `yaml:"rust,omitempty"`
147+
148+
// Python contains Python-specific default configuration.
149+
Python *PythonDefault `yaml:"python,omitempty"`
147150
}
148151

149152
// Library represents a library configuration.

internal/config/language.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,11 @@ type RustPoller struct {
280280
MethodID string `yaml:"method_id"`
281281
}
282282

283-
// PythonPackage contains Python-specific library configuration.
283+
// PythonPackage contains Python-specific library configuration. It inherits
284+
// from PythonDefault, allowing library-specific overrides of global settings.
284285
type PythonPackage struct {
286+
PythonDefault `yaml:",inline"`
287+
285288
// OptArgs contains additional options passed to the generator, where
286289
// the options are common to all apis.
287290
// Example: ["warehouse-package-name=google-cloud-batch"]
@@ -299,6 +302,17 @@ type PythonPackage struct {
299302
ProtoOnlyAPIs []string `yaml:"proto_only_apis,omitempty"`
300303
}
301304

305+
// PythonDefault contains Python-specific default configuration.
306+
type PythonDefault struct {
307+
// CommonGAPICPaths contains paths which are generated for any package
308+
// containing a GAPIC API. These are relative to the package's output
309+
// directory, and the string "{neutral-source}" is replaced with the path
310+
// to the version-neutral source code (e.g. "google/cloud/run"). If a
311+
// library defines its own common_gapic_paths, they will be appended to
312+
// the defaults.
313+
CommonGAPICPaths []string `yaml:"common_gapic_paths,omitempty"`
314+
}
315+
302316
// DartPackage contains Dart-specific library configuration.
303317
type DartPackage struct {
304318
// APIKeysEnvironmentVariables is a comma-separated list of environment variable names

internal/librarian/generate.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,14 @@ func cleanLibraries(language string, libraries []*config.Library) error {
156156
switch language {
157157
case languageFake:
158158
// No cleaning needed.
159-
case languageDart, languagePython:
159+
case languageDart:
160160
if err := checkAndClean(library.Output, library.Keep); err != nil {
161161
return err
162162
}
163+
case languagePython:
164+
if err := python.CleanLibrary(library); err != nil {
165+
return err
166+
}
163167
case languageGo:
164168
if err := golang.Clean(library); err != nil {
165169
return err

internal/librarian/library.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ func fillDefaults(lib *config.Library, d *config.Default) *config.Library {
4646
if d.Dart != nil {
4747
return fillDart(lib, d)
4848
}
49+
if d.Python != nil {
50+
return fillPython(lib, d)
51+
}
4952
return lib
5053
}
5154

@@ -98,6 +101,16 @@ func fillDart(lib *config.Library, d *config.Default) *config.Library {
98101
return lib
99102
}
100103

104+
// fillPython populates empty Python-specific fields in lib from the provided
105+
// default.
106+
func fillPython(lib *config.Library, d *config.Default) *config.Library {
107+
if lib.Python == nil {
108+
lib.Python = &config.PythonPackage{}
109+
}
110+
lib.Python.CommonGAPICPaths = append(d.Python.CommonGAPICPaths, lib.Python.CommonGAPICPaths...)
111+
return lib
112+
}
113+
101114
// mergeDartDependencies merges library dependencies with default dependencies.
102115
// Duplicate dependencies in defaults will be ignored.
103116
func mergeDartDependencies(libDeps, defaultDeps string) string {

internal/librarian/library_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,78 @@ func TestFillDefaults_Rust(t *testing.T) {
353353
}
354354
}
355355

356+
func TestFillDefaults_Python(t *testing.T) {
357+
for _, test := range []struct {
358+
name string
359+
lib *config.Library
360+
defaults *config.PythonDefault
361+
want *config.Library
362+
}{
363+
{
364+
name: "common_gapic_paths only in defaults",
365+
lib: &config.Library{},
366+
defaults: &config.PythonDefault{
367+
CommonGAPICPaths: []string{"a", "b"},
368+
},
369+
want: &config.Library{
370+
Python: &config.PythonPackage{
371+
PythonDefault: config.PythonDefault{
372+
CommonGAPICPaths: []string{"a", "b"},
373+
},
374+
},
375+
},
376+
},
377+
{
378+
name: "common_gapic_paths only in package",
379+
lib: &config.Library{
380+
Python: &config.PythonPackage{
381+
PythonDefault: config.PythonDefault{
382+
CommonGAPICPaths: []string{"a", "b"},
383+
},
384+
},
385+
},
386+
defaults: &config.PythonDefault{},
387+
want: &config.Library{
388+
Python: &config.PythonPackage{
389+
PythonDefault: config.PythonDefault{
390+
CommonGAPICPaths: []string{"a", "b"},
391+
},
392+
},
393+
},
394+
},
395+
{
396+
name: "common_gapic_paths merged",
397+
lib: &config.Library{
398+
Python: &config.PythonPackage{
399+
PythonDefault: config.PythonDefault{
400+
CommonGAPICPaths: []string{"c", "d"},
401+
},
402+
},
403+
},
404+
defaults: &config.PythonDefault{
405+
CommonGAPICPaths: []string{"a", "b"},
406+
},
407+
want: &config.Library{
408+
Python: &config.PythonPackage{
409+
PythonDefault: config.PythonDefault{
410+
CommonGAPICPaths: []string{"a", "b", "c", "d"},
411+
},
412+
},
413+
},
414+
},
415+
} {
416+
t.Run(test.name, func(t *testing.T) {
417+
defaults := &config.Default{
418+
Python: test.defaults,
419+
}
420+
got := fillDefaults(test.lib, defaults)
421+
if diff := cmp.Diff(test.want, got); diff != "" {
422+
t.Errorf("mismatch (-want +got):\n%s", diff)
423+
}
424+
})
425+
}
426+
}
427+
356428
func TestPrepareLibrary(t *testing.T) {
357429
for _, test := range []struct {
358430
name string

0 commit comments

Comments
 (0)