Files
2026-01-05 17:38:31 +00:00

73 lines
2.2 KiB
Python

import os.path
import sys
_helpers_root = os.path.dirname(os.path.abspath(__file__))
_working_dir = os.getcwd()
def get_pep660_editable_roots_from_metadata():
try:
# importlib.metadata was added in 3.8
from importlib.metadata import distributions, Distribution
except ImportError:
return []
# We only reach here on Python 3.8+ (or environments providing importlib.metadata).
# Safe to import these urllib submodules (since Python 3.0+) here.
from urllib.parse import urlsplit
from urllib.request import url2pathname
def read_from_direct_url_json(dist):
# type: (Distribution) -> str | None
import json
direct_url_file = dist._path / 'direct_url.json'
if direct_url_file.exists():
with direct_url_file.open() as f:
data = json.load(f)
if data.get('dir_info', {}).get('editable'):
return data.get('url', '')
return None
def file_url_to_path(url):
# type: (str) -> str | None
parts = urlsplit(url)
if parts.scheme != "file":
return None
# For local file URLs, netloc is "" or "localhost"
if parts.netloc not in ("", "localhost"):
# Non-local authorities exist but usually aren't meaningful for local sys.path usage
return None
return url2pathname(parts.path)
editable_roots = []
for dist in distributions():
url = None # type: str | None
try:
# 'origin' was added in Python 3.13
if dist.origin.dir_info.editable:
url = dist.origin.url
except AttributeError:
url = read_from_direct_url_json(dist)
if url:
path = file_url_to_path(url)
if path:
editable_roots.append(path)
return editable_roots
if __name__ == "__main__":
for root in sys.path:
# The current working dir is not automatically included but can be if PYTHONPATH
# contains an empty entry.
if root != _helpers_root and root != os.curdir and root != _working_dir:
print(root)
for editable_root in get_pep660_editable_roots_from_metadata():
print(editable_root)