Metadata-Version: 2.1
Name: pusimp
Version: 0.1.1
Summary: Prevent user-site imports
Author-email: Francesco Ballarin <francesco.ballarin@unicatt.it>, Drew Parsons <dparsons@debian.org>
Maintainer-email: Francesco Ballarin <francesco.ballarin@unicatt.it>, Drew Parsons <dparsons@debian.org>
License: Copyright 2023-2024 pusimp authors and contributors
        
        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
        
Project-URL: repository, https://github.com/python-pusimp/pusimp
Project-URL: issues, https://github.com/python-pusimp/pusimp/issues
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: AUTHORS
Provides-Extra: lint
Requires-Dist: isort ; extra == 'lint'
Requires-Dist: mypy ; extra == 'lint'
Requires-Dist: ruff ; extra == 'lint'
Requires-Dist: yamllint ; extra == 'lint'
Provides-Extra: tests
Requires-Dist: coverage[toml] ; extra == 'tests'
Requires-Dist: pip ; extra == 'tests'
Requires-Dist: pytest ; extra == 'tests'
Requires-Dist: virtualenv ; extra == 'tests'

# pusimp - prevent user-site imports

**pusimp** is a python library to prevent user-site imports of specific dependencies of a package. The typical scenario for using **pusimp** is in combination with a system manager (e.g., `apt` for Debian), to prevent dependencies from being loaded from user-site instead of the location provided by the system manager.

**pusimp** is currently developed and maintained at [Università Cattolica del Sacro Cuore](https://www.unicatt.it/) by [Prof. Francesco Ballarin](https://www.francescoballarin.it), in collaboration with [Prof. Drew Parsons](https://web.unica.it/unica/page/en/drewf_parsons) at [Università degli Studi di Cagliari](https://www.unica.it/).

## The acronym
**pusimp** is an acronym for "**p**revent **u**ser-**s**ite **imp**orts". However, an internet search reveals that PUSIMP is also a slang term that stands for "Put yourself in my position". In agreement with the slang meaning, **pusimp** reports an informative (although, arguably, quite long) error message to guide the user towards solving the conflict in their dependencies.

## Content

The logic of **pusimp** is implemented in [a single python file](https://github.com/python-pusimp/pusimp/blob/main/pusimp/prevent_user_site_imports.py), which exposes the function `pusimp.prevent_user_site_imports`. **pusimp** can be `pip install`ed from [its GitHub repository](https://github.com/python-pusimp/pusimp/) or from [PyPI](https://pypi.org/project/pusimp/).

## Sample usage

Assume to be the maintainer of a package named `my_package`, with website `https://www.my.package`.
`my_package` depends on the auxiliary packages `my_dependency_one`, `my_dependency_two`, `my_dependency_three`, and optionally on `my_dependency_four`.
Furthermore, assume that all five packages are installed by the system manager `my_apt` at the path `/usr/lib/python3.xy/site-packages`, and that the four dependencies are available on `pypi` as `my-dependency-one`, `my-dependency-two`, `my-dependency-three`, and `my-dependency-four`. The corresponding sample usage in this case is:
```
import pusimp
pusimp.prevent_user_site_imports(
    "my_package", "my_apt", "https://www.my.package",
    "/usr/lib/python3.xy/site-packages",
    ["my_dependency_one", "my_dependency_two", "my_dependency_three", "my_dependency_four"],
    ["my-dependency-one", "my-dependency-two", "my-dependency-three", "my-dependency-four"],
    [False, False, False, True],
    [
        "Additional message for my_dependency_one.",
        "",
        "",
        "Maybe inform the user that my_dependency_four is optional."
    ],
    lambda executable, dependency_pypi_name, dependency_actual_path: f"{executable} -m pip uninstall {dependency_pypi_name}"
)
```
Suppose now to have a broken configuration in which `my_dependency_one` is missing, `my_dependency_two` is broken, while `my_dependency_three` and `my_dependency_four` are installed on the user-site location.
A sample error in such case is the following (the terminal will automatically handle line wrapping of long lines):
```
pusimp has detected the following problems with my_package dependencies:
1) Missing dependencies:
* my_dependency_one is missing. Its expected path was /usr/lib/python3.xy/site-packages/my_dependency_one/__init__.py.
2) Broken dependencies:
* my_dependency_two is broken. Error on import was 'purposely broken'.
3) Dependencies imported from a local path rather than from the path provided by my_apt:
* my_dependency_three was imported from a local path: expected in /usr/lib/python3.xy/site-packages/my_dependency_three/__init__.py, but imported from ~/.local/lib/python3.xy/site-packages/my_dependency_three/__init__.py.
* my_dependency_four was imported from a local path: expected in /usr/lib/python3.xy/site-packages/my_dependency_four/__init__.py, but imported from ~/.local/lib/python3.xy/site-packages/my_dependency_four/__init__.py.

pusimp suggests to apply all of the following fixes:
1) To install missing dependencies:
* check how to install my_dependency_one with my_apt.
2) To fix broken dependencies:
* run 'python3 -m pip show my-dependency-two' in a terminal: if the location field is not /usr/lib/python3.xy/site-packages consider running 'python3 -m pip uninstall my-dependency-two' in a terminal, because the broken dependency is probably being imported from a local path rather than from the path provided by my_apt.
3) To uninstall local dependencies:
* run 'python3 -m pip uninstall my-dependency-three' in a terminal, and verify that you are prompted to confirm removal of files in ~/.local/lib/python3.xy/site-packages/my_dependency_three.
* run 'python3 -m pip uninstall my-dependency-four' in a terminal, and verify that you are prompted to confirm removal of files in ~/.local/lib/python3.xy/site-packages/my_dependency_four. Maybe inform the user that my_dependency_four is optional.

You can disable this check by exporting the MY_PACKAGE_ALLOW_USER_SITE_IMPORTS environment variable. Note, however, that this may break the installation provided by my_apt.
If you believe that this message appears incorrectly, report this at https://www.my.package .
```
