Skip to content

Commit

Permalink
add option in python for configuring conditional imports
Browse files Browse the repository at this point in the history
  • Loading branch information
gabotechs committed Dec 24, 2023
1 parent 93c9989 commit 9306cbb
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 43 deletions.
13 changes: 7 additions & 6 deletions cmd/.root_test/.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ Available Commands:
render (default command) Render the dependency tree starting from the provided entrypoint

Flags:
-c, --config string path to dep-tree's config file (default .dep-tree.yml)
--exclude stringArray Files that match this glob pattern will be ignored. You can provide an arbitrary number of --exclude flags
--follow-re-exports whether to follow re-exports or not while resolving imports between files (default true)
-h, --help help for dep-tree
--js-follow-ts-config-paths whether to follow the tsconfig.json paths while resolving imports or not (default false)
-v, --version version for dep-tree
-c, --config string path to dep-tree's config file (default .dep-tree.yml)
--exclude stringArray Files that match this glob pattern will be ignored. You can provide an arbitrary number of --exclude flags
--follow-re-exports whether to follow re-exports or not while resolving imports between files (default true)
-h, --help help for dep-tree
--js-follow-ts-config-paths whether to follow the tsconfig.json paths while resolving imports or not (default false)
--python-exclude-conditional-imports exclude conditional imports while calculating file dependencies, like imports wrapped inside if statements (default false)
-v, --version version for dep-tree

Use "dep-tree [command] --help" for more information about a command.
13 changes: 7 additions & 6 deletions cmd/.root_test/help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ Available Commands:
render (default command) Render the dependency tree starting from the provided entrypoint

Flags:
-c, --config string path to dep-tree's config file (default .dep-tree.yml)
--exclude stringArray Files that match this glob pattern will be ignored. You can provide an arbitrary number of --exclude flags
--follow-re-exports whether to follow re-exports or not while resolving imports between files (default true)
-h, --help help for dep-tree
--js-follow-ts-config-paths whether to follow the tsconfig.json paths while resolving imports or not (default false)
-v, --version version for dep-tree
-c, --config string path to dep-tree's config file (default .dep-tree.yml)
--exclude stringArray Files that match this glob pattern will be ignored. You can provide an arbitrary number of --exclude flags
--follow-re-exports whether to follow re-exports or not while resolving imports between files (default true)
-h, --help help for dep-tree
--js-follow-ts-config-paths whether to follow the tsconfig.json paths while resolving imports or not (default false)
--python-exclude-conditional-imports exclude conditional imports while calculating file dependencies, like imports wrapped inside if statements (default false)
-v, --version version for dep-tree

