Skip to content

Commit

Permalink
refactor: moving from deprecated pkg_resources API, bumping requireme…
Browse files Browse the repository at this point in the history
…nts, adding 3.12 and 3.13 support (#87)

* build: running edgetest on edgetest

* ci: adding 3.12 and 3.13 to our build matrices

* test: fixing warning from pytest about our core class

* refactor: removing use of deprecated pkg_resources API and moving towards packaging

* build: adding 3.12 and 3.13 classifiers to pyproject.toml

* chore: bumping version

* ci: removing 3.13 support since it doesn't seem well-adopted at the moment

* test: moving up the pins for integration test packages since the older versions don't support Python 3.12
  • Loading branch information
ak-gupta authored Oct 25, 2024
1 parent f8b186a commit dfc8b73
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 38 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest]
python-version:
- 3.8
- 3.9
- "3.10"
- "3.11"
- "3.12"
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
Expand Down
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
author = "Akshay Gupta"

# The short X.Y version
version = "2024.8.0"
version = "2024.10.0"
# The full version, including alpha/beta/rc tags
release = ""

Expand Down
2 changes: 1 addition & 1 deletion edgetest/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Package initialization."""

__version__ = "2024.8.0"
__version__ = "2024.10.0"

__title__ = "edgetest"
__description__ = "Bleeding edge dependency testing"
Expand Down
3 changes: 3 additions & 0 deletions edgetest/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ class TestPackage:
after ``run_tests`` has been executed.
"""

# Tell pytest this isn't for tests
__test__ = False

