precisionai-agrieval 0.1.0.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- precisionai_agrieval-0.1.0.dev0/.gitattributes +12 -0
- precisionai_agrieval-0.1.0.dev0/.gitignore +203 -0
- precisionai_agrieval-0.1.0.dev0/.pre-commit-config.yaml +46 -0
- precisionai_agrieval-0.1.0.dev0/CHANGELOG.md +18 -0
- precisionai_agrieval-0.1.0.dev0/CLAUDE.md +218 -0
- precisionai_agrieval-0.1.0.dev0/CODE_OF_CONDUCT.md +67 -0
- precisionai_agrieval-0.1.0.dev0/CONTRIBUTING.md +75 -0
- precisionai_agrieval-0.1.0.dev0/LICENSE.md +201 -0
- precisionai_agrieval-0.1.0.dev0/MANIFEST.in +11 -0
- precisionai_agrieval-0.1.0.dev0/PKG-INFO +441 -0
- precisionai_agrieval-0.1.0.dev0/README.md +184 -0
- precisionai_agrieval-0.1.0.dev0/SECURITY.md +63 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/__init__.py +2 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/__init__.py +2 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/api/__init__.py +2 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/api/app.py +103 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/api/config.py +31 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/__init__.py +28 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/api/__init__.py +2 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/api/app.py +114 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/api/config.py +8 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/api/routes/__init__.py +2 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/api/routes/evaluate.py +126 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/metrics/__init__.py +115 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/metrics/_utils.py +240 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/metrics/analysis.py +202 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/metrics/cross_model.py +235 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/metrics/duplicates.py +190 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/metrics/geometry.py +282 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/metrics/label_aware.py +805 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/metrics/neighbors.py +195 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/metrics/ranking.py +258 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/metrics/similarity.py +212 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/schemas/__init__.py +14 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/schemas/evaluate.py +471 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/services/__init__.py +2 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/services/evaluate.py +1117 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/emb/services/reporting.py +754 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/seg/__init__.py +9 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/seg/api/__init__.py +2 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/seg/api/config.py +8 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/seg/api/routes/__init__.py +2 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/seg/api/routes/evaluate.py +75 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/seg/cli.py +73 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/seg/metrics/__init__.py +22 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/seg/metrics/segmentation.py +165 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/seg/schemas/__init__.py +2 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/seg/schemas/evaluate.py +129 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/seg/services/__init__.py +2 -0
- precisionai_agrieval-0.1.0.dev0/precisionai/agrieval/seg/services/evaluate.py +573 -0
- precisionai_agrieval-0.1.0.dev0/precisionai_agrieval.egg-info/PKG-INFO +441 -0
- precisionai_agrieval-0.1.0.dev0/precisionai_agrieval.egg-info/SOURCES.txt +60 -0
- precisionai_agrieval-0.1.0.dev0/precisionai_agrieval.egg-info/dependency_links.txt +1 -0
- precisionai_agrieval-0.1.0.dev0/precisionai_agrieval.egg-info/entry_points.txt +4 -0
- precisionai_agrieval-0.1.0.dev0/precisionai_agrieval.egg-info/requires.txt +30 -0
- precisionai_agrieval-0.1.0.dev0/precisionai_agrieval.egg-info/scm_file_list.json +201 -0
- precisionai_agrieval-0.1.0.dev0/precisionai_agrieval.egg-info/scm_version.json +8 -0
- precisionai_agrieval-0.1.0.dev0/precisionai_agrieval.egg-info/top_level.txt +1 -0
- precisionai_agrieval-0.1.0.dev0/pyproject.toml +177 -0
- precisionai_agrieval-0.1.0.dev0/requirements-dev.txt +20 -0
- precisionai_agrieval-0.1.0.dev0/requirements.txt +6 -0
- precisionai_agrieval-0.1.0.dev0/setup.cfg +4 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Normalize line endings to LF on commit, regardless of editor/OS settings.
|
|
2
|
+
* text=auto eol=lf
|
|
3
|
+
|
|
4
|
+
# Treat binary files as binary (no line-ending conversion).
|
|
5
|
+
*.png binary
|
|
6
|
+
*.jpg binary
|
|
7
|
+
*.jpeg binary
|
|
8
|
+
*.JPG binary
|
|
9
|
+
*.JPEG binary
|
|
10
|
+
*.svg binary
|
|
11
|
+
*.pdf binary
|
|
12
|
+
*.ipynb text eol=lf
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Existing project-specific ignores
|
|
2
|
+
.venv/
|
|
3
|
+
exports/
|
|
4
|
+
lightning_logs/
|
|
5
|
+
.streamlit/users.json
|
|
6
|
+
.streamlit/secrets.toml
|
|
7
|
+
|
|
8
|
+
# Byte-compiled / optimized / DLL files
|
|
9
|
+
__pycache__/
|
|
10
|
+
*.py[cod]
|
|
11
|
+
*$py.class
|
|
12
|
+
|
|
13
|
+
# C extensions
|
|
14
|
+
*.so
|
|
15
|
+
|
|
16
|
+
# Distribution / packaging
|
|
17
|
+
.Python
|
|
18
|
+
build/
|
|
19
|
+
develop-eggs/
|
|
20
|
+
dist/
|
|
21
|
+
downloads/
|
|
22
|
+
eggs/
|
|
23
|
+
.eggs/
|
|
24
|
+
lib/
|
|
25
|
+
lib64/
|
|
26
|
+
parts/
|
|
27
|
+
sdist/
|
|
28
|
+
var/
|
|
29
|
+
wheels/
|
|
30
|
+
share/python-wheels/
|
|
31
|
+
*.egg-info/
|
|
32
|
+
.installed.cfg
|
|
33
|
+
*.egg
|
|
34
|
+
MANIFEST
|
|
35
|
+
|
|
36
|
+
# PyInstaller
|
|
37
|
+
*.manifest
|
|
38
|
+
*.spec
|
|
39
|
+
|
|
40
|
+
# Installer logs
|
|
41
|
+
pip-log.txt
|
|
42
|
+
pip-delete-this-directory.txt
|
|
43
|
+
|
|
44
|
+
# Unit test / coverage reports
|
|
45
|
+
htmlcov/
|
|
46
|
+
.tox/
|
|
47
|
+
.nox/
|
|
48
|
+
.coverage
|
|
49
|
+
.coverage.*
|
|
50
|
+
.cache
|
|
51
|
+
nosetests.xml
|
|
52
|
+
coverage.xml
|
|
53
|
+
*.cover
|
|
54
|
+
*.py,cover
|
|
55
|
+
.hypothesis/
|
|
56
|
+
.pytest_cache/
|
|
57
|
+
cover/
|
|
58
|
+
|
|
59
|
+
# Translations
|
|
60
|
+
*.mo
|
|
61
|
+
*.pot
|
|
62
|
+
temp/
|
|
63
|
+
|
|
64
|
+
# Django stuff:
|
|
65
|
+
*.log
|
|
66
|
+
local_settings.py
|
|
67
|
+
db.sqlite3
|
|
68
|
+
db.sqlite3-journal
|
|
69
|
+
|
|
70
|
+
# Flask stuff:
|
|
71
|
+
instance/
|
|
72
|
+
.webassets-cache
|
|
73
|
+
|
|
74
|
+
# Scrapy stuff:
|
|
75
|
+
.scrapy
|
|
76
|
+
|
|
77
|
+
# Sphinx documentation
|
|
78
|
+
docs/_build/
|
|
79
|
+
|
|
80
|
+
# PyBuilder
|
|
81
|
+
.pybuilder/
|
|
82
|
+
target/
|
|
83
|
+
|
|
84
|
+
# Jupyter Notebook
|
|
85
|
+
.ipynb_checkpoints
|
|
86
|
+
|
|
87
|
+
# IPython
|
|
88
|
+
profile_default/
|
|
89
|
+
ipython_config.py
|
|
90
|
+
|
|
91
|
+
# pyenv
|
|
92
|
+
.python-version
|
|
93
|
+
|
|
94
|
+
# pipenv
|
|
95
|
+
Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# poetry
|
|
98
|
+
poetry.lock
|
|
99
|
+
|
|
100
|
+
# pdm
|
|
101
|
+
.pdm.toml
|
|
102
|
+
|
|
103
|
+
# PEP 582
|
|
104
|
+
__pypackages__/
|
|
105
|
+
|
|
106
|
+
# Celery stuff
|
|
107
|
+
celerybeat-schedule
|
|
108
|
+
celerybeat.pid
|
|
109
|
+
|
|
110
|
+
# SageMath parsed files
|
|
111
|
+
*.sage.py
|
|
112
|
+
|
|
113
|
+
# Environments
|
|
114
|
+
.env
|
|
115
|
+
.venv
|
|
116
|
+
env/
|
|
117
|
+
venv/
|
|
118
|
+
ENV/
|
|
119
|
+
env.bak/
|
|
120
|
+
venv.bak/
|
|
121
|
+
|
|
122
|
+
# Spyder project settings
|
|
123
|
+
.spyderproject
|
|
124
|
+
.spyproject
|
|
125
|
+
|
|
126
|
+
# Rope project settings
|
|
127
|
+
.ropeproject
|
|
128
|
+
|
|
129
|
+
# mkdocs documentation
|
|
130
|
+
/site
|
|
131
|
+
|
|
132
|
+
# mypy
|
|
133
|
+
.mypy_cache/
|
|
134
|
+
.dmypy.json
|
|
135
|
+
dmypy.json
|
|
136
|
+
|
|
137
|
+
# Pyre type checker
|
|
138
|
+
.pyre/
|
|
139
|
+
|
|
140
|
+
# pytype static type analyzer
|
|
141
|
+
.pytype/
|
|
142
|
+
|
|
143
|
+
# Cython debug symbols
|
|
144
|
+
cython_debug/
|
|
145
|
+
|
|
146
|
+
# PyCharm
|
|
147
|
+
.idea/
|
|
148
|
+
|
|
149
|
+
# VS Code
|
|
150
|
+
.vscode/
|
|
151
|
+
|
|
152
|
+
# PyTorch / Machine Learning
|
|
153
|
+
*.pth
|
|
154
|
+
*.pt
|
|
155
|
+
*.ckpt
|
|
156
|
+
*.pkl
|
|
157
|
+
*.h5
|
|
158
|
+
*.hdf5
|
|
159
|
+
*.onnx
|
|
160
|
+
*.pb
|
|
161
|
+
*.tflite
|
|
162
|
+
*.tfl
|
|
163
|
+
*.pdf
|
|
164
|
+
checkpoints/
|
|
165
|
+
models/
|
|
166
|
+
weights/
|
|
167
|
+
wandb/
|
|
168
|
+
mlruns/
|
|
169
|
+
.neptune/
|
|
170
|
+
|
|
171
|
+
# OS files
|
|
172
|
+
.DS_Store
|
|
173
|
+
.DS_Store?
|
|
174
|
+
._*
|
|
175
|
+
.Spotlight-V100
|
|
176
|
+
.Trashes
|
|
177
|
+
ehthumbs.db
|
|
178
|
+
Thumbs.db
|
|
179
|
+
*~
|
|
180
|
+
|
|
181
|
+
# Temporary files
|
|
182
|
+
*.tmp
|
|
183
|
+
*.temp
|
|
184
|
+
*.swp
|
|
185
|
+
*.swo
|
|
186
|
+
*~
|
|
187
|
+
|
|
188
|
+
# Data files (uncomment if you don't want to track datasets)
|
|
189
|
+
# *.csv
|
|
190
|
+
# *.json
|
|
191
|
+
# *.parquet
|
|
192
|
+
# *.h5
|
|
193
|
+
# *.hdf5
|
|
194
|
+
# data/
|
|
195
|
+
dataset/
|
|
196
|
+
output/
|
|
197
|
+
|
|
198
|
+
# packaging artifacts
|
|
199
|
+
*.egg-info/
|
|
200
|
+
dist/
|
|
201
|
+
build/
|
|
202
|
+
|
|
203
|
+
dummy_input.json
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
# ── File hygiene ────────────────────────────────────────────────────────────
|
|
3
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
4
|
+
rev: v6.0.0
|
|
5
|
+
hooks:
|
|
6
|
+
- id: check-added-large-files
|
|
7
|
+
# Keep committed test/image fixtures small enough for fast clones and CI.
|
|
8
|
+
args: ["--maxkb=1800"]
|
|
9
|
+
- id: check-yaml
|
|
10
|
+
- id: check-json
|
|
11
|
+
- id: check-toml
|
|
12
|
+
- id: end-of-file-fixer
|
|
13
|
+
- id: trailing-whitespace
|
|
14
|
+
- id: check-merge-conflict
|
|
15
|
+
- id: detect-private-key
|
|
16
|
+
- id: debug-statements
|
|
17
|
+
- id: fix-byte-order-marker
|
|
18
|
+
|
|
19
|
+
# ── Ruff: lint + format + import sorting ───────────────────────────────────
|
|
20
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
21
|
+
rev: v0.15.17
|
|
22
|
+
hooks:
|
|
23
|
+
- id: ruff
|
|
24
|
+
args: ["--fix"]
|
|
25
|
+
- id: ruff-format
|
|
26
|
+
|
|
27
|
+
# ── Type checking (pyright / pylance engine) ────────────────────────────────
|
|
28
|
+
- repo: local
|
|
29
|
+
hooks:
|
|
30
|
+
- id: pyright
|
|
31
|
+
name: pyright
|
|
32
|
+
entry: python -m pyright
|
|
33
|
+
language: system
|
|
34
|
+
types: [python]
|
|
35
|
+
pass_filenames: false
|
|
36
|
+
|
|
37
|
+
# ── Tests + coverage (≥ 90%) ────────────────────────────────────────────────
|
|
38
|
+
- repo: local
|
|
39
|
+
hooks:
|
|
40
|
+
- id: pytest
|
|
41
|
+
name: pytest (coverage ≥ 90%)
|
|
42
|
+
entry: python -m pytest
|
|
43
|
+
language: system
|
|
44
|
+
args: ["tests/emb/", "tests/seg/", "-q", "--tb=short", "--no-header"]
|
|
45
|
+
pass_filenames: false
|
|
46
|
+
always_run: true
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - Initial public release
|
|
11
|
+
|
|
12
|
+
- `precisionai.agrieval.emb` — embedding evaluation: KNN retrieval benchmarking (nDCG, MAP, MRR, purity), geometry diagnostics, and interactive visualizations.
|
|
13
|
+
- `precisionai.agrieval.seg` — semantic segmentation evaluation: per-class IoU, Dice/F1, accuracy, mIoU, mAcc, FWIoU from colour-coded masks.
|
|
14
|
+
- Unified FastAPI server exposing both subpackages, plus a standalone segmentation CLI (`precisionai-agrieval-seg`).
|
|
15
|
+
- Top-level re-exports on both subpackages so the primary entry points can be imported directly, e.g. `from precisionai.agrieval.emb import run_image2image_eval` and `from precisionai.agrieval.seg import run_seg_eval`.
|
|
16
|
+
|
|
17
|
+
[Unreleased]: https://github.com/Precision-AI-Inc/agrieval/compare/v0.1.0...HEAD
|
|
18
|
+
[0.1.0]: https://github.com/Precision-AI-Inc/agrieval/releases/tag/v0.1.0
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Precision AI — Python Project Standards
|
|
2
|
+
|
|
3
|
+
Apply these standards when writing, reviewing, or refactoring code in any PAI Python project.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Environment
|
|
8
|
+
|
|
9
|
+
- Python 3.10+, managed with `python -m venv .venv` (never conda)
|
|
10
|
+
- Install: `pip install -e ".[dev]"` → installs all deps including pre-commit
|
|
11
|
+
- Register hooks once: `pre-commit install`
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Project layout
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
precisionai/<namespace>/<subpackage>/
|
|
19
|
+
api/
|
|
20
|
+
routes/ # FastAPI route handlers (thin — delegate to services)
|
|
21
|
+
config.py # env-var config only
|
|
22
|
+
app.py # FastAPI app factory
|
|
23
|
+
schemas/ # Pydantic v2 request/response models
|
|
24
|
+
services/ # Business logic (evaluate.py, reporting.py, …)
|
|
25
|
+
metrics/ # Pure computation modules
|
|
26
|
+
__init__.py # re-exports only — no logic
|
|
27
|
+
docs/ # Sphinx (HTML + LaTeX/PDF)
|
|
28
|
+
tests/<subpackage>/ # mirrors precisionai.<namespace>.<subpackage>, e.g. tests/emb/, tests/seg/
|
|
29
|
+
examples/<subpackage>/ # standalone runnable scripts, e.g. examples/emb/, examples/seg/
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## pyproject.toml — canonical config
|
|
35
|
+
|
|
36
|
+
```toml
|
|
37
|
+
[tool.ruff]
|
|
38
|
+
line-length = 120
|
|
39
|
+
target-version = "py310"
|
|
40
|
+
|
|
41
|
+
[tool.ruff.lint]
|
|
42
|
+
select = ["E","W","F","I","UP","B","SIM","N","C90","D","PT","RUF","PL","ANN","PERF","S"]
|
|
43
|
+
ignore = [
|
|
44
|
+
"E501", # enforced by ruff-format
|
|
45
|
+
"B008", # FastAPI default-arg pattern
|
|
46
|
+
"SIM108", # ternary readability
|
|
47
|
+
"D100","D104", # module/package docstrings optional
|
|
48
|
+
"D203","D213", # pydocstyle conflicts — always ignore these two
|
|
49
|
+
"PLR0913","PLR2004", # arg count + magic values common in metrics/tests
|
|
50
|
+
"ANN401", # Any is allowed for genuinely dynamic types
|
|
51
|
+
"S311", # pseudo-random generators are intentional in scientific code
|
|
52
|
+
"S104", # binding to 0.0.0.0 is intentional for a configurable server host
|
|
53
|
+
]
|
|
54
|
+
[tool.ruff.lint.per-file-ignores]
|
|
55
|
+
"**/__init__.py" = ["F401"]
|
|
56
|
+
"tests/<subpackage>/**" = ["D","PLR","ANN","S"] # e.g. tests/emb/**, tests/seg/**
|
|
57
|
+
"docs/conf.py" = ["E402","UP031","ANN","S"]
|
|
58
|
+
|
|
59
|
+
[tool.ruff.lint.pydocstyle]
|
|
60
|
+
convention = "numpy" # enforces NumPy docstring style
|
|
61
|
+
|
|
62
|
+
[tool.ruff.lint.mccabe]
|
|
63
|
+
max-complexity = 10
|
|
64
|
+
|
|
65
|
+
[tool.ruff.lint.isort]
|
|
66
|
+
known-first-party = ["precisionai"] # adjust namespace per project
|
|
67
|
+
|
|
68
|
+
[tool.ruff.format]
|
|
69
|
+
quote-style = "double"
|
|
70
|
+
indent-style = "space"
|
|
71
|
+
docstring-code-format = true # formats code blocks inside docstrings
|
|
72
|
+
|
|
73
|
+
[tool.pytest.ini_options]
|
|
74
|
+
addopts = "--cov=precisionai --cov-report=term-missing --cov-fail-under=90"
|
|
75
|
+
|
|
76
|
+
[tool.coverage.report]
|
|
77
|
+
fail_under = 90
|
|
78
|
+
exclude_lines = ["pragma: no cover","if __name__ == .__main__.:",
|
|
79
|
+
"raise ImportError","except ImportError"]
|
|
80
|
+
|
|
81
|
+
[tool.pyright]
|
|
82
|
+
pythonVersion = "3.10"
|
|
83
|
+
typeCheckingMode = "standard"
|
|
84
|
+
reportMissingImports = false
|
|
85
|
+
reportMissingModuleSource = false
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## pre-commit
|
|
91
|
+
|
|
92
|
+
```yaml
|
|
93
|
+
repos:
|
|
94
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
95
|
+
rev: v6.0.0
|
|
96
|
+
hooks: [check-added-large-files (--maxkb=1800), check-yaml, check-json,
|
|
97
|
+
check-toml, end-of-file-fixer, trailing-whitespace,
|
|
98
|
+
check-merge-conflict, detect-private-key, debug-statements,
|
|
99
|
+
fix-byte-order-marker]
|
|
100
|
+
|
|
101
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
102
|
+
rev: v0.15.17
|
|
103
|
+
hooks: [ruff (--fix), ruff-format]
|
|
104
|
+
|
|
105
|
+
- repo: local
|
|
106
|
+
hooks:
|
|
107
|
+
- id: pyright
|
|
108
|
+
name: pyright
|
|
109
|
+
entry: python -m pyright
|
|
110
|
+
language: system
|
|
111
|
+
types: [python]
|
|
112
|
+
pass_filenames: false
|
|
113
|
+
|
|
114
|
+
- repo: local
|
|
115
|
+
hooks:
|
|
116
|
+
- id: pytest
|
|
117
|
+
entry: python -m pytest
|
|
118
|
+
language: system
|
|
119
|
+
args: [tests/emb/, tests/seg/, -q, --tb=short, --no-header]
|
|
120
|
+
always_run: true
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Code style
|
|
126
|
+
|
|
127
|
+
### Imports
|
|
128
|
+
- All imports at the **top of the file** — never inside functions
|
|
129
|
+
- Optional/unavailable deps: module-level `try/except ImportError` with a flag variable
|
|
130
|
+
- No silent fallbacks unless mathematically equivalent (document why)
|
|
131
|
+
- `__init__.py` re-exports only — no logic, no comments between import blocks
|
|
132
|
+
- `__all__` must be **alphabetically sorted**
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
# optional dep pattern
|
|
136
|
+
try:
|
|
137
|
+
import plotly.graph_objects as go # type: ignore[import]
|
|
138
|
+
_PLOTLY_AVAILABLE = True
|
|
139
|
+
except ImportError:
|
|
140
|
+
_PLOTLY_AVAILABLE = False
|
|
141
|
+
|
|
142
|
+
# inside function that needs it
|
|
143
|
+
if not _PLOTLY_AVAILABLE:
|
|
144
|
+
raise ImportError("plotly is required: pip install plotly") from None
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Docstrings
|
|
148
|
+
- **NumPy style** on all public functions, classes, and modules
|
|
149
|
+
- Module docstrings: plain English, no prefixes (no P0/P1/P2, no "original", no labels)
|
|
150
|
+
- One-line summary in **imperative mood** ("Compute …", "Return …", "Save …")
|
|
151
|
+
- Blank line between summary and extended description (D205)
|
|
152
|
+
|
|
153
|
+
### Type hints
|
|
154
|
+
- Required on **all** function signatures (public and private) — enforced by ruff (`ANN`) and pyright
|
|
155
|
+
- Use `X | Y` union syntax (Python 3.10+), not `Union[X, Y]` or `(X, Y)` in isinstance
|
|
156
|
+
- Use `Any` from `typing` for genuinely dynamic types — don't use `object` when methods will be called on it
|
|
157
|
+
- pyright config lives in `[tool.pyright]` in `pyproject.toml` — never pass type-checker flags inline
|
|
158
|
+
|
|
159
|
+
### Comments
|
|
160
|
+
- Only when the **why** is non-obvious
|
|
161
|
+
- No section-divider comments that describe what the code already says
|
|
162
|
+
- No cryptic labels, no TODO/FIXME without a ticket reference
|
|
163
|
+
|
|
164
|
+
### Exception handling
|
|
165
|
+
- Always `raise X from err` or `raise X from None` inside `except` blocks (B904)
|
|
166
|
+
|
|
167
|
+
### General
|
|
168
|
+
- `len()` returns `int` — never `int(len(...))`
|
|
169
|
+
- Loop variables not used in the body → rename to `_`
|
|
170
|
+
- `assert a and b` in tests → split into separate asserts
|
|
171
|
+
- `@pytest.fixture` not `@pytest.fixture()`
|
|
172
|
+
- `pytest.raises` always includes `match=` parameter
|
|
173
|
+
- No `# type: ignore[attr-defined]` when `Any` already covers the attribute
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Docs (Sphinx)
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
docs/
|
|
181
|
+
conf.py # version from git tag, logo, LaTeX/fancyhdr, enumitem fix
|
|
182
|
+
index.rst # toctree: readme, modules
|
|
183
|
+
modules.rst # autodoc for all public submodules
|
|
184
|
+
requirements.txt # sphinx, sphinx-rtd-theme, myst-parser, sphinx-autodoc-typehints
|
|
185
|
+
Makefile # make html | make latexpdf | make clean
|
|
186
|
+
assets/logo.png
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
- `conf.py` copies root `README.md` → `docs/readme.md` at build time
|
|
190
|
+
- Version read from `git describe --tags --exact-match`, falls back to `0.0.0`
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Testing
|
|
195
|
+
|
|
196
|
+
- Mirror package structure: `tests/<subpackage>/test_<module>.py` (e.g. `tests/emb/`, `tests/seg/`)
|
|
197
|
+
- Shared fixtures in each subpackage's `tests/<subpackage>/conftest.py`
|
|
198
|
+
- 90% coverage hard minimum — enforced by pytest and pre-commit
|
|
199
|
+
- No mocks for database/filesystem unless truly unavoidable
|
|
200
|
+
- Integration tests marked `@pytest.mark.integration` and excluded from default runs
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## What to avoid
|
|
205
|
+
|
|
206
|
+
| Pattern | Instead |
|
|
207
|
+
|---|---|
|
|
208
|
+
| `int(len(x))` | `len(x)` |
|
|
209
|
+
| `isinstance(x, (A, B))` | `isinstance(x, A \| B)` |
|
|
210
|
+
| `assert a and b` (tests) | two separate asserts |
|
|
211
|
+
| `@pytest.fixture()` | `@pytest.fixture` |
|
|
212
|
+
| `pytest.raises(ValueError)` | `pytest.raises(ValueError, match="…")` |
|
|
213
|
+
| `raise X` inside except | `raise X from None` or `raise X from err` |
|
|
214
|
+
| Deferred imports inside functions | Module-level try/except with flag |
|
|
215
|
+
| Cryptic prefixes (P0–P4, "original") | Plain descriptive names |
|
|
216
|
+
| `# type: ignore[attr-defined]` on `Any` | Remove — redundant |
|
|
217
|
+
| `# noqa` suppression | Fix the underlying issue |
|
|
218
|
+
| Silent fallback for optional dep | Raise `ImportError` with install hint |
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our
|
|
6
|
+
community a harassment-free experience for everyone, regardless of age, body
|
|
7
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
8
|
+
identity and expression, level of experience, education, socio-economic status,
|
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
|
10
|
+
orientation.
|
|
11
|
+
|
|
12
|
+
We pledge to act and interact in ways that contribute to an open, welcoming,
|
|
13
|
+
diverse, inclusive, and healthy community.
|
|
14
|
+
|
|
15
|
+
## Our Standards
|
|
16
|
+
|
|
17
|
+
Examples of behavior that contributes to a positive environment:
|
|
18
|
+
|
|
19
|
+
- Demonstrating empathy and kindness toward other people
|
|
20
|
+
- Being respectful of differing opinions, viewpoints, and experiences
|
|
21
|
+
- Giving and gracefully accepting constructive feedback
|
|
22
|
+
- Accepting responsibility and apologizing to those affected by our mistakes,
|
|
23
|
+
and learning from the experience
|
|
24
|
+
- Focusing on what is best not just for us as individuals, but for the overall
|
|
25
|
+
community
|
|
26
|
+
|
|
27
|
+
Examples of unacceptable behavior:
|
|
28
|
+
|
|
29
|
+
- The use of sexualized language or imagery, and sexual attention or advances
|
|
30
|
+
of any kind
|
|
31
|
+
- Trolling, insulting or derogatory comments, and personal or political attacks
|
|
32
|
+
- Public or private harassment
|
|
33
|
+
- Publishing others' private information, such as a physical or email address,
|
|
34
|
+
without their explicit permission
|
|
35
|
+
- Other conduct which could reasonably be considered inappropriate in a
|
|
36
|
+
professional setting
|
|
37
|
+
|
|
38
|
+
## Enforcement Responsibilities
|
|
39
|
+
|
|
40
|
+
Community leaders are responsible for clarifying and enforcing our standards of
|
|
41
|
+
acceptable behavior and will take appropriate and fair corrective action in
|
|
42
|
+
response to any behavior that they deem inappropriate, threatening, offensive,
|
|
43
|
+
or harmful.
|
|
44
|
+
|
|
45
|
+
## Scope
|
|
46
|
+
|
|
47
|
+
This Code of Conduct applies within all community spaces, and also applies when
|
|
48
|
+
an individual is officially representing the community in public spaces.
|
|
49
|
+
|
|
50
|
+
## Enforcement
|
|
51
|
+
|
|
52
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
53
|
+
reported to the community leaders responsible for enforcement at
|
|
54
|
+
**michael@precision.ai**. All complaints will be reviewed and investigated
|
|
55
|
+
promptly and fairly.
|
|
56
|
+
|
|
57
|
+
All community leaders are obligated to respect the privacy and security of the
|
|
58
|
+
reporter of any incident.
|
|
59
|
+
|
|
60
|
+
## Attribution
|
|
61
|
+
|
|
62
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
63
|
+
version 2.1, available at
|
|
64
|
+
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
|
65
|
+
|
|
66
|
+
[homepage]: https://www.contributor-covenant.org
|
|
67
|
+
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing to Precision AI AgriEval.
|
|
4
|
+
|
|
5
|
+
By participating in this project, you agree to abide by the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
Requires Python 3.10+.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
git clone https://github.com/Precision-AI-Inc/agrieval.git
|
|
13
|
+
cd agrieval
|
|
14
|
+
|
|
15
|
+
python -m venv .venv
|
|
16
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
17
|
+
|
|
18
|
+
pip install -e ".[dev]"
|
|
19
|
+
pre-commit install
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`pip install -e ".[dev]"` installs all dependencies including test, analysis, and pre-commit tooling. `pre-commit install` registers the hooks so they run automatically on every commit.
|
|
23
|
+
|
|
24
|
+
## Making changes
|
|
25
|
+
|
|
26
|
+
1. Create a branch from `main`.
|
|
27
|
+
2. Make your changes.
|
|
28
|
+
3. Add or update tests — coverage must remain at or above 90%.
|
|
29
|
+
4. Commit. Pre-commit hooks run automatically and will block the commit if any check fails.
|
|
30
|
+
|
|
31
|
+
If a hook auto-fixes files (ruff lint/format), stage the changes and commit again.
|
|
32
|
+
|
|
33
|
+
## Pre-commit hooks
|
|
34
|
+
|
|
35
|
+
| Hook | What it checks |
|
|
36
|
+
|---|---|
|
|
37
|
+
| File hygiene | Large files (>1800 KB), trailing whitespace, merge conflicts, private keys, debug statements, BOM removal |
|
|
38
|
+
| `ruff` | Linting and import sorting (auto-fix); includes `ANN` rules that enforce PEP 484 annotations |
|
|
39
|
+
| `ruff-format` | Code formatting (auto-fix) |
|
|
40
|
+
| `pyright` | Static type checking (pylance engine) — config in `[tool.pyright]` in `pyproject.toml` |
|
|
41
|
+
| `pytest` | Full test suite with ≥ 90% coverage |
|
|
42
|
+
|
|
43
|
+
To run all hooks manually without committing:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pre-commit run --all-files
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Code style
|
|
50
|
+
|
|
51
|
+
- **Formatter / linter:** ruff (`line-length = 120`, Python 3.10 target).
|
|
52
|
+
- **Type hints:** all functions (public and private) must have complete PEP 484 type annotations. Enforced at lint time by ruff (`ANN` rules) and statically by pyright. `Any` is allowed for genuinely dynamic types; explicit `Any` is preferred over `object` when methods will be called on a value.
|
|
53
|
+
- **Docstrings:** NumPy style for all public functions, classes, and modules.
|
|
54
|
+
- **Comments:** only where the _why_ is non-obvious. No inline narration of what the code does.
|
|
55
|
+
|
|
56
|
+
## Tests
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pytest # run all tests with coverage report
|
|
60
|
+
pytest tests/emb/test_metrics.py # run a specific file
|
|
61
|
+
pytest tests/seg/ # run a single subpackage
|
|
62
|
+
pytest -k "test_purity" # run tests matching a pattern
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Tests live in `tests/` and mirror the package structure. The coverage threshold (90%) is enforced both by `pytest` directly and by the pre-commit hook.
|
|
66
|
+
|
|
67
|
+
## Pull requests
|
|
68
|
+
|
|
69
|
+
- Keep PRs focused — one logical change per PR.
|
|
70
|
+
- Write a clear description of what changed and why.
|
|
71
|
+
- All pre-commit hooks must pass before requesting review.
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
By contributing, you agree that your contributions are licensed under the Apache License, Version 2.0.
|