Skip to content

Commit

Permalink
Transition from using setup.py to pyproject.toml to specify project m…
Browse files Browse the repository at this point in the history
…etadata (#89)
  • Loading branch information
R-Palazzo authored Mar 4, 2024
1 parent 7c6f4b3 commit 8da3fed
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 111 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/readme.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,7 @@ jobs:
run: |
python -m pip install --upgrade pip
python -m pip install invoke rundoc .
python -m pip install tomli
python -m pip install packaging
- name: Run the README.md
run: invoke readme
4 changes: 2 additions & 2 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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',
...
Expand Down
3 changes: 1 addition & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,7 @@ coverage: ## check code coverage quickly with the default Python

.PHONY: dist
dist: clean ## builds source and wheel package
python setup.py sdist
python setup.py bdist_wheel
python -m build --wheel --sdist
ls -l dist

.PHONY: publish-confirm
Expand Down
107 changes: 53 additions & 54 deletions setup.py → pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
[build-system]
requires = ['setuptools', 'wheel']
build-backend = 'setuptools.build_meta'

"""The setup script."""

from setuptools import setup, find_packages

with open('README.md', encoding='utf-8') as readme_file:
readme = readme_file.read()

with open('HISTORY.md', encoding='utf-8') as history_file:
history = history_file.read()

install_requires = [
[project]
name = 'deepecho'
description = 'Create sequential synthetic data of mixed types using a GAN.'
authors = [{ name = 'DataCebo, Inc.', email = 'info@sdv.dev' }]
classifiers = [
'Development Status :: 2 - Pre-Alpha',
'Intended Audience :: Developers',
'License :: Free for non-commercial use',
'Natural Language :: English',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Topic :: Scientific/Engineering :: Artificial Intelligence',
]
keywords = ['deepecho', 'DeepEcho']
version = '0.5.1.dev0'
license = { text = 'BSL-1.1' }
requires-python = '>=3.8,<3.12'
readme = 'README.md'
dependencies = [
"numpy>=1.20.0,<2;python_version<'3.10'",
"numpy>=1.23.3,<2;python_version>='3.10'",
"pandas>=1.1.3;python_version<'3.10'",
Expand All @@ -23,19 +35,25 @@
'tqdm>=4.15,<5',
]

setup_requires = [
'pytest-runner>=2.11.1',
]
[project.urls]
"Source Code"= "https://github.com/sdv-dev/Deepecho/"
"Issue Tracker" = "https://github.com/sdv-dev/Deepecho/issues"
"Twitter" = "https://twitter.com/sdv_dev"
"Chat" = "https://bit.ly/sdv-slack-invite"

tests_require = [
[project.optional-dependencies]
test = [
'pytest>=3.4.2',
'pytest-cov>=2.6.0',
'pytest-rerunfailures>=9.0.0,<10',
'jupyter>=1.0.0,<2',
'rundoc>=0.4.3,<0.5',
'pytest-runner >= 2.11.1',
'tomli>=2.0.0,<3',
]
dev = [
'deepecho[test]',

development_requires = [
# general
'setuptools<49.2',
'bumpversion>=0.5.3,<0.6',
Expand Down Expand Up @@ -79,39 +97,20 @@
'invoke'
]

setup(
author='DataCebo, Inc.',
author_email='info@sdv.dev',
classifiers=[
'Development Status :: 2 - Pre-Alpha',
'Intended Audience :: Developers',
'License :: Free for non-commercial use',
'Natural Language :: English',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Topic :: Scientific/Engineering :: Artificial Intelligence',
],
description='Create sequential synthetic data of mixed types using a GAN.',
extras_require={
'test': tests_require,
'dev': development_requires + tests_require,
},
include_package_data=True,
install_requires=install_requires,
keywords='deepecho deepecho DeepEcho',
license='BSL-1.1',
long_description=readme + '\n\n' + history,
long_description_content_type='text/markdown',
name='deepecho',
packages=find_packages(include=['deepecho', 'deepecho.*']),
python_requires='>=3.8,<3.12',
setup_requires=setup_requires,
test_suite='tests',
tests_require=tests_require,
url='https://github.com/sdv-dev/DeepEcho',
version='0.5.1.dev0',
zip_safe=False,
)
[tool.setuptools]
include-package-data = true

[tool.setuptools.packages.find]
include = ['deepecho', 'deepecho.*']
namespaces = false

[tool.isort]
include_trailing_comment = true
line_length = 99
lines_between_types = 0
multi_line_output = 4
not_skip = ['__init__.py']
use_parentheses = true

[tool.pytest.ini_options]
collect_ignore = ['pyproject.toml']
13 changes: 1 addition & 12 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ values =

[bumpversion:part:candidate]

[bumpversion:file:setup.py]
[bumpversion:file:pyproject.toml]
search = version='{current_version}'
replace = version='{new_version}'

Expand All @@ -43,20 +43,9 @@ ignore-names =
Y,
Y_padded

[isort]
include_trailing_comment = True
line_length = 99
lines_between_types = 0
multi_line_output = 4
not_skip = __init__.py
use_parentheses = True

[aliases]
test = pytest

[tool:pytest]
collect_ignore = ['setup.py']

[pylint]
persistent = no
extension-pkg-whitelist = numpy
Expand Down
79 changes: 38 additions & 41 deletions tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -39,48 +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('setup.py', 'r') as setup_py:
lines = setup_py.read().splitlines()

versions = []
started = False
for line in lines:
if started:
if line == ']':
break

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\.?)+', line).group(0)
if version:
version = re.sub(r'>=?', '==', version)
version = re.sub(r"""['",]""", '', version)
requirement += version
versions.append(requirement)

elif line.startswith('install_requires = ['):
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
Expand Down
38 changes: 38 additions & 0 deletions tests/test_tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""Tests for the ``tasks.py`` file."""
from tasks import _get_minimum_versions


def test_get_minimum_versions():
"""Test the ``_get_minimum_versions`` method.
The method should return the minimum versions of the dependencies for the given python version.
If a library is linked to an URL, the minimum version should be the URL.
"""
# Setup
dependencies = [
"numpy>=1.20.0,<2;python_version<'3.10'",
"numpy>=1.23.3,<2;python_version>='3.10'",
"pandas>=1.2.0,<2;python_version<'3.10'",
"pandas>=1.3.0,<2;python_version>='3.10'",
'humanfriendly>=8.2,<11',
'pandas @ git+https://github.com/pandas-dev/pandas.git@master#egg=pandas'
]

# Run
minimum_versions_39 = _get_minimum_versions(dependencies, '3.9')
minimum_versions_310 = _get_minimum_versions(dependencies, '3.10')

# Assert
expected_versions_39 = [
'numpy==1.20.0',
'pandas @ git+https://github.com/pandas-dev/pandas.git@master#egg=pandas',
'humanfriendly==8.2',
]
expected_versions_310 = [
'numpy==1.23.3',
'pandas @ git+https://github.com/pandas-dev/pandas.git@master#egg=pandas',
'humanfriendly==8.2',
]

assert minimum_versions_39 == expected_versions_39
assert minimum_versions_310 == expected_versions_310

0 comments on commit 8da3fed

Please sign in to comment.