def __init__(
self,
hook: _HookRelay,
Expand Down
70 changes: 46 additions & 24 deletions edgetest/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
from subprocess import PIPE, Popen
from typing import Any, Dict, List, Optional, Tuple, Union

from packaging.specifiers import SpecifierSet
from pkg_resources import parse_requirements
from packaging.requirements import Requirement
from packaging.specifiers import Specifier, SpecifierSet
from tomlkit import TOMLDocument, load
from tomlkit.container import Container
from tomlkit.items import Array, Item, String, Table
Expand Down Expand Up @@ -97,7 +97,11 @@ def convert_requirements(requirements: str, conf: Optional[Dict] = None) -> Dict
A configuration dictionary.
"""
conf = {"envs": []} if conf is None else conf
pkgs = [pkg.project_name for pkg in parse_requirements(requirements)]
pkgs = [
Requirement(val).name
for val in requirements.splitlines()
if not (val.strip().startswith("#") or val.strip() == "")
]
for pkg in pkgs:
conf["envs"].append({})
conf["envs"][-1]["name"] = pkg
Expand All @@ -119,7 +123,7 @@ def gen_requirements_config(fname_or_buf: str, **options) -> Dict:
Parameters
----------
fname_or_buf : str
Path to the requirements file to parse using ``pkg_resources.parse_requirements``
Path to the requirements file to parse using ``packaging.requirements.Requirement``
or the string representing the requirements file.
**options
Options to apply to each test environment.
Expand Down Expand Up @@ -387,7 +391,7 @@ def upgrade_requirements(
Parameters
----------
fname_or_buf : str
Path to the requirements file to parse using ``pkg_resources.parse_requirements``
Path to the requirements file to parse using ``packaging.requirements.Requirement``
or the string representing the requirements file.
upgraded_packages : list
A list of packages upgraded in the testing procedure.
Expand All @@ -407,23 +411,32 @@ def upgrade_requirements(
except OSError:
# Filename too long for the is_file() function
cfg = fname_or_buf
pkgs = list(parse_requirements(cfg))
pkgs = [
Requirement(val)
for val in cfg.splitlines()
if not (val.strip().startswith("#") or val.strip() == "")
]
upgrades = {pkg["name"]: pkg["version"] for pkg in upgraded_packages}

for pkg in pkgs:
if pkg.project_name not in upgrades:
if pkg.name not in upgrades:
continue
# Replace the spec
specs = deepcopy(pkg.specs)
specs = list(pkg.specifier)
new_spec = list(pkg.specifier)
for index, value in enumerate(specs):
if value[0] == "<=":
pkg.specs[index] = ("<=", upgrades[pkg.project_name])
elif value[0] == "<":
pkg.specs[index] = ("!=", value[1])
pkg.specs.append(("<=", upgrades[pkg.project_name]))
elif value[0] == "==":
pkg.specs = [(">=", value[1]), ("<=", upgrades[pkg.project_name])]
pkg.specifier = SpecifierSet(",".join("".join(spec) for spec in pkg.specs)) # type: ignore
if value.operator == "<=":
new_spec[index] = Specifier(f"<={upgrades[pkg.name]}")
elif value.operator == "<":
new_spec[index] = Specifier(f"!={value.version}")
new_spec.append(Specifier(f"<={upgrades[pkg.name]}"))
elif value.operator == "==":
new_spec = Specifier(f">={value.version}") & Specifier(
f"<={upgrades[pkg.name]}"
) # type: ignore
# End the loop
break
pkg.specifier = SpecifierSet(",".join(str(spec) for spec in new_spec))

return "\n".join(str(pkg) for pkg in pkgs)

Expand Down Expand Up @@ -522,15 +535,15 @@ def _isin_case_dashhyphen_ins(a: str, vals: List[str]) -> bool:
return any(a.replace("_", "-").lower() == b.replace("_", "-").lower() for b in vals)


def get_lower_bounds(requirements: str, lower: str) -> str:
def get_lower_bounds(requirements: Union[str, List[str]], lower: str) -> str:
r"""Get lower bounds of requested packages from installation requirements.
Parses through the project ``requirements`` and the newline-delimited
packages requested in ``lower`` to find the lower bounds.
Parameters
----------
requirements : str
requirements : str or list
Project setup requirements,
e.g. ``"pandas>=1.5.1,<=1.4.2\nnumpy>=1.22.1,<=1.25.4"``
lower : str
Expand All @@ -542,12 +555,21 @@ def get_lower_bounds(requirements: str, lower: str) -> str:
str
The packages along with the lower bound, e.g. ``"pandas==1.5.1\nnumpy==1.22.1"``.
"""
all_lower_bounds = {
pkg.project_name + (f"[{','.join(pkg.extras)}]" if pkg.extras else ""): dict(
pkg.specs
).get(">=")
for pkg in parse_requirements(requirements)
}
if isinstance(requirements, str):
pkgs = [
Requirement(val)
for val in requirements.splitlines()
if not (val.strip().startswith("#") or val.strip() == "")
]
elif isinstance(requirements, list):
pkgs = [Requirement(val) for val in requirements]
all_lower_bounds: Dict[str, str] = {}
for pkg in pkgs:
full_name = pkg.name + (f"[{','.join(pkg.extras)}]" if pkg.extras else "")
for spec in pkg.specifier:
if spec.operator == ">=":
all_lower_bounds[full_name] = spec.version
break

lower_with_bounds = ""
for pkg_name, lower_bound in all_lower_bounds.items():
Expand Down
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
]
dependencies = ["Cerberus<=1.3.5,>=1.3.0", "click<=8.1.7,>=7.0", "pluggy<=1.4.0,>=1.3.0", "tabulate<=0.9.0,>=0.8.9", "packaging<=24.0,>20.6", "tomlkit<=0.11.4,>=0.11.4", "uv<=0.2.28,>=0.2.0"]
dependencies = ["Cerberus<=1.3.5,>=1.3.0", "click<=8.1.7,>=7.0", "pluggy<=1.5.0,>=1.3.0", "tabulate<=0.9.0,>=0.8.9", "packaging<=24.1,>20.6", "tomlkit<=0.11.4,>=0.11.4", "uv<=0.4.26,>=0.2.0"]

dynamic = ["readme", "version"]

Expand Down Expand Up @@ -93,7 +94,7 @@ lower = [
# BUMPVER --------------------------------------------------------------------

[bumpver]
current_version = "2024.8.0"
current_version = "2024.10.0"
version_pattern = "YYYY.MM.INC0"

[bumpver.file_patterns]
Expand Down
8 changes: 4 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# This file was autogenerated by uv via the following command:
# uv pip compile -o requirements.txt pyproject.toml
# uv pip compile --output-file=requirements.txt pyproject.toml
cerberus==1.3.5
# via edgetest (pyproject.toml)
click==8.1.7
# via edgetest (pyproject.toml)
packaging==24.0
packaging==24.1
# via edgetest (pyproject.toml)
pluggy==1.4.0
pluggy==1.5.0
# via edgetest (pyproject.toml)
tabulate==0.9.0
# via edgetest (pyproject.toml)
tomlkit==0.11.4
# via edgetest (pyproject.toml)
uv==0.2.28
uv==0.4.26
# via edgetest (pyproject.toml)
6 changes: 3 additions & 3 deletions tests/test_integration_cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
include_package_data = True
packages = find:
install_requires =
polars<=1.0.0,>=0.20.31
polars>=1.0.0,<=1.5.0
[options.extras_require]
tests =
Expand Down Expand Up @@ -75,8 +75,8 @@
include_package_data = True
packages = find:
install_requires =
scikit-learn>=1.0,<=1.2.0
polars[pyarrow]<=1.0.0,>=0.20.31
scikit-learn>=1.3.2,<=1.4.0
polars[pyarrow]>=1.0.0,<=1.5.0
[options.extras_require]
tests =
Expand Down
4 changes: 2 additions & 2 deletions tests/test_integration_toml.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
version = "0.1.0"
description = "Fake description"
requires-python = ">=3.7.0"
dependencies = ["polars<=1.0.0,>=0.20.31"]
dependencies = ["polars>=1.0.0,<=1.5.0"]
[project.optional-dependencies]
tests = ["pytest"]
Expand All @@ -48,7 +48,7 @@
version = "0.1.0"
description = "Fake description"
requires-python = ">=3.7.0"
dependencies = ["Scikit_Learn>=1.0,<=1.2.0", "Polars[pyarrow]<=1.0.0,>=0.20.31"]
dependencies = ["Scikit_Learn>=1.3.2,<=1.4.0", "Polars[pyarrow]>=1.0.0,<=1.5.0"]
[project.optional-dependencies]
tests = ["pytest"]
Expand Down

0 comments on commit dfc8b73

Please sign in to comment.