Reputation: 10281
I'm pip-installing my module like so:
cd my_working_dir
pip install -e .
When I later import the module from within Python, can I somehow detect if the module is installed in this editable mode?
Right now, I'm just checking if there's a .git folder in os.path.dirname(mymodule.__file__))
which, well, only works if there's actually a .git folder there. Is there a more reliable way?
Upvotes: 22
Views: 4789
Reputation: 4692
There is actually a public-facing std-lib API for this in importlib.metadata
.
import json
from importlib.metadata import Distribution
direct_url = Distribution.from_name("pkg-name").read_text("direct_url.json")
pkg_is_editable = json.loads(direct_url).get("dir_info", {}).get("editable", False)
Found out about it in this GH issue. See here for the direct_url.json
specification.
If you have importlib
6.11.0 or later, use Distribution.origin
to get a Namespace
representation of direct_url.json
directly.
Upvotes: 4
Reputation: 69
Run pip list
, and there is a column called "Editable project location". If that column has a value, specifically the directory from which you installed it, then the package is pip installed in editable mode.
Upvotes: 6
Reputation: 18426
Haven't found a definite source for this, but if the output of
$ pip show my-package -f
is something like this:
..
..
Files:
__editable__.my-package-0.0.5.pth
my-package-0.0.5.dist-info/INSTALLER
my-package-0.0.5.dist-info/METADATA
my-package-0.0.5.dist-info/RECORD
my-package-0.0.5.dist-info/REQUESTED
my-package-0.0.5.dist-info/WHEEL
my-package-0.0.5.dist-info/direct_url.json
my-package-0.0.5.dist-info/top_level.txt
then it's probably editable.
Upvotes: 1
Reputation: 117
Recently I had to test if various packages were installed in editable mode across different machines. Running pip show <package name>
reveals not only the version, but other information about it, which includes the location of the source code. If the package was not installed in editable mode, this location will point to site-packages
, so for my case it was sufficient with checking the output of such command:
import subprocess
def check_if_editable(name_of_the_package:str) -> bool:
out = subprocess.check_output(["pip", "show", f"{name_of_the_package}"]).decode()
return "site-packages" in out
Upvotes: 0
Reputation: 3752
Another workaround:
Place an "not to install" file into your package. This can be a README.md
, or a not_to_install.txt
file. Use any non-pythonic extension, to prevent that file installation. Then check if that file exists in your package.
The suggested source structure:
my_repo
|-- setup.py
`-- awesome_package
|-- __init__.py
|-- not_to_install.txt
`-- awesome_module.py
setup.py:
# setup.py
from setuptools import setup, find_packages
setup(
name='awesome_package',
version='1.0.0',
# find_packages() will ignore non-python files.
packages=find_packages(),
)
The __init__.py or the awesome_module.py:
import os
# The current directory
__here__ = os.path.dirname(os.path.realpath(__file__))
# Place the following function into __init__.py or into awesome_module.py
def check_editable_installation():
'''
Returns true if the package was installed with the editable flag.
'''
not_to_install_exists = os.path.isfile(os.path.join(__here__, 'not_to_install.txt'))
return not_to_install_exists
Upvotes: 3
Reputation: 13528
I don't know of a way to detect this directly (e.g. ask setuptools
).
You could try to detect that you package can not be reached through the paths in sys.path
. But that's tedious. It's also not bullet proof -- what if it can be reached through sys.path but it's also installed as en editable package?
The best option is to look at the artifacts an editable install leaves in your site-packages
folder. There's a file called my_package.egg-link
there.
from pathlib import Path
# get site packages folder through some other magic
# assuming this current file is located in the root of your package
current_package_root = str(Path(__file__).parent.parent)
installed_as_editable = False
egg_link_file = Path(site_packages_folder) / "my_package.egg-link"
try:
linked_folder = egg_link_file.read_text()
installed_as_editable = current_package_root in linked_folder
except FileNotFoundError:
installed_as_editable = False
Note: to make this a bit more bullet-proof, read only the first line of the egg-link
file and parse it using Path()
as well to account for proper slashes etc.
Upvotes: 0