diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000000..65dd95ba48 --- /dev/null +++ b/.flake8 @@ -0,0 +1,6 @@ +[flake8] +# E203: whitespace before ':' +# E402: module level import not at top of file +# E501: line too long +extend-ignore = E203, E402, E501 +max-line-length = 88 diff --git a/.github/ISSUE_TEMPLATE/~release-checklist.md b/.github/ISSUE_TEMPLATE/~release-checklist.md index 5567cbcf7a..12de456ab8 100644 --- a/.github/ISSUE_TEMPLATE/~release-checklist.md +++ b/.github/ISSUE_TEMPLATE/~release-checklist.md @@ -32,7 +32,7 @@ about: Checklist for core developers to complete as part of making a release * [ ] Verify that a Binder has properly built for the new release. * [ ] Watch for a GitHub notification that there is an automatic PR to the [Conda-forge feedstock](https://github.com/conda-forge/pyhf-feedstock). This may take multiple hours to happen. If there are any changes needed to the Conda-forge release make them **from a personal account** and not from an organization account to have workflows properly trigger. - [ ] Check if any requirements need to be updated by commenting "@conda-grayskull show requirements" on the PR. - - [ ] Verify the requirements in the [Conda-forge feedstock](https://github.com/conda-forge/pyhf-feedstock) recipe `meta.yaml` match those in `setup.cfg` and `pyproject.toml`. + - [ ] Verify the requirements in the [Conda-forge feedstock](https://github.com/conda-forge/pyhf-feedstock) recipe `meta.yaml` match those in `pyproject.toml`. ## After Release diff --git a/.github/workflows/publish-package.yml b/.github/workflows/publish-package.yml index c9050ffe48..add241b00f 100644 --- a/.github/workflows/publish-package.yml +++ b/.github/workflows/publish-package.yml @@ -37,16 +37,12 @@ jobs: with: python-version: '3.10' - - name: Install python-build, check-manifest, and twine + - name: Install python-build and twine run: | - python -m pip install --upgrade pip setuptools wheel - python -m pip install build check-manifest twine + python -m pip install --upgrade pip + python -m pip install build twine python -m pip list - - name: Check MANIFEST - run: | - check-manifest - - name: Build a wheel and a sdist run: | PYTHONWARNINGS=error,default::DeprecationWarning python -m build . diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index e5af33dbdc..0000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,13 +0,0 @@ -prune ** -graft src -exclude src/conftest.py - -include setup.py -include setup.cfg -include LICENSE -include README.rst -include pyproject.toml -include MANIFEST.in -include AUTHORS - -global-exclude __pycache__ *.py[cod] diff --git a/pyproject.toml b/pyproject.toml index 4214261f18..86f57723fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,159 @@ [build-system] -# Minimum requirements for the build system to execute. -requires = ["setuptools>=61.0.0", "setuptools_scm>=7.0.1"] -build-backend = "setuptools.build_meta" +requires = [ + "hatchling>=1.13.0", + "hatch-vcs>=0.3.0", +] +build-backend = "hatchling.build" + +[project] +name = "pyhf" +dynamic = ["version"] +description = "pure-Python HistFactory implementation with tensors and autodiff" +readme = "README.rst" +license = { text = "Apache-2.0" } # SPDX short identifier +requires-python = ">=3.7" +authors = [ + { name = "Lukas Heinrich", email = "lukas.heinrich@cern.ch" }, + { name = "Matthew Feickert", email = "matthew.feickert@cern.ch" }, + { name = "Giordon Stark", email = "gstark@cern.ch" }, +] +maintainers = [ {name = "The Scikit-HEP admins", email = "scikit-hep-admins@googlegroups.com"} ] +keywords = [ + "fitting", + "jax", + "numpy", + "physics", + "pytorch", + "scipy", + "tensorflow", +] +classifiers = [ + "Development Status :: 4 - Beta", + "Environment :: WebAssembly :: Emscripten", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Scientific/Engineering", + "Topic :: Scientific/Engineering :: Physics", +] +dependencies = [ + "click>=8.0.0", # for console scripts + "importlib_resources>=1.4.0; python_version < '3.9'", # for resources in schema + "jsonpatch>=1.15", + "jsonschema>=4.15.0", # for utils + "pyyaml>=5.1", # for parsing CLI equal-delimited options + "scipy>=1.2.0", # requires numpy, which is required by pyhf and tensorflow + "tqdm>=4.56.0", # for readxml + "typing_extensions>=3.7.4.3; python_version == '3.7'", # for SupportsIndex + "numpy", # compatible versions controlled through scipy +] + +[project.scripts] +pyhf = "pyhf.cli:cli" + +[project.urls] +Documentation = "https://pyhf.readthedocs.io/" +Homepage = "https://github.com/scikit-hep/pyhf" +"Issue Tracker" = "https://github.com/scikit-hep/pyhf/issues" +"Release Notes" = "https://pyhf.readthedocs.io/en/stable/release-notes.html" +"Releases" = "https://github.com/scikit-hep/pyhf/releases" +"Source Code" = "https://github.com/scikit-hep/pyhf" + +[project.optional-dependencies] +shellcomplete = ["click_completion"] +tensorflow = [ + "tensorflow>=2.7.0; platform_machine != 'arm64'", # c.f. PR #1962 + "tensorflow-macos>=2.7.0; platform_machine == 'arm64' and platform_system == 'Darwin'", # c.f. PR #2119 + "tensorflow-probability>=0.11.0", # c.f. PR #1657 +] +torch = ["torch>=1.10.0"] # c.f. PR #1657 +jax = [ + "jax>=0.2.10", # c.f. PR #1962, Issue #1501 + "jaxlib>=0.1.61,!=0.1.68", # c.f. PR #1962, Issue #1501 +] +xmlio = ["uproot>=4.1.1"] # c.f. PR #1567 +minuit = ["iminuit>=2.7.0"] # c.f. PR #1895 +contrib = [ + "matplotlib>=3.0.0", + "requests>=2.22.0", +] +backends = ["pyhf[tensorflow,torch,jax,minuit]"] +all = ["pyhf[backends,xmlio,contrib,shellcomplete]"] -[tool.setuptools_scm] -write_to = "src/pyhf/_version.py" +# Developer extras +test = [ + "pyhf[all]", + "scikit-hep-testdata>=0.4.11", + "pytest>=6.0", + "pytest-cov>=2.5.1", + "pytest-mock", + "requests-mock>=1.9.0", + "pytest-benchmark[histogram]", + "pytest-console-scripts", + "pytest-mpl", + "pydocstyle", + "papermill~=2.3.4", + "scrapbook~=0.5.0", + "jupyter", + "graphviz", + "pytest-socket>=0.2.0", # c.f. PR #1917 +] +docs = [ + "pyhf[xmlio,contrib]", + "sphinx>=5.1.1", # c.f. https://github.com/scikit-hep/pyhf/pull/1926 + "sphinxcontrib-bibtex~=2.1", + "sphinx-click", + "sphinx_rtd_theme", + "nbsphinx!=0.8.8", # c.f. https://github.com/spatialaudio/nbsphinx/issues/620 + "ipywidgets", + "sphinx-issues", + "sphinx-copybutton>=0.3.2", + "sphinx-togglebutton>=0.3.0", + "ipython!=8.7.0", # c.f. https://github.com/scikit-hep/pyhf/pull/2068 +] +develop = [ + "pyhf[test,docs]", + "tbump>=6.7.0", + "pre-commit", + "nox", + "codemetapy>=2.3.0", +] + +[tool.hatch.version] +source = "vcs" + +[tool.hatch.version.raw-options] local_scheme = "no-local-version" +[tool.hatch.build.hooks.vcs] +version-file = "src/pyhf/_version.py" + +[tool.hatch.build.targets.sdist] +# only-include needed to properly include src/pyhf/schemas +# c.f. https://github.com/pypa/hatch/pull/299 +# hatchling always includes: +# pyproject.toml, .gitignore, any README, any LICENSE, AUTHORS +only-include = [ + "/src", + "/CITATION.cff" +] +exclude = [ + "/src/conftest.py" +] + +[tool.hatch.build.targets.wheel] +packages = ["src/pyhf"] + [tool.black] line-length = 88 -target-version = ['py37', 'py38'] +target-version = ['py37', 'py38', 'py39', 'py310', 'py311'] skip-string-normalization = true include = '\.pyi?$' exclude = ''' @@ -17,27 +161,10 @@ exclude = ''' \.git | .eggs | build + | .nox )/ ''' -[tool.check-manifest] -ignore = [ - 'docs*', - 'validation*', - 'examples*', - 'tests*', - 'docker*', - 'binder*', - '.*', - 'pyproject.toml', - 'pytest.ini', - 'codecov.yml', - 'codemeta.json', - 'CODE_OF_CONDUCT.md', - 'CONTRIBUTING.md', - 'AUTHORS', -] - [tool.pytest.ini_options] minversion = "6.0" xfail_strict = true @@ -78,6 +205,7 @@ markers = [ ] filterwarnings = [ "error", + 'ignore::DeprecationWarning', # ignore DeprecationWarning on patch release branches 'ignore:the imp module is deprecated:DeprecationWarning', # tensorflow 'ignore:distutils Version classes are deprecated:DeprecationWarning', # tensorflow-probability 'ignore:the `interpolation=` argument to percentile was renamed to `method=`, which has additional options:DeprecationWarning', # Issue #1772 @@ -90,6 +218,8 @@ filterwarnings = [ 'ignore:divide by zero encountered in (true_)?divide:RuntimeWarning', #FIXME: pytest tests/test_tensor.py::test_pdf_calculations[numpy] 'ignore:[A-Z]+ is deprecated and will be removed in Pillow 10:DeprecationWarning', # keras 'ignore:Call to deprecated create function:DeprecationWarning', # protobuf via tensorflow + 'ignore:`np.bool8` is a deprecated alias for `np.bool_`:DeprecationWarning', # numpy via tensorflow + "ignore:module 'sre_constants' is deprecated:DeprecationWarning", # tensorflow v2.12.0+ for Python 3.11+ ] [tool.nbqa.mutate] @@ -100,7 +230,7 @@ pyupgrade = ["--py37-plus"] [tool.mypy] files = "src" -python_version = "3.10" +python_version = "3.11" warn_unused_configs = true strict = true show_error_codes = true diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 3484d02c58..0000000000 --- a/setup.cfg +++ /dev/null @@ -1,59 +0,0 @@ -[metadata] -name = pyhf -description = pure-Python HistFactory implementation with tensors and autodiff -long_description = file: README.rst -long_description_content_type = text/x-rst -url = https://github.com/scikit-hep/pyhf -author = Lukas Heinrich, Matthew Feickert, Giordon Stark -author_email = lukas.heinrich@cern.ch, matthew.feickert@cern.ch, gstark@cern.ch -license = Apache -license_files = LICENSE -keywords = physics fitting numpy scipy tensorflow pytorch jax -project_urls = - Documentation = https://pyhf.readthedocs.io/ - Source Code = https://github.com/scikit-hep/pyhf - Issue Tracker = https://github.com/scikit-hep/pyhf/issues - Release Notes = https://pyhf.readthedocs.io/en/stable/release-notes.html -classifiers = - Development Status :: 4 - Beta - License :: OSI Approved :: Apache Software License - Intended Audience :: Science/Research - Topic :: Scientific/Engineering - Topic :: Scientific/Engineering :: Physics - Programming Language :: Python :: 3 - Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: Implementation :: CPython - -[options] -packages = find_namespace: -package_dir = - = src -include_package_data = True -python_requires = >=3.7 -install_requires = - scipy>=1.2.0 # requires numpy, which is required by pyhf and tensorflow - click>=8.0.0 # for console scripts - tqdm>=4.56.0 # for readxml - jsonschema>=4.15.0 # for utils - jsonpatch>=1.15 - pyyaml>=5.1 # for parsing CLI equal-delimited options - importlib_resources>=1.4.0; python_version < "3.9" # for resources in schema - typing_extensions>=3.7.4.3; python_version == "3.7" # for SupportsIndex - -[options.packages.find] -where = src - -[options.entry_points] -console_scripts = - pyhf = pyhf.cli:cli - -[flake8] -# E203: whitespace before ':' -# E402: module level import not at top of file -# E501: line too long -extend-ignore = E203, E402, E501 -max-line-length = 88 diff --git a/setup.py b/setup.py deleted file mode 100644 index 1406f9b4ff..0000000000 --- a/setup.py +++ /dev/null @@ -1,85 +0,0 @@ -from setuptools import setup - -extras_require = { - 'shellcomplete': ['click_completion'], - 'tensorflow': [ - 'tensorflow>=2.7.0', # c.f. PR #1962 - 'tensorflow-probability>=0.11.0', # c.f. PR #1657 - ], - 'torch': ['torch>=1.10.0'], # c.f. PR #1657 - 'jax': ['jax>=0.2.10', 'jaxlib>=0.1.61,!=0.1.68'], # c.f. PR #1962, Issue #1501 - 'xmlio': ['uproot>=4.1.1'], # c.f. PR #1567 - 'minuit': ['iminuit>=2.7.0'], # c.f. PR #1895 -} -extras_require['backends'] = sorted( - set( - extras_require['tensorflow'] - + extras_require['torch'] - + extras_require['jax'] - + extras_require['minuit'] - ) -) -extras_require['contrib'] = sorted({'matplotlib', 'requests'}) -extras_require['test'] = sorted( - set( - extras_require['backends'] - + extras_require['xmlio'] - + extras_require['contrib'] - + extras_require['shellcomplete'] - + [ - 'scikit-hep-testdata>=0.4.11', - 'pytest>=6.0', - 'pytest-cov>=2.5.1', - 'pytest-mock', - 'requests-mock>=1.9.0', - 'pytest-benchmark[histogram]', - 'pytest-console-scripts', - 'pytest-mpl', - 'pydocstyle', - 'papermill~=2.3.4', - 'scrapbook~=0.5.0', - 'jupyter', - 'graphviz', - 'pytest-socket>=0.2.0', # c.f. PR #1917 - ] - ) -) -extras_require['docs'] = sorted( - set( - extras_require['xmlio'] - + extras_require['contrib'] - + [ - 'sphinx>=5.1.1', # c.f. https://github.com/scikit-hep/pyhf/pull/1926 - 'sphinxcontrib-bibtex~=2.1', - 'sphinx-click', - 'sphinx_rtd_theme', - 'nbsphinx!=0.8.8', # c.f. https://github.com/spatialaudio/nbsphinx/issues/620 - 'ipywidgets', - 'sphinx-issues', - 'sphinx-copybutton>=0.3.2', - 'sphinx-togglebutton>=0.3.0', - ] - ) -) -extras_require['develop'] = sorted( - set( - extras_require['docs'] - + extras_require['test'] - + [ - 'nbdime', - 'tbump>=6.7.0', - 'ipython', - 'pre-commit', - 'check-manifest', - 'codemetapy>=0.3.4', - 'twine', - ] - ) -) -extras_require['complete'] = sorted(set(sum(extras_require.values(), []))) - - -setup( - extras_require=extras_require, - use_scm_version=lambda: {'local_scheme': lambda version: ''}, -)