diff --git a/src/codegen/sdk/python/import_resolution.py b/src/codegen/sdk/python/import_resolution.py index 16f7f876b..f8066c583 100644 --- a/src/codegen/sdk/python/import_resolution.py +++ b/src/codegen/sdk/python/import_resolution.py @@ -85,73 +85,87 @@ def imported_exports(self) -> list[Exportable]: @noapidoc @reader def resolve_import(self, base_path: str | None = None, *, add_module_name: str | None = None) -> ImportResolution[PyFile] | None: - base_path = base_path or self.ctx.projects[0].base_path or "" - module_source = self.module.source if self.module else "" - symbol_name = self.symbol_name.source if self.symbol_name else "" - if add_module_name: - module_source += f".{symbol_name}" - symbol_name = add_module_name - # If import is relative, convert to absolute path - if module_source.startswith("."): - module_source = self._relative_to_absolute_import(module_source) - - # =====[ Check if we are importing an entire file ]===== - if self.is_module_import(): - # covers `import a.b.c` case and `from a.b.c import *` case - filepath = os.path.join(base_path, module_source.replace(".", "/") + ".py") - else: - # This is the case where you do: - # `from a.b.c import foo` - filepath = os.path.join( - base_path, - module_source.replace(".", "/") + "/" + symbol_name + ".py", - ) - - # =====[ Check if we are importing an entire file with custom resolve path or sys.path enabled ]===== - if len(self.ctx.config.import_resolution_paths) > 0 or self.ctx.config.py_resolve_syspath: - # Handle resolve overrides first if both is set - resolve_paths: list[str] = self.ctx.config.import_resolution_paths + (sys.path if self.ctx.config.py_resolve_syspath else []) - if file := self._file_by_custom_resolve_paths(resolve_paths, filepath): + try: + base_path = base_path or self.ctx.projects[0].base_path or "" + module_source = self.module.source if self.module else "" + symbol_name = self.symbol_name.source if self.symbol_name else "" + if add_module_name: + module_source += f".{symbol_name}" + symbol_name = add_module_name + # If import is relative, convert to absolute path + if module_source.startswith("."): + module_source = self._relative_to_absolute_import(module_source) + + # =====[ Check if we are importing an entire file ]===== + if self.is_module_import(): + # covers `import a.b.c` case and `from a.b.c import *` case + filepath = os.path.join(base_path, module_source.replace(".", "/") + ".py") + else: + # This is the case where you do: + # `from a.b.c import foo` + filepath = os.path.join( + base_path, + module_source.replace(".", "/") + "/" + symbol_name + ".py", + ) + + # =====[ Check if we are importing an entire file with custom resolve path or sys.path enabled ]===== + if len(self.ctx.config.import_resolution_paths) > 0 or self.ctx.config.py_resolve_syspath: + # Handle resolve overrides first if both is set + resolve_paths: list[str] = self.ctx.config.import_resolution_paths + (sys.path if self.ctx.config.py_resolve_syspath else []) + if file := self._file_by_custom_resolve_paths(resolve_paths, filepath): + return ImportResolution(from_file=file, symbol=None, imports_file=True) + + # =====[ Default path ]===== + if file := self.ctx.get_file(filepath): + return ImportResolution(from_file=file, symbol=None, imports_file=True) + + filepath = filepath.replace(".py", "/__init__.py") + if file := self.ctx.get_file(filepath): + # TODO - I think this is another edge case, due to `dao/__init__.py` etc. + # You can't do `from a.b.c import foo` => `foo.utils.x` right now since `foo` is just a file... return ImportResolution(from_file=file, symbol=None, imports_file=True) - # =====[ Default path ]===== - if file := self.ctx.get_file(filepath): - return ImportResolution(from_file=file, symbol=None, imports_file=True) - - filepath = filepath.replace(".py", "/__init__.py") - if file := self.ctx.get_file(filepath): - # TODO - I think this is another edge case, due to `dao/__init__.py` etc. - # You can't do `from a.b.c import foo` => `foo.utils.x` right now since `foo` is just a file... - return ImportResolution(from_file=file, symbol=None, imports_file=True) - - # =====[ Check if `module.py` file exists in the graph with custom resolve path or sys.path enabled ]===== - filepath = module_source.replace(".", "/") + ".py" - if len(self.ctx.config.import_resolution_paths) > 0 or self.ctx.config.py_resolve_syspath: - # Handle resolve overrides first if both is set - resolve_paths: list[str] = self.ctx.config.import_resolution_paths + (sys.path if self.ctx.config.py_resolve_syspath else []) - if file := self._file_by_custom_resolve_paths(resolve_paths, filepath): + # =====[ Check if `module.py` file exists in the graph with custom resolve path or sys.path enabled ]===== + filepath = module_source.replace(".", "/") + ".py" + if len(self.ctx.config.import_resolution_paths) > 0 or self.ctx.config.py_resolve_syspath: + # Handle resolve overrides first if both is set + resolve_paths: list[str] = self.ctx.config.import_resolution_paths + (sys.path if self.ctx.config.py_resolve_syspath else []) + if file := self._file_by_custom_resolve_paths(resolve_paths, filepath): + symbol = file.get_node_by_name(symbol_name) + return ImportResolution(from_file=file, symbol=symbol) + + # =====[ Check if `module.py` file exists in the graph ]===== + filepath = os.path.join(base_path, filepath) + if file := self.ctx.get_file(filepath): symbol = file.get_node_by_name(symbol_name) - return ImportResolution(from_file=file, symbol=symbol) - - # =====[ Check if `module.py` file exists in the graph ]===== - filepath = os.path.join(base_path, filepath) - if file := self.ctx.get_file(filepath): - symbol = file.get_node_by_name(symbol_name) - if symbol is None: - if file.get_node_from_wildcard_chain(symbol_name): - return ImportResolution(from_file=file, symbol=None, imports_file=True) + if symbol is None: + if file.get_node_from_wildcard_chain(symbol_name): + return ImportResolution(from_file=file, symbol=None, imports_file=True) + else: + # This is most likely a broken import + return ImportResolution(from_file=file, symbol=None) else: - # This is most likely a broken import - return ImportResolution(from_file=file, symbol=None) - else: - return ImportResolution(from_file=file, symbol=symbol) - - # =====[ Check if `module/__init__.py` file exists in the graph with custom resolve path or sys.path enabled ]===== - filepath = filepath.replace(".py", "/__init__.py") - if len(self.ctx.config.import_resolution_paths) > 0 or self.ctx.config.py_resolve_syspath: - # Handle resolve overrides first if both is set - resolve_paths: list[str] = self.ctx.config.import_resolution_paths + (sys.path if self.ctx.config.py_resolve_syspath else []) - if from_file := self._file_by_custom_resolve_paths(resolve_paths, filepath): + return ImportResolution(from_file=file, symbol=symbol) + + # =====[ Check if `module/__init__.py` file exists in the graph with custom resolve path or sys.path enabled ]===== + filepath = filepath.replace(".py", "/__init__.py") + if len(self.ctx.config.import_resolution_paths) > 0 or self.ctx.config.py_resolve_syspath: + # Handle resolve overrides first if both is set + resolve_paths: list[str] = self.ctx.config.import_resolution_paths + (sys.path if self.ctx.config.py_resolve_syspath else []) + if from_file := self._file_by_custom_resolve_paths(resolve_paths, filepath): + symbol = from_file.get_node_by_name(symbol_name) + if symbol is None: + if from_file.get_node_from_wildcard_chain(symbol_name): + return ImportResolution(from_file=from_file, symbol=None, imports_file=True) + else: + # This is most likely a broken import + return ImportResolution(from_file=from_file, symbol=None) + + else: + return ImportResolution(from_file=from_file, symbol=symbol) + + # =====[ Check if `module/__init__.py` file exists in the graph ]===== + if from_file := self.ctx.get_file(filepath): symbol = from_file.get_node_by_name(symbol_name) if symbol is None: if from_file.get_node_from_wildcard_chain(symbol_name): @@ -163,40 +177,30 @@ def resolve_import(self, base_path: str | None = None, *, add_module_name: str | else: return ImportResolution(from_file=from_file, symbol=symbol) - # =====[ Check if `module/__init__.py` file exists in the graph ]===== - if from_file := self.ctx.get_file(filepath): - symbol = from_file.get_node_by_name(symbol_name) - if symbol is None: - if from_file.get_node_from_wildcard_chain(symbol_name): - return ImportResolution(from_file=from_file, symbol=None, imports_file=True) - else: - # This is most likely a broken import - return ImportResolution(from_file=from_file, symbol=None) - - else: - return ImportResolution(from_file=from_file, symbol=symbol) - - # =====[ Case: Can't resolve the import ]===== - if base_path == "": - # Try to resolve with "src" as the base path - return self.resolve_import(base_path="src", add_module_name=add_module_name) - if base_path == "src": - # Try "test" next - return self.resolve_import(base_path="test", add_module_name=add_module_name) + # =====[ Case: Can't resolve the import ]===== + if base_path == "": + # Try to resolve with "src" as the base path + return self.resolve_import(base_path="src", add_module_name=add_module_name) + if base_path == "src": + # Try "test" next + return self.resolve_import(base_path="test", add_module_name=add_module_name) - # if not G_override: - # for resolver in ctx.import_resolvers: - # if imp := resolver.resolve(self): - # return imp + # if not G_override: + # for resolver in ctx.import_resolvers: + # if imp := resolver.resolve(self): + # return imp - return None - # # =====[ Check if we are importing an external module in the graph ]===== - # if ext := self.ctx.get_external_module(self.source, self._unique_node.source): - # return ImportResolution(symbol=ext) - # # Implies we are not importing the symbol from the current repo. - # # In these cases, consider the import as an ExternalModule and add to graph - # ext = ExternalModule.from_import(self) - # return ImportResolution(symbol=ext) + return None + # # =====[ Check if we are importing an external module in the graph ]===== + # if ext := self.ctx.get_external_module(self.source, self._unique_node.source): + # return ImportResolution(symbol=ext) + # # Implies we are not importing the symbol from the current repo. + # # In these cases, consider the import as an ExternalModule and add to graph + # ext = ExternalModule.from_import(self) + # return ImportResolution(symbol=ext) + except AssertionError: + # Codebase is probably trying to import file from outside repo + return None @noapidoc @reader diff --git a/src/codegen/sdk/typescript/import_resolution.py b/src/codegen/sdk/typescript/import_resolution.py index 090c63b24..387ff2b14 100644 --- a/src/codegen/sdk/typescript/import_resolution.py +++ b/src/codegen/sdk/typescript/import_resolution.py @@ -215,63 +215,67 @@ def resolve_import(self, base_path: str | None = None, *, add_module_name: str | - symbol: The specific symbol being imported (None for module imports) - imports_file: True if importing the entire file/module """ - self.file: TSFile # Type cast ts_file - base_path = base_path or self.ctx.projects[0].base_path or "" - - # Get the import source path - import_source = self.module.source.strip('"').strip("'") if self.module else "" - - # Try to resolve the import using the tsconfig paths - if self.file.ts_config: - import_source = self.file.ts_config.translate_import_path(import_source) - - # Check if need to resolve relative import path to absolute path - relative_import = False - if import_source.startswith("."): - relative_import = True - - # Insert base path - # This has the happen before the relative path resolution - if not import_source.startswith(base_path): - import_source = os.path.join(base_path, import_source) - - # If the import is relative, convert it to an absolute path - if relative_import: - import_source = self._relative_to_absolute_import(import_source) - else: - import_source = os.path.normpath(import_source) - - # covers the case where the import is from a directory ex: "import { postExtract } from './post'" - import_name = import_source.split("/")[-1] - if "." not in import_name: - possible_paths = ["index.ts", "index.js", "index.tsx", "index.jsx"] - for p_path in possible_paths: - if self.ctx.to_absolute(os.path.join(import_source, p_path)).exists(): - import_source = os.path.join(import_source, p_path) - break - - # Loop through all extensions and try to find the file - extensions = ["", ".ts", ".d.ts", ".tsx", ".d.tsx", ".js", ".jsx"] - # Try both filename with and without extension - for import_source_base in (import_source, os.path.splitext(import_source)[0]): - for extension in extensions: - import_source_ext = import_source_base + extension - if file := self.ctx.get_file(import_source_ext): - if self.is_module_import(): - return ImportResolution(from_file=file, symbol=None, imports_file=True) - else: - # If the import is a named import, resolve to the named export in the file - if self.symbol_name is None: - return ImportResolution(from_file=file, symbol=None, imports_file=True) - export_symbol = file.get_export(export_name=self.symbol_name.source) - if export_symbol is None: - # If the named export is not found, it is importing a module re-export. - # In this case, resolve to the file itself and dynamically resolve the symbol later. + try: + self.file: TSFile # Type cast ts_file + base_path = base_path or self.ctx.projects[0].base_path or "" + + # Get the import source path + import_source = self.module.source.strip('"').strip("'") if self.module else "" + + # Try to resolve the import using the tsconfig paths + if self.file.ts_config: + import_source = self.file.ts_config.translate_import_path(import_source) + + # Check if need to resolve relative import path to absolute path + relative_import = False + if import_source.startswith("."): + relative_import = True + + # Insert base path + # This has the happen before the relative path resolution + if not import_source.startswith(base_path): + import_source = os.path.join(base_path, import_source) + + # If the import is relative, convert it to an absolute path + if relative_import: + import_source = self._relative_to_absolute_import(import_source) + else: + import_source = os.path.normpath(import_source) + + # covers the case where the import is from a directory ex: "import { postExtract } from './post'" + import_name = import_source.split("/")[-1] + if "." not in import_name: + possible_paths = ["index.ts", "index.js", "index.tsx", "index.jsx"] + for p_path in possible_paths: + if self.ctx.to_absolute(os.path.join(import_source, p_path)).exists(): + import_source = os.path.join(import_source, p_path) + break + + # Loop through all extensions and try to find the file + extensions = ["", ".ts", ".d.ts", ".tsx", ".d.tsx", ".js", ".jsx"] + # Try both filename with and without extension + for import_source_base in (import_source, os.path.splitext(import_source)[0]): + for extension in extensions: + import_source_ext = import_source_base + extension + if file := self.ctx.get_file(import_source_ext): + if self.is_module_import(): return ImportResolution(from_file=file, symbol=None, imports_file=True) - return ImportResolution(from_file=file, symbol=export_symbol) - - # If the imported file is not found, treat it as an external module - return None + else: + # If the import is a named import, resolve to the named export in the file + if self.symbol_name is None: + return ImportResolution(from_file=file, symbol=None, imports_file=True) + export_symbol = file.get_export(export_name=self.symbol_name.source) + if export_symbol is None: + # If the named export is not found, it is importing a module re-export. + # In this case, resolve to the file itself and dynamically resolve the symbol later. + return ImportResolution(from_file=file, symbol=None, imports_file=True) + return ImportResolution(from_file=file, symbol=export_symbol) + + # If the imported file is not found, treat it as an external module + return None + except AssertionError: + # Codebase is probably trying to import file from outside repo + return None @noapidoc @reader