How can I create imports that always work?

前端 未结 4 1113
孤独总比滥情好
孤独总比滥情好 2021-01-27 23:08

I am struggling a bit to set up a working structure in one of my projects. The problem is, that I have main package and a subpackage in a structure like this (I left out all unn

相关标签:
4条回答
  • 2021-01-27 23:19

    You should create a structure like this:

    flammi88
    ├── flammi88
    │   ├── __init__.py
    │   ├── code.py
    │   └── mypackage
    │       ├── __init__.py
    │       ├── utils.py
    │       └── work.py
    └── setup.py
    

    then put at least this in the setup.py:

    import setuptools
    from distutils.core import setup
    
    setup(
        name='flammi88',
        packages=['flammi88'],
    )
    

    now, from the directory containing setup.py, run

    pip install -e .
    

    This will make the flammi88 package available in development mode. Now you can say:

    from flammi88.mypackage import utils
    

    everywhere. This is the normal way to develop packages in Python, and it solves all of your relative import problems. That being said, Guido frowns upon standalone scripts in sub-packages. With this structure I would move the tests inside flammi88/tests/... (and run them with e.g. py.test), but some people like to keep the tests next to the code.

    Update:

    an extended setup.py that describes external requirements and creates executables of the sub-packages you want to run can look like:

    import setuptools
    from distutils.core import setup
    
    setup(
        name='flammi88',
        packages=['flammi88'],
        install_requires=[
            'markdown',
        ],
        entry_points={
            'console_scripts': [
                'work = flammi88.mypackage.work:someMethod',
            ]
        }
    )
    

    now, after pip installing your package, you can just type work at the command line.

    0 讨论(0)
  • 2021-01-27 23:26

    Import utils inside the work.py as follows:

    import mypackage.utils
    

    or if you want to use shorter name:

    from mypackage import utils
    

    EDIT: If you need to run work.py outside of the package, then try:

    try:
        from mypackage import utils
    except ImportError:
        import utils
    
    0 讨论(0)
  • 2021-01-27 23:26

    Use:

    from . import utils
    

    as suggested by Peter

    In your code.py you should use:

    from mypackage import work
    
    0 讨论(0)
  • 2021-01-27 23:31

    Unfortunately relative imports and direct running of submodules don't mix.

    Add the parent directory of mypackage to your PYTHONPATH or always cd into the parent directory when you want to run a submodule.

    Then you have two possibilities:

    Use absolute (from mypackage import utils) instead of relative imports (from . import utils) and run them directly as before. The drawback with that solution is that you'll always need to write the fully qualified path, making it more work to rename mypackage later, among other things.

    or

    Run python3 -m mypackage.utils etc. to run your submodules instead of running python3 mypackage/utils.py.

    This may take some time to adapt to, but it's the more correct way (a module in a package isn't the same as a standalone script) and you can continue to use relative imports.

    There are more "magical" solutions involving __package__ and sys.path but they all require extra code at the top of every file with relative imports you want to run directly. I wouldn't recommend these.

    0 讨论(0)
提交回复
热议问题