Skip to content

AndresBena19/py-imports

Repository files navigation

Py-Imports

Be aware about imports meta information

Test Coverage Package version Supported Python versions pre-commit.ci status


Source Code: https://github.com/andresbena19/py-imports

Requirements

Python 3.7+

py-imports stands on the shoulders of giants:

Installation

$ pip install py-imports

---> 100%

All it's ready to begin 

Example

Introspect it

  • Create a file main.py with:
import logging
from py_imports.manager import PyImports
from .parse_local_dir import file_imports_from_dir_one

myself = "main.py"

# Let's introspect myself
with PyImports() as manager:
    imports_file = manager.get_imports(myself)

# Now you have access to the imports used in each file 
imports_file
{
 'main.py': <py_imports.base.models.ImportsCollectionFile object at 0x10b889220>
}

# Get details about the absolute, relative and standard imports in the file
collector_object = imports_file.get(myself)
absolute_imports = collector_object.absolute_imports
relative_imports = collector_object.relative_imports
standard_imports = collector_object.imports
Get meta information about absolute imports...absolute_imports
  # Absolute imports
  #  --- from py_imports.manager import PyImports ---
  # If we introspect the object, we will get the following
 
  example_abs_import = absolute_imports[0]
  example_abs_import.children -> ['PyImports']
  example_abs_import.parent -> 'py_imports.manager'
  example_abs_import.statement -> 'from py_imports.manager import PyImports'
  example_abs_import.level -> 0
  example_abs_import.line -> 2
Get meta information about relative imports...relative_imports
  # relative imports
  #  --- from .parse_local_dir import file_imports_from_dir_one ---
  # If we introspect the object, we will get the following
 
  example_relative_import = relative_imports[0]
  example_abs_import.children -> ['file_imports_from_dir_one']
  example_abs_import.children_unused -> ['file_imports_from_dir_one']
  example_abs_import.parent -> 'parse_local_dir'
  example_abs_import.statement -> 'from .parse_local_dir import file_imports_from_dir_one'
  example_abs_import.level -> 1
  example_abs_import.line -> 3
Get meta information about standard imports ...standard_imports
     # standard imports
     #  --- import logging ---
     # If we introspect the object, we will get the following
     
     example_standard_import = standard_imports[0]
     example_standard_import.children -> ['logging']
     example_standard_import.children_unused -> ['logging']
     example_standard_import.statement -> 'import logging'
     example_standard_import.line -> 1

Now you know more about you...

Features

Classify the imports found into three groups

The util allow identifying and group the imports according ...relative imports, absolu...
  • Python Abstract Grammar

    The util allow identifying and group the imports according to the abstract grammar defined with python

     ...
     | Import(alias* names)
     | ImportFrom(identifier? module, alias* names, int? level)
    
  • Import types

    • Relative Imports

      Relative imports use leading dots. A single leading dot indicates a relative import, starting with the current package. Two or more leading dots indicate a relative import to the parent(s) of the current package, one level per dot after the first.

      • Schema syntax

        Relative imports must always use from <> import;import <> is always absolute.
      • Ex.

        from .moduleY import spam
        from .moduleY import spam as ham
        from . import moduleY
        from ..subpackage1 import moduleY
        from ..subpackage2.moduleZ import eggs
        from ..moduleA import foo
        from ...package import bar
        from ...sys import path
    • Absolute Imports

      Absolute import involves full path i.e., from the project’s root folder to the desired module. An absolute import state that the resource
      to be imported using its full path from the project’s root folder.

      • Schema syntax

        Absolute imports may use either the import <> or from <> import <> syntax, but relative imports may only use the second form.
      • Ex.

        from moduleY import spam
        from moduleY import spam as ham
        
        # OR
        
        import XXX.YYY.ZZZ
    • Standard Imports

      Standard imports will be introspected and the data about it will be saved in an object named ImportStatement.

If the imports are being used

If some child it's not used in an import ...children_unused...
  • Unused imports

    If some child it's not used in an import, this will be added in children_unused attribute in every concrete implementation that represent an imports.

    from ..subpackage1 import moduleY, moduleZ
    
    def foo() -> moduleZ:
        pass

    In this case the relative import from ..subpackage1 import moduleY, moduleZ has a child that is not used in the file.

    ...  # After introspect the file
    
    relative_imports = imports_file.relative_imports
    relative_imports[0].children_unused -> ["moduleY"]
    
    # But the total of children present in this file 
    relative_imports[0].children -> ["moduleY", "moduleZ"]

    it's used pyflakes to determine the unused imports, because follow the same philosophy to get the information just using a static analysis.

If the imports are located inside an inner scope ex. function, class, etc.

If the position of the import statement ...in_inner_scope...
  • Imports in inner scopes

    If some imports are located inside an inner scope, the import object will contain a boolean field named in_inner_scope indicating that is located outside his default position (the top of the file or in the global scope), also will be included an attribute named outer_parent_node that will contain the AST node, to allow the user get more information about the data structure node parent that is around the import.

    def foo():
       from pkg import moduleY, moduleZ
    ...

    In this case the absolute import is located inside a function named foo.

    ...  # After introspect the file
    
    absolute_imports = imports_file.absolute_imports
    absolute_imports[0].in_inner_scope -> True
    
    # it's possible to get the ast node parent with
    absolute_imports[0].outer_parent_node -> ast.AST object

Notes

This library does not execute any part of the python target code, this just make a static analysis over the code to describe the meta information about the imports in the file.

License

This project is licensed under the terms of the MIT license.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages