Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixes #42: no pkg_resources on Python 3.12 #43

Merged
merged 3 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- uses: pre-commit/action@v3.0.0
build:
strategy:
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ build/
constraints-mxdev.txt
example/*-outfile.txt
requirements-mxdev.txt
venv/
.venv/
dist/
13 changes: 4 additions & 9 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
---
repos:
- repo: https://github.com/psf/black.git
rev: 22.3.0
rev: 24.2.0
hooks:
- id: black
language_version: python3
exclude: ^(tests\/hooks-abort-render\/hooks|docs\/HelloCookieCutter1)

- repo: https://github.com/pre-commit/mirrors-mypy
rev: 'v0.960' # Use the sha / tag you want to point at
rev: 'v1.9.0' # Use the sha / tag you want to point at
hooks:
- id: mypy
additional_dependencies: [types-setuptools]
- repo: https://github.com/PyCQA/doc8
rev: 0.8.1
rev: v1.1.1
hooks:
- id: doc8
name: doc8
Expand All @@ -28,13 +28,8 @@ repos:
# - id: flake8
# additional_dependencies:
# - flake8-docstrings
# - repo: https://github.com/PyCQA/bandit
# rev: 1.6.0
# hooks:
# - id: bandit
# args: [--ini, .bandit]
- repo: https://github.com/mgedmin/check-manifest
rev: "0.48"
rev: "0.49"
hooks:
- id: check-manifest
# - repo: https://github.com/Lucas-C/pre-commit-hooks-safety
Expand Down
6 changes: 3 additions & 3 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

## 4.0.2 (unreleased)


- Nothing changed yet.

- Fix #42: deprecated use of `pkg_resoures` to load entry points and parse requirements.
This enables mxdev to work on Python 3.12, where `pkg_resources` is no longer installed by default in virtual_envs.
[jensens]

## 4.0.1 (2024-03-01)

Expand Down
11 changes: 8 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ VENV_CREATE?=true
# target folder for the virtual environment. If `VENV_ENABLED` is `true` and
# `VENV_CREATE` is false it is expected to point to an existing virtual
# environment. If `VENV_ENABLED` is `false` it is ignored.
# Default: venv
VENV_FOLDER?=venv
# Default: .venv
VENV_FOLDER?=.venv

# mxdev to install in virtual environment.
# Default: mxdev
Expand Down Expand Up @@ -222,8 +222,13 @@ endif

# Determine the executable path
ifeq ("$(VENV_ENABLED)", "true")
export PATH:=$(abspath $(VENV_FOLDER))/bin:$(PATH)
export VIRTUAL_ENV=$(abspath $(VENV_FOLDER))
ifeq ("$(OS)", "Windows_NT")
VENV_EXECUTABLE_FOLDER=$(VIRTUAL_ENV)/Scripts
else
VENV_EXECUTABLE_FOLDER=$(VIRTUAL_ENV)/bin
endif
export PATH:=$(VENV_EXECUTABLE_FOLDER):$(PATH)
MXENV_PYTHON=python
else
MXENV_PYTHON=$(PRIMARY_PYTHON)
Expand Down
8 changes: 2 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,16 @@ classifiers = [
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
]
dependencies = []
dependencies = ["packaging"]
dynamic = ["readme"]

[project.optional-dependencies]
mypy = [
"types-setuptools",
"types-pkg-resources",
]
mypy = []
test = [
"pytest",
"pytest-cov",
"pytest-mock",
"httpretty",
"types-setuptools",
]

[project.urls]
Expand Down
8 changes: 4 additions & 4 deletions src/mxdev/config.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from .including import read_with_included
from .logging import logger
from packaging.requirements import Requirement

import os
import pkg_resources
import typing


Expand Down Expand Up @@ -55,11 +55,11 @@ def __init__(
self.overrides = {}
for line in raw_overrides.split("\n"):
try:
parsed = pkg_resources.Requirement.parse(line)
parsed = Requirement(line)
except Exception:
logger.error(f"Can not parse override: {line}")
continue
self.overrides[parsed.key] = line
self.overrides[parsed.name] = line

raw_ignores = settings.get("ignores", "").strip()
self.ignore_keys = []
Expand All @@ -68,7 +68,7 @@ def __init__(
if line:
self.ignore_keys.append(line)

def is_ns_member(name):
def is_ns_member(name) -> bool:
for hook in hooks:
if name.startswith(hook.namespace):
return True
Expand Down
27 changes: 27 additions & 0 deletions src/mxdev/entry_points.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# this is a helper to load entrypoints with importlib, since pkg_resources
# is deprecated. In Python 3.12 an API incompatible change was introduced,
# so this code is that ugly now.
from importlib.metadata import entry_points


try:
# do we have Python 3.12+?
from importlib.metadata import EntryPoints # type: ignore # noqa: F401

HAS_IMPORTLIB_ENTRYPOINTS = True
except ImportError:
HAS_IMPORTLIB_ENTRYPOINTS = False


def load_eps_by_group(group: str) -> list:
if HAS_IMPORTLIB_ENTRYPOINTS:
eps = entry_points(group=group) # type: ignore
else:
eps_base = entry_points()
if group not in eps_base:
return []
eps = eps_base[group] # type: ignore
# XXX: for some reasons entry points are loaded twice. not sure if this
# is a glitch when installing with uv or something related to
# importlib.metadata.entry_points
return list(set(eps)) # type: ignore
13 changes: 11 additions & 2 deletions src/mxdev/hooks.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
from .entry_points import load_eps_by_group
from .state import State
from pkg_resources import iter_entry_points

import typing


try:
# do we have Python 3.12+
from importlib.metadata import EntryPoints # type: ignore # noqa: F401

HAS_IMPORTLIB_ENTRYPOINTS = True
except ImportError:
HAS_IMPORTLIB_ENTRYPOINTS = False


class Hook:
"""Entry point for hooking into mxdev."""

Expand All @@ -18,7 +27,7 @@ def write(self, state: State) -> None:


def load_hooks() -> list:
return [ep.load()() for ep in iter_entry_points("mxdev") if ep.name == "hook"]
return [ep.load()() for ep in load_eps_by_group("mxdev") if ep.name == "hook"]


def read_hooks(state: State, hooks: typing.List[Hook]) -> None:
Expand Down
10 changes: 5 additions & 5 deletions src/mxdev/processing.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from .logging import logger
from .state import State
from .vcs.common import WorkingCopies
from packaging.requirements import Requirement
from pathlib import Path
from urllib import parse
from urllib import request

import pkg_resources
import typing


Expand Down Expand Up @@ -49,15 +49,15 @@ def process_line(
variety="r",
)
try:
parsed = pkg_resources.Requirement.parse(line)
parsed = Requirement(line)
except Exception:
pass
else:
if parsed.key in package_keys:
if parsed.name in package_keys:
line = f"# {line.strip()} -> mxdev disabled (source)\n"
if variety == "c" and parsed.key in override_keys:
if variety == "c" and parsed.name in override_keys:
line = f"# {line.strip()} -> mxdev disabled (override)\n"
if variety == "c" and parsed.key in ignore_keys:
if variety == "c" and parsed.name in ignore_keys:
line = f"# {line.strip()} -> mxdev disabled (ignore)\n"
if variety == "c":
return [], [line]
Expand Down
3 changes: 1 addition & 2 deletions src/mxdev/tests/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,7 @@ def test_WorkingCopies_process(mocker, caplog):
def test_WorkingCopies_checkout(mocker, caplog, tmpdir):
caplog.set_level(logging.INFO)

class SysExit(Exception):
...
class SysExit(Exception): ...

class Exit:
def __call__(self, code):
Expand Down
30 changes: 10 additions & 20 deletions src/mxdev/vcs/common.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from ..entry_points import load_eps_by_group

import abc
import logging
import os
import pkg_resources
import platform
import queue
import re
Expand Down Expand Up @@ -93,20 +94,16 @@ def should_update(self, **kwargs) -> bool:
return update

@abc.abstractmethod
def checkout(self, **kwargs) -> typing.Union[str, None]:
...
def checkout(self, **kwargs) -> typing.Union[str, None]: ...

@abc.abstractmethod
def status(self, **kwargs) -> typing.Union[typing.Tuple[str, str], str]:
...
def status(self, **kwargs) -> typing.Union[typing.Tuple[str, str], str]: ...

@abc.abstractmethod
def matches(self) -> bool:
...
def matches(self) -> bool: ...

@abc.abstractmethod
def update(self, **kwargs) -> typing.Union[str, None]:
...
def update(self, **kwargs) -> typing.Union[str, None]: ...


def yesno(
Expand Down Expand Up @@ -150,23 +147,16 @@ def get_workingcopytypes() -> typing.Dict[str, typing.Type[BaseWorkingCopy]]:
if _workingcopytypes:
return _workingcopytypes
group = "mxdev.workingcopytypes"
addons = {}
for entrypoint in pkg_resources.iter_entry_points(group=group):
addons: dict[str, typing.Type[BaseWorkingCopy]] = {}
for entrypoint in load_eps_by_group(group):
key = entrypoint.name
workingcopytype = entrypoint.load()
if not entrypoint.dist:
continue
if entrypoint.dist.project_name == "mxdev":
_workingcopytypes[key] = workingcopytype
continue
if key in addons:
logger.error(
f"There already is a working copy type addon registered for '{key}'."
f"Duplicate workingcopy types registration '{key}' at "
f"{entrypoint.value} can not override {addons[key]}"
)
sys.exit(1)
logger.info(
f"Overwriting '{key}' with addon from '{entrypoint.dist.project_name}'."
)
addons[key] = workingcopytype
_workingcopytypes.update(addons)
return _workingcopytypes
Expand Down
2 changes: 2 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ envlist =
py38
py39
py310
py311
py312
minversion = 3.25.0
requires =
virtualenv >= 20.14.1
Expand Down
Loading