Delgan
Delgan

Reputation: 19627

How to package a library whose import produces side effects in Python?

I am working on a python library (not mine) which looks like this:

.
├── README.md
├── setup.py
└── library
    ├── __init__.py
    ├── core.py
    ├── a.py
    └── b.py

The file __init__.py make use of core.py which itself uses a.py and b.py. The important thing to note is that import library has some side effets which are deliberately intended.

However, I would like to give the user the possibility to use functions of core.py without there being any side effects. Unfortunately, as you know, import library.core or from library import core will execute __init__.py (where side effects occur) anyway.

Do you know how could I reorganize my package and the setup.py to solve this problem?


I thought to something like this:

.
├── README.md
├── setup.py
├── library_core
│   ├── __init__.py
│   ├── core.py
│   ├── a.py
│   └── b.py
└── library
    └── __init__.py  # Import library_core and apply side effects

I would update setup.py with packages = ['library', 'library_core']. That way, importing library do not change anything, but user could then import library_core without any side effects. Also, this would avoid duplicating code and everything would stay in the same repository.

Unfortunately, this does not work because I do not have the ability to import library_core from library since they are not in the same place in the file tree.

Upvotes: 1

Views: 1743

Answers (2)

Delgan
Delgan

Reputation: 19627

Using two package seems to be the best way.

The use of two adjacent packages can work only if the whole library is installed (with python setup.py install for example). This complicates development considerably, for unit tests for example: it was then impossible to do import library since library_core could not be found if not installed.

So, the best solution is to simply make a sub-package, and specify within the setup.py where library_core is located thanks to the package_dir option.

The files tree would look like this:

.
├── README.md
├── setup.py
└── library
    ├── __init__.py
    └── core
        ├── __init__.py
        ├── a.py
        └── b.py

And in setup.py:

setup(
    name = 'library',
    packages = ['library', 'library.core', 'library_core'],
    package_dir = {'library_core': 'library/core'},
    ...
)

Upvotes: 0

holdenweb
holdenweb

Reputation: 37033

I'd recommend that you stop relying on side effects and require the user to explicitly trigger them by calling a documented function. Otherwise you are fighting a losing battle: the default is currently to trigger the side effects, and then you have to undo them if the user doesn't want them.

Upvotes: 1

Related Questions