diff --git a/.github/workflows/readme.yml b/.github/workflows/readme.yml index b3a4413..5f8ba53 100644 --- a/.github/workflows/readme.yml +++ b/.github/workflows/readme.yml @@ -22,5 +22,6 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install invoke rundoc . + python -m pip install tomli - name: Run the README.md run: invoke readme diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 0205c61..08a98bb 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -219,9 +219,9 @@ This will perform the following actions: 2. Bump the current version to the next release candidate, ``X.Y.Z.dev(N+1)`` After this is done, the new pre-release can be installed by including the ``dev`` section in the -dependency specification, either in ``setup.py``:: +dependency specification, either in ``pyproject.toml``:: - install_requires = [ + dependencies = [ ... 'deepecho>=X.Y.Z.dev', ... diff --git a/pyproject.toml b/pyproject.toml index 4ad3db9..91774e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,6 +48,7 @@ test = [ 'pytest-rerunfailures>=9.0.0,<10', 'jupyter>=1.0.0,<2', 'rundoc>=0.4.3,<0.5', + 'tomli>=2.0.0,<3', ] dev = [ 'deepecho[test]', diff --git a/tasks.py b/tasks.py index 5f9190d..91c3bce 100644 --- a/tasks.py +++ b/tasks.py @@ -2,15 +2,15 @@ import inspect import operator import os -import re -import pkg_resources -import platform import shutil import stat +import sys from pathlib import Path +import tomli from invoke import task - +from packaging.requirements import Requirement +from packaging.version import Version COMPARISONS = { '>=': operator.ge, @@ -39,49 +39,45 @@ def unit(c): c.run('python -m pytest ./tests/unit --reruns 3') -def _validate_python_version(line): - is_valid = True - for python_version_match in re.finditer(r"python_version(<=?|>=?|==)\'(\d\.?)+\'", line): - python_version = python_version_match.group(0) - comparison = re.search(r'(>=?|<=?|==)', python_version).group(0) - version_number = python_version.split(comparison)[-1].replace("'", "") - comparison_function = COMPARISONS[comparison] - is_valid = is_valid and comparison_function( - pkg_resources.parse_version(platform.python_version()), - pkg_resources.parse_version(version_number), - ) +def _get_minimum_versions(dependencies, python_version): + min_versions = {} + for dependency in dependencies: + if '@' in dependency: + name, url = dependency.split(' @ ') + min_versions[name] = f'{name} @ {url}' + continue + + req = Requirement(dependency) + if ';' in dependency: + marker = req.marker + if marker and not marker.evaluate({'python_version': python_version}): + continue # Skip this dependency if the marker does not apply to the current Python version + + if req.name not in min_versions: + min_version = next((spec.version for spec in req.specifier if spec.operator in ('>=', '==')), None) + if min_version: + min_versions[req.name] = f'{req.name}=={min_version}' - return is_valid + elif '@' not in min_versions[req.name]: + existing_version = Version(min_versions[req.name].split('==')[1]) + new_version = next((spec.version for spec in req.specifier if spec.operator in ('>=', '==')), existing_version) + if new_version > existing_version: + min_versions[req.name] = f'{req.name}=={new_version}' # Change when a valid newer version is found + + return list(min_versions.values()) @task def install_minimum(c): - with open('pyproject.toml', 'r') as pyproject: - lines = pyproject.read().splitlines() - - versions = [] - started = False - for line in lines: - if started: - if line == ']': - started = False - continue - - line = line.strip() - if _validate_python_version(line): - requirement = re.match(r'[^>]*', line).group(0) - requirement = re.sub(r"""['",]""", '', requirement) - version = re.search(r'>=?(\d\.?)+\w*', line).group(0) - if version: - version = re.sub(r'>=?', '==', version) - version = re.sub(r"""['",]""", '', version) - requirement += version - versions.append(requirement) - - elif (line.startswith('dependencies = [')): - started = True - - c.run(f'python -m pip install {" ".join(versions)}') + with open('pyproject.toml', 'rb') as pyproject_file: + pyproject_data = tomli.load(pyproject_file) + + dependencies = pyproject_data.get('project', {}).get('dependencies', []) + python_version = '.'.join(map(str, sys.version_info[:2])) + minimum_versions = _get_minimum_versions(dependencies, python_version) + + if minimum_versions: + c.run(f'python -m pip install {" ".join(minimum_versions)}') @task