Use "dep-tree [command] --help" for more information about a command.
5 changes: 5 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (

var configPath string
var jsFollowTsConfigPaths bool
var pythonExcludeConditionalImports bool
var followReExports bool
var exclude []string

Expand Down Expand Up @@ -53,6 +54,7 @@ func NewRoot(args []string) *cobra.Command {
root.PersistentFlags().StringVarP(&configPath, "config", "c", "", "path to dep-tree's config file (default .dep-tree.yml)")
root.PersistentFlags().BoolVar(&followReExports, "follow-re-exports", true, "whether to follow re-exports or not while resolving imports between files")
root.PersistentFlags().BoolVar(&jsFollowTsConfigPaths, "js-follow-ts-config-paths", false, "whether to follow the tsconfig.json paths while resolving imports or not (default false)")
root.PersistentFlags().BoolVar(&pythonExcludeConditionalImports, "python-exclude-conditional-imports", false, "exclude conditional imports while calculating file dependencies, like imports wrapped inside if statements (default false)")
root.PersistentFlags().StringArrayVar(&exclude, "exclude", nil, "Files that match this glob pattern will be ignored. You can provide an arbitrary number of --exclude flags")

switch {
Expand Down Expand Up @@ -90,6 +92,9 @@ func loadConfig() (*config.Config, error) {
if root.PersistentFlags().Changed("js-follow-ts-config-paths") {
cfg.Js.FollowTsConfigPaths = jsFollowTsConfigPaths
}
if root.PersistentFlags().Changed("python-exclude-conditional-imports") {
cfg.Python.ExcludeConditionalImports = pythonExcludeConditionalImports
}
cfg.Exclude = append(cfg.Exclude, exclude...)
for _, exclusion := range cfg.Exclude {
if _, err := utils.GlobstarMatch(exclusion, ""); err != nil {
Expand Down
11 changes: 10 additions & 1 deletion internal/config/sample-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,16 @@ js:

# Python specific settings.
python:
# None available at the moment.
# Whether to take into account conditional imports as dependencies between files or not.
# A conditional import is an `import` statement that is wrapped inside an `if` block or
# a function, for example:
#
# if SHOULD_IMPORT:
# from foo import *
#
# by default these statements introduce a dependency between importing and imported file,
# but depending on your use case you might want to disable it.
excludeConditionalImports: false

# Rust specific settings.
rust:
Expand Down
4 changes: 3 additions & 1 deletion internal/python/config.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
package python

type Config struct{}
type Config struct {
ExcludeConditionalImports bool `yaml:"excludeConditionalImports"`
}
10 changes: 8 additions & 2 deletions internal/python/imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ func (l *Language) ParseImports(file *python_grammar.File) (*language.ImportsRes
switch {
case stmt == nil:
// Is this even possible?
case stmt.Import != nil && !stmt.Import.Indented:
case stmt.Import != nil:
if l.cfg.ExcludeConditionalImports && stmt.Import.Indented {
continue
}
resolved := l.ResolveAbsolute(stmt.Import.Path[0:])
switch {
case resolved == nil:
Expand All @@ -41,7 +44,10 @@ func (l *Language) ParseImports(file *python_grammar.File) (*language.ImportsRes
})
}
}
case stmt.FromImport != nil && !stmt.FromImport.Indented:
case stmt.FromImport != nil:
if l.cfg.ExcludeConditionalImports && stmt.FromImport.Indented {
continue
}
importedNames := make([]string, len(stmt.FromImport.Names))
for i, name := range stmt.FromImport.Names {
importedNames[i] = name.Name
Expand Down
75 changes: 49 additions & 26 deletions internal/python/imports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,37 +18,58 @@ func TestLanguage_ParseImports(t *testing.T) {
importsTestFolder, _ := filepath.Abs(importsTestFolder)

tests := []struct {
Name string
File string
Entrypoint string
Expected []language.ImportEntry
ExpectedErrors []string
Name string
File string
Entrypoint string
Expected []language.ImportEntry
ExpectedErrors []string
ExcludeConditionalImports bool
}{
{
Name: "main.py",
File: "main.py",
Entrypoint: "main.py",
Expected: []language.ImportEntry{
// {
// All: true,
// Path: path.Join(importsTestFolder, "src", "foo.py"),
// },
// {
// All: true,
// Path: path.Join(importsTestFolder, "src", "main.py"),
// },
// {
// All: true,
// Path: path.Join(importsTestFolder, "src", "main.py"),
// },
// {
// All: true,
// Path: path.Join(importsTestFolder, "src", "module", "__init__.py"),
// },
// {
// Names: []string{"main"},
// Path: path.Join(importsTestFolder, "src", "main.py"),
// },
{
All: true,
Path: path.Join(importsTestFolder, "src", "main.py"),
},
{
Names: []string{"main"},
Path: path.Join(importsTestFolder, "src", "main.py"),
},
{
All: true,
Path: path.Join(importsTestFolder, "src", "main.py"),
},
{
Names: []string{"main"},
Path: path.Join(importsTestFolder, "src", "main.py"),
},
{
All: true,
Path: path.Join(importsTestFolder, "src", "module", "__init__.py"),
},
{
All: true,
Path: path.Join(importsTestFolder, "src", "module", "module.py"),
},
{
Names: []string{"bar"},
Path: path.Join(importsTestFolder, "src", "module", "__init__.py"),
},
},
ExpectedErrors: []string{
"cannot import file src.py from directory",
"cannot import file un_existing.py from directory",
},
},
{
Name: "main.py",
File: "main.py",
Entrypoint: "main.py",
ExcludeConditionalImports: true,
Expected: []language.ImportEntry{
{
All: true,
Path: path.Join(importsTestFolder, "src", "main.py"),
Expand Down Expand Up @@ -80,7 +101,9 @@ func TestLanguage_ParseImports(t *testing.T) {
for _, tt := range tests {
t.Run(tt.Name, func(t *testing.T) {
a := require.New(t)
_, lang, err := MakePythonLanguage(context.Background(), path.Join(importsTestFolder, tt.Entrypoint), nil)
_, lang, err := MakePythonLanguage(context.Background(), path.Join(importsTestFolder, tt.Entrypoint), &Config{
ExcludeConditionalImports: tt.ExcludeConditionalImports,
})
a.NoError(err)

parsed, err := lang.ParseFile(path.Join(importsTestFolder, tt.File))
Expand Down
7 changes: 6 additions & 1 deletion internal/python/language.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ var Extensions = []string{
type Language struct {
IgnoreModuleImports bool
PythonPath []string
cfg *Config
}

var _ language.Language[python_grammar.File] = &Language{}
Expand All @@ -43,9 +44,13 @@ func isRootFilePresent(dir string) bool {
return false
}

func MakePythonLanguage(ctx context.Context, entrypoint string, _ *Config) (context.Context, language.Language[python_grammar.File], error) {
func MakePythonLanguage(ctx context.Context, entrypoint string, cfg *Config) (context.Context, language.Language[python_grammar.File], error) {
lang := Language{
IgnoreModuleImports: true,
cfg: cfg,
}
if lang.cfg == nil {
lang.cfg = &Config{}
}
entrypointAbsPath, err := filepath.Abs(entrypoint)
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions internal/python/python_grammar/import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ func TestImport(t *testing.T) {
Name: "from foo import (a as a_2,\n b)",
ExpectedFromImports: []FromImport{{Names: []ImportedName{{Name: "a", Alias: "a_2"}, {Name: "b"}}, Path: []string{"foo"}}},
},
{
Name: " from foo.bar import Foo",
ExpectedFromImports: []FromImport{{Names: []ImportedName{{Name: "Foo"}}, Indented: true, Path: []string{"foo", "bar"}}},
},
{
Name: "''' import foo '''",
},
Expand Down

0 comments on commit 9306cbb

Please sign in to comment.