-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathpyproject.toml
More file actions
255 lines (235 loc) · 9.55 KB
/
Copy pathpyproject.toml
File metadata and controls
255 lines (235 loc) · 9.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
[build-system]
requires = ["hatchling>=1.27"]
build-backend = "hatchling.build"
[project]
name = "python-som"
version = "0.8.0"
authors = [{ name = "André Moreira Souza", email = "msouza.andre@hotmail.com" }]
description = "Python implementation of the Self-Organizing Map"
readme = "README.md"
requires-python = ">=3.10"
license = "MIT"
license-files = ["LICEN[CS]E*"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Intended Audience :: Science/Research",
"Topic :: Software Development :: Libraries",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Operating System :: OS Independent",
"Typing :: Typed",
]
# NumPy is the only runtime dependency. pandas and scikit-learn were dropped in 0.4.0, taking the
# install from 333 MB across 10 packages to 69 MB across 1. Both stay in `dev`, where differential
# tests re-check the replacements against them.
dependencies = [
"numpy>=1.24",
]
[project.optional-dependencies]
cli = ["tqdm>=4.66"]
dev = [
"hypothesis==6.163.0",
# Test-only. tests/test_minisom_agreement.py checks this package's equations against MiniSom's.
# MIT, a single file, and it declares no dependencies of its own.
"minisom==2.3.6",
"mypy==2.3.0",
# Test-only: the DataFrame path through the port, and the differential PCA test. Pinned because
# scikit-learn changed its default PCA solver in 1.5, and a floating pin would surface that as
# an unrelated PR's CI failure. Split by Python version, since the current majors dropped 3.10.
"pandas==3.0.5; python_version >= '3.11'",
"pandas==2.3.3; python_version < '3.11'",
"scikit-learn==1.9.0; python_version >= '3.11'",
"scikit-learn==1.7.2; python_version < '3.11'",
# pandas-stubs 3.x needs Python >=3.11; gated rather than raising the library's floor.
"pandas-stubs==3.0.3.260530; python_version >= '3.11'",
"pre-commit==4.6.1",
"pytest==9.1.1",
"pytest-cov==7.1.0",
"ruff==0.16.0",
# tomllib entered the stdlib in 3.11; tomli is the backport it was derived from.
"tomli==2.4.1; python_version < '3.11'",
"twine==7.0.0",
"types-tqdm==4.69.0.20260728",
]
docs = [
"mkdocs-material==9.7.7",
# SUPPLY CHAIN: pinned to 1.2.2, not the newer 1.2.3. Upstream (github.com/mkdocs/mkdocs-
# redirects) has no v1.2.3 tag; PyPI's 1.2.3 declares its source as a different repository
# created two weeks before it was published. 1.2.2 is the last release whose provenance checks
# out. Do not bump without re-checking who publishes it.
"mkdocs-redirects==1.2.3",
"mkdocstrings-python==2.0.5",
]
# Review tools, kept out of `dev` so CI jobs that never run them do not install them. Nothing here
# gates a merge; ruff and mypy are the enforced checks.
#
# SUPPLY CHAIN, three tools deliberately absent:
# osv-scanner the PyPI package of that name is a placeholder with no functionality; the real
# tool is a Go binary from Google.
# guarddog genuine (DataDog) but first released three months after this project, so it fails
# the rule that a dependency should predate what it is added to.
# semgrep pins mcp==1.23.3 exactly, which carries PYSEC-2026-3481/3482/3483 and so cannot be
# remediated from here. Revisit if it relaxes the pin.
# Benchmarking, kept out of `dev`: asv pulls about ten transitive packages and no gating job runs
# it. minisom is repeated so `--extra bench` alone runs every script in benchmarks/.
#
# SOMPY cannot be added: it uses `np.Inf`, removed in NumPy 2.0, at class-definition time.
# benchmarks/bench_vs_sompy.py drives it through a separate interpreter built by hand.
bench = [
# What numpy, scipy, pandas and scikit-learn all use to track their own performance.
"asv==0.6.6",
"minisom==2.3.6",
]
analysis = [
# PyCQA, first released 2015. Security-oriented AST checks.
"bandit==1.9.4",
# PyPA. Reports known CVEs in the resolved dependency set; expected to report none.
"pip-audit==2.10.1",
# PyCQA, first released 2009. Not wired into any gate; here so the findings a contributor's IDE
# reports can be reproduced from the command line.
"pylint==4.0.6",
]
# scikit-learn integration. Only python_som.sklearn imports it. Lower bounds rather than pins:
# these are user-facing install sets, not tooling. `examples` restores what 0.3.0 installed.
sklearn = [
"scikit-learn>=1.4",
]
examples = [
"matplotlib>=3.8",
"pandas>=2.0",
"scikit-learn>=1.3",
"seaborn>=0.13",
]
[project.urls]
Homepage = "https://github.com/andremsouza/python-som"
Documentation = "https://andremsouza.github.io/python-som/"
Changelog = "https://github.com/andremsouza/python-som/blob/master/CHANGELOG.md"
Issues = "https://github.com/andremsouza/python-som/issues"
[tool.hatch.build.targets.wheel]
packages = ["src/python_som"]
[tool.hatch.build.targets.sdist]
include = [
"/src",
"/tests",
"/docs",
"/examples",
"/README.md",
"/CHANGELOG.md",
"/LICENSE",
]
[tool.ruff]
line-length = 100
target-version = "py310"
src = ["src", "tests"]
[tool.ruff.lint]
select = ["ALL"]
ignore = [
# The 13-argument constructor is the established public API. Reducing it, or forcing the
# arguments keyword-only, would break every existing caller for no gain in correctness.
"PLR0913",
"PLR0917",
# `verbose`, `normalize` and `cyclic_*` are long-standing boolean parameters of the public
# API. Making them keyword-only would break positional callers.
"FBT001",
"FBT002",
# Conflicts with the formatter.
"COM812",
"ISC001",
# This project documents parameters with `:param:` rather than a Google/NumPy section.
"D417",
# Per-file copyright headers are not this project's convention; the MIT terms live in
# LICENSE and are declared in the package metadata.
"CPY001",
]
[tool.ruff.lint.per-file-ignores]
# The ban protects the core, not the suite that checks it, nor the adapter that exists to import
# scikit-learn.
"src/python_som/sklearn.py" = ["TID251"]
"tests/test_sklearn_adapter.py" = ["TID251"]
"tests/*" = [
"TID251",
# Tests reach into private helpers deliberately; that is what is under test.
"SLF001",
# assert is the point of a test.
"S101",
# Tests do not need to document every parameter.
"D103",
"D100",
# Magic values are the expected values being asserted.
"PLR2004",
]
"examples/*" = ["INP001", "T201", "D100"]
# Scripts a human runs: a table on stdout is the deliverable, and they are not importable modules.
"benchmarks/*" = ["INP001", "T201"]
[tool.ruff.lint.flake8-tidy-imports.banned-api]
# The package is numpy-only at runtime. No module under src/ is exempt; only tests are, so the
# replacements can be compared against the originals.
"pandas".msg = "The core is numpy-only. Convert at the boundary in python_som/_convert.py."
"sklearn".msg = "The core is numpy-only. Linear algebra belongs in python_som/_core/_linalg.py."
[tool.ruff.lint.pydocstyle]
convention = "pep257"
[tool.ruff.lint.isort]
known-first-party = ["python_som"]
[tool.mypy]
# Not pinned to 3.10: NumPy's stubs use 3.12 syntax, so pinning to the floor makes mypy fail on the
# dependencies rather than on our code. Real 3.10 support is covered by the CI matrix.
strict = true
files = ["src", "tests"]
warn_unreachable = true
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
[[tool.mypy.overrides]]
module = ["sklearn.*", "numba.*"]
ignore_missing_imports = true
# scikit-learn ships no py.typed, so --strict refuses to subclass BaseEstimator. Relaxed for the
# adapter alone; a blanket type: ignore would hide any other mistake in the same file.
[[tool.mypy.overrides]]
module = ["python_som.sklearn"]
disallow_subclassing_any = false
# numba ships no py.typed, so --strict rejects the jit decorator and `prange` as untyped. Relaxed
# for the accelerator alone; its contract is the BmuKernel protocol, checked by a differential test.
# These only fire when numba is installed, which is the accelerated-path CI job.
[[tool.mypy.overrides]]
module = ["python_som._accelerate"]
disallow_untyped_decorators = false
disallow_untyped_calls = false
disable_error_code = ["attr-defined"]
[tool.pytest.ini_options]
minversion = "8.0"
testpaths = ["tests"]
addopts = [
"--strict-markers",
"--strict-config",
"-ra",
]
markers = [
"slow: end-to-end runs; deselect with -m 'not slow'",
]
filterwarnings = ["error"]
[tool.coverage.run]
# source_pkgs, not source: with a src layout the package under test is the installed one.
source_pkgs = ["python_som"]
branch = true
[tool.coverage.paths]
source = ["src/python_som", "*/site-packages/python_som"]
[tool.coverage.report]
# Anything genuinely unreachable carries an explicit `# pragma: no cover` a reviewer can question.
fail_under = 100
show_missing = true
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:",
"raise NotImplementedError",
# A bare `...` is a Protocol method body, never executed. Matches only a line whose entire
# content is an ellipsis, which occurs solely in _core/_protocols.py.
"^\\s*\\.\\.\\.$",
]
[tool.bandit]
# B101 fires on every test assert. Excluded by directory rather than skipped, so it still applies
# to `src/`, where an assert would be wrong: they vanish under `python -O`.
exclude_dirs = ["tests", ".venv", "site", "dist"]