Title is kinda confusing, but basically, I followed the Python packaging process to set up my Python package development environment. My project structure is layed out the same, except for a .venv in the root directory (not in src), and additional Python files in the src/package_username directory.

I can build my package fine, but when I go to import it into other projects, I have to import it like import package_username.file or from package_username.file import SomethingInFile. For other python packages, I would only need to do import package or from package import Something.

How can I set up by build process to remove the need for the first portion in my import statements so it matches other packages like termcolor? Is there something I need to add in my __init__.py file?

all 5 comments

sorted by: hot top controversial new old
[–] 6 points 7 months ago* (2 children)

it's strange the packaging guide doesn't mention __all__. Check this out https://realpython.com/python-all-attribute/#exposing-names-from-modules-and-packages-with-__all__

Ignore wildcard (star) imports, it's a bad practice most of the times. I wish they emphasized that more instead of appearing to promote it from the table of contents...

  • source
  • hideshow 2 child comments
  • [–] [S] 3 points 7 months ago (1 child)

    I looked at the guide you linked. So in my __init__.py file, I should import each public name I want from my files, then add them to the __all__ list like this? (I want to make sure I understood the guide correctly)

    from file_1 import SomeClass
    from file_2 import AnotherClass
    
    __all__ = [
        "SomeClass",
        "AnotherClass",
    ]
    
  • source
  • parent
  • hideshow 1 child comment
  • [–] 4 points 7 months ago* (last edited 7 months ago)

    right, those names are also useful when importing your package in tests

    you can also create a __version__ string and append it to __all__ to have a mypackage.__version__

    to pull version from pyproject.toml:

    LIB_NAME: str = "mypackage"
    __version__ = importlib.metadata.version(LIB_NAME)
    
    ...
    
    __all__ = [
        "__version__",
        ...
    ]
    
  • source
  • parent
  • [–] 3 points 7 months ago*

    You’re barking up the right tree. Add a relative import call to your top-level __init__.py and they’ll get namespaced in the way you’re wanting.

    E.g. adding from .file import SomethingInFile as Newthing will let you run import package and reference package.Newthing.

    See the docs for the __all__ dunder as well.

  • source
  • [–] 1 point 7 months ago

    Better have a damn good reason to import everything into the package level namespace.

    The reasoning sqlalchemy has is to prepare beforehand to be able to run in multiple threads without needing to import anything. Importing is slow and should be done up front.

    So there is a slight delay when importing sqlalchemy.

    Keep in mind, the sqlalchemy author and maintainers are waaaaaaay smarter than you and I. py315 may level the play field ever so slightly.

    py315 is supposed to introduce soft import. So wait for that and then everyone jump ship like every previous version has rabies.

  • source