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

Upgrade project, testing with nox, replace VisibleDeprecationWarning #106

Merged
merged 7 commits into from
Aug 6, 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
35 changes: 35 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Deploy

on:
workflow_dispatch:
release:
types: [published]
pull_request:
paths:
- .github/workflows/deploy.yml

jobs:
deploy:
runs-on: ubuntu-latest

environment:
name: pypi
url: https://pypi.org/p/numba-stats
permissions:
id-token: write

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # needed by setuptools_scm
- uses: actions/setup-python@v5
with:
python-version: '3.12'

- run: python -m pip install --upgrade pip build
- run: python -m build
- run: python -m pip install --prefer-binary $(echo dist/*.whl)'[test]'
- run: python -m pytest

- uses: pypa/gh-action-pypi-publish@release/v1
if: github.event_name == 'push' && contains(github.event.ref, '/tags/')
28 changes: 0 additions & 28 deletions .github/workflows/release.yml

This file was deleted.

18 changes: 12 additions & 6 deletions .github/workflows/ci.yml → .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: CI
name: Test

on:
push:
Expand All @@ -8,19 +8,25 @@ on:
paths-ignore:
- '*.md'

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: true

env:
PIP_ONLY_BINARY: ":all:"

jobs:
build:
test:

runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.12"]
python-version: ["3.9", "3.12"]

steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- run: python -m pip install --upgrade pip
- run: python -m pip install --prefer-binary -e .[test]
- run: python -m pytest
- run: python -m pip install --upgrade pip nox
- run: nox -s test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ venv
*.egg-info
.vscode
bench/*.svg
.nox
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@ repos:

# Python formatting
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.4.2
rev: 24.8.0
hooks:
- id: black
1 change: 0 additions & 1 deletion MANIFEST.in

This file was deleted.

22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# numba-stats

![](https://img.shields.io/pypi/v/numba-stats.svg)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.13236518.svg)](https://doi.org/10.5281/zenodo.13236518)

We provide `numba`-accelerated implementations of statistical distributions for common probability distributions

We provide `numba`-accelerated implementations of common probability distributions.

* Uniform
* (Truncated) Normal
Expand Down Expand Up @@ -83,6 +85,16 @@ You won't get these errors when you call the numba-stats PDFs outside of a compi
but
`norm_pdf(1, 2, 3)` (as implemented above) will fail.

## Documentation

To get documentation, please use `help()` in the Python interpreter.

Functions with equivalents in `scipy.stats` follow the `scipy` calling conventions exactly, except for distributions starting with `trunc...`, which follow a different convention, since the `scipy` behavior is very impractical. Even so, note that the `scipy` conventions are sometimes a bit unusual, particular in case of the exponential, the log-normal, and the uniform distribution. See the `scipy` docs for details.

## Citation

If you use this package in a scientific work, please cite us. You can generate citations in your preferred format on the [Zenodo website](https://doi.org/10.5281/zenodo.13236518).

## Benchmarks

The following benchmarks were produced on an Intel(R) Core(TM) i7-8569U CPU @ 2.80GHz against SciPy-1.10.1. The dotted line on the right-hand figure shows the expected speedup (4x) from parallelization on a CPU with four physical cores.
Expand Down Expand Up @@ -113,15 +125,9 @@ The `bernstein.density` does not profit from auto-parallelization, on the contra
![](docs/_static/bernstein.density.svg)
![](docs/_static/truncexpon.pdf.plus.norm.pdf.svg)

## Documentation

To get documentation, please use `help()` in the Python interpreter.

Functions with equivalents in `scipy.stats` follow the `scipy` calling conventions exactly, except for distributions starting with `trunc...`, which follow a different convention, since the `scipy` behavior is very impractical. Even so, note that the `scipy` conventions are sometimes a bit unusual, particular in case of the exponential, the log-normal, and the uniform distribution. See the `scipy` docs for details.

## Contributions

**You can help with adding more distributions, patches are very welcome.** Implementing a probability distribution is easy. You need to write it in simple Python that `numba` can understand. Special functions from `scipy.special` can be used after some wrapping, see submodule `numba_stats._special.py` how it is done.
**You can help with adding more distributions, patches are welcome.** Implementing a probability distribution is easy. You need to write it in simple Python that `numba` can understand. Special functions from `scipy.special` can be used after some wrapping, see submodule `numba_stats._special.py` how it is done.

## numba-stats and numba-scipy

Expand Down
2 changes: 0 additions & 2 deletions coverage.sh

This file was deleted.

50 changes: 50 additions & 0 deletions noxfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""
Noxfile to orchestrate tests and computing coverage.

Pass extra arguments to pytest after --
"""

import nox
import sys

sys.path.append(".")
import python_releases

nox.needs_version = ">=2024.3.2"
nox.options.default_venv_backend = "uv|virtualenv"

ENV = {
"COVERAGE_CORE": "sysmon", # faster coverage on Python 3.12
}

PYPROJECT = nox.project.load_toml("pyproject.toml")
MINIMUM_PYTHON = PYPROJECT["project"]["requires-python"].strip(">=")
LATEST_PYTHON = str(python_releases.latest())

nox.options.sessions = ["test", "maxtest"]

# running in parallel with pytest-xdist does not make the tests faster


@nox.session(reuse_venv=True)
def test(session: nox.Session) -> None:
"""Run all tests."""
session.install("-e.[test]")
session.run("pytest", *session.posargs)


@nox.session(python=LATEST_PYTHON, reuse_venv=True)
def maxtest(session: nox.Session) -> None:
"""Run the unit and regular tests."""
session.install("-e.[test]")
session.run("pytest", *session.posargs, env=ENV)


# Python-3.12 provides coverage info faster
@nox.session(python="3.12", reuse_venv=True)
def cov(session: nox.Session) -> None:
"""Run covage and place in 'htmlcov' directory."""
session.install("-e.[test]")
session.run("coverage", "run", "-m", "pytest", env=ENV)
session.run("coverage", "html", "-d", "htmlcov")
session.run("coverage", "report", "-m")
41 changes: 40 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,47 @@
requires = ["setuptools>=42", "setuptools_scm[toml]>=3.4"]
build-backend = "setuptools.build_meta"

[project]
name = "numba-stats"
dynamic = ["version"]
requires-python = ">=3.9"
dependencies = ["numba>=0.53", "numpy>=1.20", "scipy>=1.5"]
authors = [{ name = "Hans Dembinski", email = "[email protected]" }]
readme = "README.md"
description = "Numba-accelerated implementations of scipy probability distributions and others used in particle physics"
license = { text = "MIT" }
classifiers = [
# complete classifier list: http://pypi.python.org/pypi?%3Aaction=list_classifiers
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Science/Research',
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3 :: Only',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: Implementation :: CPython',
]

[project.urls]
repository = "https://github.com/hdembinski/numba-stats"

[project.optional-dependencies]
test = [
"pytest>=6",
"pytest-cov>=5",
"pytest-benchmark>=4",
"pydocstyle>=6",
"coverage>=6",
]

[tool.setuptools.packages.find]
where = ["src"]

[tool.setuptools_scm]
write_to = "src/numba_stats/_version.py"

[tool.pytest.ini_options]
minversion = "6.0"
Expand Down
64 changes: 64 additions & 0 deletions python_releases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""Get the latest Python release which is online."""

import urllib.request
import re
from html.parser import HTMLParser
import gzip
from packaging.version import Version


class PythonVersionParser(HTMLParser):
"""Specialized HTMLParser to get Python version number."""

def __init__(self):
"""Initialize parser state."""
super().__init__()
self.versions = set()
self.found_version = False

def handle_starttag(self, tag, attrs):
"""Look for the right tag and store result in an attribute."""
if tag == "a":
for attr in attrs:
if attr[0] == "href" and "/downloads/release/python-" in attr[1]:
self.found_version = True
return

def handle_data(self, data):
"""Extract Python version from entry."""
if self.found_version:
self.found_version = False
match = re.search(r"Python (\d+\.\d+)", data)
if match:
self.versions.add(Version(match.group(1)))


def versions():
"""Get all Python release versions."""
req = urllib.request.Request("https://www.python.org/downloads/")
req.add_header("Accept-Encoding", "gzip")

with urllib.request.urlopen(req) as response:
raw = response.read()
if response.info().get("Content-Encoding") == "gzip":
raw = gzip.decompress(raw)
html = raw.decode("utf-8")

parser = PythonVersionParser()
parser.feed(html)

return parser.versions


def latest():
"""Return version of latest Python release."""
return max(versions())


def main():
"""Print all discovered release versions."""
print(" ".join(str(x) for x in sorted(versions())))


if __name__ == "__main__":
main()
37 changes: 0 additions & 37 deletions setup.cfg

This file was deleted.

8 changes: 0 additions & 8 deletions setup.py

This file was deleted.

Loading