enumplus 1.0.0__tar.gz → 1.2.0__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.
- {enumplus-1.0.0 → enumplus-1.2.0}/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- enumplus-1.2.0/.github/workflows/ci.yml +62 -0
- enumplus-1.2.0/.github/workflows/release.yml +176 -0
- {enumplus-1.0.0 → enumplus-1.2.0}/.gitignore +3 -0
- enumplus-1.2.0/AGENTS.md +73 -0
- enumplus-1.2.0/CHANGELOG.md +76 -0
- {enumplus-1.0.0 → enumplus-1.2.0}/CONTRIBUTING.md +16 -3
- enumplus-1.2.0/PKG-INFO +478 -0
- enumplus-1.0.0/PKG-INFO → enumplus-1.2.0/README.md +172 -27
- {enumplus-1.0.0 → enumplus-1.2.0}/SECURITY.md +2 -1
- enumplus-1.2.0/enumplus/__init__.py +12 -0
- enumplus-1.2.0/enumplus/enum.py +507 -0
- enumplus-1.2.0/enumplus/pydantic.py +56 -0
- enumplus-1.2.0/enumplus/serialize.py +86 -0
- enumplus-1.2.0/pyproject.toml +55 -0
- enumplus-1.2.0/tests/__init__.py +0 -0
- {enumplus-1.0.0 → enumplus-1.2.0}/tests/test_compatibility.py +22 -0
- enumplus-1.2.0/tests/test_edge_cases.py +581 -0
- {enumplus-1.0.0 → enumplus-1.2.0}/tests/test_enum.py +67 -1
- enumplus-1.2.0/tests/test_new_features.py +357 -0
- {enumplus-1.0.0 → enumplus-1.2.0}/tests/test_ordered.py +1 -1
- {enumplus-1.0.0 → enumplus-1.2.0}/tests/test_public_api.py +1 -1
- enumplus-1.2.0/tests/test_pydantic.py +79 -0
- {enumplus-1.0.0 → enumplus-1.2.0}/tests/test_serialize.py +16 -0
- enumplus-1.0.0/.github/workflows/ci.yml +0 -36
- enumplus-1.0.0/.github/workflows/release.yml +0 -124
- enumplus-1.0.0/README.md +0 -283
- enumplus-1.0.0/enumplus/__init__.py +0 -6
- enumplus-1.0.0/enumplus/enum.py +0 -206
- enumplus-1.0.0/enumplus/pydantic.py +0 -29
- enumplus-1.0.0/enumplus/serialize.py +0 -38
- enumplus-1.0.0/pyproject.toml +0 -32
- enumplus-1.0.0/tests/test_pydantic.py +0 -43
- {enumplus-1.0.0 → enumplus-1.2.0}/.github/FUNDING.yml +0 -0
- {enumplus-1.0.0 → enumplus-1.2.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {enumplus-1.0.0 → enumplus-1.2.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {enumplus-1.0.0 → enumplus-1.2.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {enumplus-1.0.0 → enumplus-1.2.0}/CODE_OF_CONDUCT.md +0 -0
- {enumplus-1.0.0 → enumplus-1.2.0}/LICENSE +0 -0
- {enumplus-1.0.0 → enumplus-1.2.0}/SUPPORT.md +0 -0
- /enumplus-1.0.0/tests/__init__.py → /enumplus-1.2.0/enumplus/py.typed +0 -0
- {enumplus-1.0.0 → enumplus-1.2.0}/tests/test_metadata_unpacking.py +0 -0
- {enumplus-1.0.0 → enumplus-1.2.0}/tests/test_type_hints.py +0 -0
|
@@ -31,7 +31,7 @@ A clear and concise description of what actually happened.
|
|
|
31
31
|
## Environment
|
|
32
32
|
|
|
33
33
|
- Python version: [e.g. 3.12.1]
|
|
34
|
-
- enumplus version: [e.g.
|
|
34
|
+
- enumplus version: [e.g. 1.1.0]
|
|
35
35
|
- OS: [e.g. Ubuntu 22.04, Windows 11, macOS 14]
|
|
36
36
|
|
|
37
37
|
## Additional context
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main", "master"]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: ["main", "master"]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ci-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
test:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
25
|
+
uses: actions/setup-python@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: ${{ matrix.python-version }}
|
|
28
|
+
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: |
|
|
31
|
+
python -m pip install --upgrade pip
|
|
32
|
+
pip install -e ".[dev]"
|
|
33
|
+
|
|
34
|
+
- name: Lint with ruff
|
|
35
|
+
run: ruff check enumplus/ tests/
|
|
36
|
+
|
|
37
|
+
- name: Type check with mypy
|
|
38
|
+
run: mypy --strict enumplus/ tests/
|
|
39
|
+
|
|
40
|
+
- name: Run tests
|
|
41
|
+
run: pytest --tb=short
|
|
42
|
+
|
|
43
|
+
build:
|
|
44
|
+
needs: test
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
|
|
49
|
+
- name: Set up Python
|
|
50
|
+
uses: actions/setup-python@v5
|
|
51
|
+
with:
|
|
52
|
+
python-version: "3.12"
|
|
53
|
+
|
|
54
|
+
- name: Build package
|
|
55
|
+
run: |
|
|
56
|
+
python -m pip install --upgrade pip build
|
|
57
|
+
python -m build
|
|
58
|
+
|
|
59
|
+
- name: Verify wheel contents
|
|
60
|
+
run: |
|
|
61
|
+
python -m zipfile -l dist/*.whl
|
|
62
|
+
python -c "import zipfile, sys; z=zipfile.ZipFile([f for f in __import__('glob').glob('dist/*.whl')][0]); assert 'enumplus/py.typed' in z.namelist(), 'py.typed missing from wheel'"
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: release-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: false
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
test:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
uses: actions/setup-python@v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: "3.12"
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: |
|
|
29
|
+
python -m pip install --upgrade pip
|
|
30
|
+
pip install -e ".[dev]"
|
|
31
|
+
|
|
32
|
+
- name: Lint with ruff
|
|
33
|
+
run: ruff check enumplus/ tests/
|
|
34
|
+
|
|
35
|
+
- name: Type check with mypy
|
|
36
|
+
run: mypy --strict enumplus/ tests/
|
|
37
|
+
|
|
38
|
+
- name: Run tests
|
|
39
|
+
run: pytest --tb=short
|
|
40
|
+
|
|
41
|
+
build:
|
|
42
|
+
needs: test
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/checkout@v4
|
|
46
|
+
|
|
47
|
+
- name: Set up Python
|
|
48
|
+
uses: actions/setup-python@v5
|
|
49
|
+
with:
|
|
50
|
+
python-version: "3.12"
|
|
51
|
+
|
|
52
|
+
- name: Install build dependencies
|
|
53
|
+
run: |
|
|
54
|
+
python -m pip install --upgrade pip
|
|
55
|
+
pip install build
|
|
56
|
+
|
|
57
|
+
- name: Build package
|
|
58
|
+
run: python -m build
|
|
59
|
+
|
|
60
|
+
- name: Upload artifacts
|
|
61
|
+
uses: actions/upload-artifact@v4
|
|
62
|
+
with:
|
|
63
|
+
name: dist
|
|
64
|
+
path: dist/
|
|
65
|
+
|
|
66
|
+
github-release:
|
|
67
|
+
needs: build
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
permissions:
|
|
70
|
+
contents: write
|
|
71
|
+
steps:
|
|
72
|
+
- uses: actions/checkout@v4
|
|
73
|
+
with:
|
|
74
|
+
fetch-depth: 0
|
|
75
|
+
|
|
76
|
+
- name: Download artifacts
|
|
77
|
+
uses: actions/download-artifact@v4
|
|
78
|
+
with:
|
|
79
|
+
name: dist
|
|
80
|
+
path: dist/
|
|
81
|
+
|
|
82
|
+
- name: Generate changelog
|
|
83
|
+
id: changelog
|
|
84
|
+
run: |
|
|
85
|
+
PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
|
|
86
|
+
if [ -z "$PREVIOUS_TAG" ]; then
|
|
87
|
+
RANGE=""
|
|
88
|
+
else
|
|
89
|
+
RANGE="${PREVIOUS_TAG}..HEAD"
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# Group commits by conventional commit type
|
|
93
|
+
FEATURES=$(git log --pretty=format:"- %s" ${RANGE} --grep="^feat" --grep="^add" --grep="^support" -i | grep -v "release:" || true)
|
|
94
|
+
FIXES=$(git log --pretty=format:"- %s" ${RANGE} --grep="^fix" --grep="^patch" -i || true)
|
|
95
|
+
REFACTOR=$(git log --pretty=format:"- %s" ${RANGE} --grep="^refactor" --grep="^clean" -i || true)
|
|
96
|
+
DOCS=$(git log --pretty=format:"- %s" ${RANGE} --grep="^docs" --grep="^readme" -i || true)
|
|
97
|
+
TESTS=$(git log --pretty=format:"- %s" ${RANGE} --grep="^test" -i || true)
|
|
98
|
+
CHORE=$(git log --pretty=format:"- %s" ${RANGE} --grep="^chore" --grep="^ci" --grep="^build" -i || true)
|
|
99
|
+
RELEASE=$(git log --pretty=format:"- %s" ${RANGE} --grep="^release" -i || true)
|
|
100
|
+
|
|
101
|
+
{
|
|
102
|
+
echo "body<<EOF"
|
|
103
|
+
if [ -n "$FEATURES" ]; then
|
|
104
|
+
echo "### Features"
|
|
105
|
+
echo ""
|
|
106
|
+
echo "$FEATURES"
|
|
107
|
+
echo ""
|
|
108
|
+
fi
|
|
109
|
+
if [ -n "$FIXES" ]; then
|
|
110
|
+
echo "### Bug Fixes"
|
|
111
|
+
echo ""
|
|
112
|
+
echo "$FIXES"
|
|
113
|
+
echo ""
|
|
114
|
+
fi
|
|
115
|
+
if [ -n "$REFACTOR" ]; then
|
|
116
|
+
echo "### Refactoring"
|
|
117
|
+
echo ""
|
|
118
|
+
echo "$REFACTOR"
|
|
119
|
+
echo ""
|
|
120
|
+
fi
|
|
121
|
+
if [ -n "$DOCS" ]; then
|
|
122
|
+
echo "### Documentation"
|
|
123
|
+
echo ""
|
|
124
|
+
echo "$DOCS"
|
|
125
|
+
echo ""
|
|
126
|
+
fi
|
|
127
|
+
if [ -n "$TESTS" ]; then
|
|
128
|
+
echo "### Tests"
|
|
129
|
+
echo ""
|
|
130
|
+
echo "$TESTS"
|
|
131
|
+
echo ""
|
|
132
|
+
fi
|
|
133
|
+
if [ -n "$CHORE" ]; then
|
|
134
|
+
echo "### Chores"
|
|
135
|
+
echo ""
|
|
136
|
+
echo "$CHORE"
|
|
137
|
+
echo ""
|
|
138
|
+
fi
|
|
139
|
+
echo "---"
|
|
140
|
+
echo ""
|
|
141
|
+
echo "**PyPI**: https://pypi.org/project/enumplus/"
|
|
142
|
+
if [ -n "$PREVIOUS_TAG" ]; then
|
|
143
|
+
echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREVIOUS_TAG}...${{ github.ref_name }}"
|
|
144
|
+
else
|
|
145
|
+
echo "**Commits**: https://github.com/${{ github.repository }}/commits/${{ github.ref_name }}"
|
|
146
|
+
fi
|
|
147
|
+
echo "EOF"
|
|
148
|
+
} >> "$GITHUB_OUTPUT"
|
|
149
|
+
|
|
150
|
+
- name: Create GitHub Release
|
|
151
|
+
uses: softprops/action-gh-release@v2
|
|
152
|
+
with:
|
|
153
|
+
tag_name: ${{ github.ref_name }}
|
|
154
|
+
name: ${{ github.ref_name }}
|
|
155
|
+
body: ${{ steps.changelog.outputs.body }}
|
|
156
|
+
files: dist/*
|
|
157
|
+
draft: false
|
|
158
|
+
prerelease: false
|
|
159
|
+
|
|
160
|
+
publish-pypi:
|
|
161
|
+
needs: [build, github-release]
|
|
162
|
+
runs-on: ubuntu-latest
|
|
163
|
+
environment: pypi
|
|
164
|
+
permissions:
|
|
165
|
+
id-token: write
|
|
166
|
+
steps:
|
|
167
|
+
- uses: actions/checkout@v4
|
|
168
|
+
|
|
169
|
+
- name: Download artifacts
|
|
170
|
+
uses: actions/download-artifact@v4
|
|
171
|
+
with:
|
|
172
|
+
name: dist
|
|
173
|
+
path: dist/
|
|
174
|
+
|
|
175
|
+
- name: Publish to PyPI
|
|
176
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
enumplus-1.2.0/AGENTS.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Agent Notes for enumplus
|
|
2
|
+
|
|
3
|
+
## Project purpose
|
|
4
|
+
|
|
5
|
+
`enumplus` is a zero-dependency Python library that extends `enum.Enum` with:
|
|
6
|
+
|
|
7
|
+
- Per-member display labels (`label`)
|
|
8
|
+
- Arbitrary per-member metadata, accessible as attributes
|
|
9
|
+
- `(value, metadata)` tuple unpacking at class definition
|
|
10
|
+
- `choices()`, `from_value()`, `from_name()`, `filter()`, `get()`, `map()`
|
|
11
|
+
- JSON serialization (`to_json`, `from_json`, `SerializableEncoder`)
|
|
12
|
+
- Declaration-order comparison (`OrderedEnum`)
|
|
13
|
+
- Optional Pydantic v2 integration (install with `pip install "enumplus[pydantic]"`)
|
|
14
|
+
|
|
15
|
+
Requires Python `>=3.11`.
|
|
16
|
+
|
|
17
|
+
## Important implementation details
|
|
18
|
+
|
|
19
|
+
- The metaclass in `enumplus/enum.py` uses a custom `_EnumPlusDict` namespace.
|
|
20
|
+
This is required to:
|
|
21
|
+
- Unpack `(value, {metadata})` tuples before stdlib enum machinery sees them.
|
|
22
|
+
- Keep class config keys such as `serialize_by_name` from becoming enum members
|
|
23
|
+
or affecting `auto()` generation.
|
|
24
|
+
- Support `auto()` following a metadata tuple on Python 3.11–3.14.
|
|
25
|
+
- `Enum.__eq__` and `EnumMeta.__contains__` use `_safe_equal`, which coerces
|
|
26
|
+
`a == b` to a `bool` without raising on shape/length mismatches (e.g. NumPy
|
|
27
|
+
arrays, unhashable container values).
|
|
28
|
+
- `Enum.__hash__` uses `hash(self.value)` when possible and falls back to
|
|
29
|
+
`id(self)` for unhashable values, so enum members with list/dict values are
|
|
30
|
+
still usable as dict keys.
|
|
31
|
+
- `serialize.py` `from_json` validates that input is a `str` and that the
|
|
32
|
+
parsed JSON is a `dict` (`TypeError` otherwise). Invalid JSON strings raise
|
|
33
|
+
`ValueError`.
|
|
34
|
+
- `py.typed` is included in the wheel so the package is a PEP 561 typed package.
|
|
35
|
+
|
|
36
|
+
## Build and verification commands
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
python -m ruff check enumplus/ tests/
|
|
40
|
+
python -m mypy --strict enumplus/ tests/
|
|
41
|
+
python -m pytest --tb=short
|
|
42
|
+
python -m build
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
After building, verify the wheel contains `py.typed`:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
python -m zipfile -l dist/*.whl
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Cross-version testing
|
|
52
|
+
|
|
53
|
+
CI tests Python 3.11, 3.12, 3.13, and 3.14. Locally, the following versions have
|
|
54
|
+
been verified:
|
|
55
|
+
|
|
56
|
+
- Python 3.11.2
|
|
57
|
+
- Python 3.12.4
|
|
58
|
+
- Python 3.14.5
|
|
59
|
+
|
|
60
|
+
Run a different version with the Windows launcher, e.g.:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
py -3.11 -m pip install -e ".[dev]"
|
|
64
|
+
py -3.11 -m pytest --tb=short
|
|
65
|
+
py -3.11 -m mypy --strict enumplus/ tests/
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Known constraints
|
|
69
|
+
|
|
70
|
+
- The git remote is `MathiasPaulenko/enumpy`, while the package name and PyPI
|
|
71
|
+
project are `enumplus`. Package URLs in `pyproject.toml` point to the actual
|
|
72
|
+
remote repository; update if the repository is renamed.
|
|
73
|
+
- `ref/` is intentionally ignored (local reference material). Do not commit it.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format follows [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
|
+
## [1.2.0] - 2026-08-23
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- `serialize_by_name` is now correctly inherited by subclass enums instead of being silently reset to `False`.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Improved README with table of contents, requirements section, and dynamic CI badge.
|
|
19
|
+
- Added `pydantic` optional dependency extra for Pydantic v2 integration.
|
|
20
|
+
- Added concurrency groups to CI and release workflows to cancel superseded runs.
|
|
21
|
+
- Updated issue templates with correct version examples.
|
|
22
|
+
- Updated CONTRIBUTING with cross-version testing instructions and repository name clarification.
|
|
23
|
+
|
|
24
|
+
## [1.1.0] - 2025-01-15
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- Case-insensitive lookup via `case_insensitive=True` on `from_value()` and `from_name()`.
|
|
29
|
+
- `serialize_by_name` class config for Pydantic v2 validation and serialization by member name.
|
|
30
|
+
- `to_dict()` method for serializing an enum to a nested dictionary.
|
|
31
|
+
- `get()` method for dict-style lookup with a default.
|
|
32
|
+
- `map()` method for mapping each member to a value.
|
|
33
|
+
- `keys()` method as an alias of `names()`.
|
|
34
|
+
- `get_initial()` and `get_final()` for declaration-order access.
|
|
35
|
+
- Callable labels for i18n / translatable labels.
|
|
36
|
+
- `@dataclass_transform()` on the metaclass for type-checker metadata attribute support.
|
|
37
|
+
- `py.typed` marker for PEP 561 typed-package support.
|
|
38
|
+
- Python 3.14 support and CI coverage.
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- `auto()` now works correctly after metadata tuples on Python 3.11–3.14.
|
|
43
|
+
- Class config (`serialize_by_name`) no longer registers as an enum member or corrupts `auto()` state.
|
|
44
|
+
- `__eq__`, `__hash__`, `__contains__`, `from_value`, `is_valid`, and `filter` are now safe for unhashable values and non-boolean comparison results.
|
|
45
|
+
- `from_json` validates input type and JSON shape (`TypeError` for wrong type, `ValueError` for invalid JSON).
|
|
46
|
+
- `from_name` raises `TypeError` for non-string input instead of `KeyError`.
|
|
47
|
+
- `to_dict()` and `to_json()` no longer invoke non-label callable metadata values.
|
|
48
|
+
- Removed redundant import in `SerializableEncoder`.
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- Improved package metadata: classifiers, project URLs, and dev dependency lower bounds.
|
|
53
|
+
- Release workflow uses `${{ github.repository }}` for dynamic changelog URLs.
|
|
54
|
+
- CONTRIBUTING and SUPPORT docs updated with correct commands.
|
|
55
|
+
|
|
56
|
+
## [1.0.0] - 2024-12-01
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
|
|
60
|
+
- `Enum` base class as a drop-in replacement for `enum.Enum`.
|
|
61
|
+
- `OrderedEnum` with declaration-order comparison operators.
|
|
62
|
+
- Per-member labels with automatic `name.title()` fallback.
|
|
63
|
+
- Per-member metadata via `(value, dict)` tuple syntax.
|
|
64
|
+
- Metadata attribute access via `__getattr__`.
|
|
65
|
+
- `choices()`, `from_value()`, `from_name()`, `is_valid()`, `validate()`.
|
|
66
|
+
- `values()`, `names()`, `labels()`.
|
|
67
|
+
- `filter()` by metadata key-value pairs.
|
|
68
|
+
- `to_json()` / `from_json()` serialization.
|
|
69
|
+
- `SerializableEncoder` for `json.dumps`.
|
|
70
|
+
- Pydantic v2 integration via `__get_pydantic_core_schema__`.
|
|
71
|
+
- Full test suite, CI, and release workflows.
|
|
72
|
+
|
|
73
|
+
[Unreleased]: https://github.com/MathiasPaulenko/enumpy/compare/v1.2.0...HEAD
|
|
74
|
+
[1.2.0]: https://github.com/MathiasPaulenko/enumpy/releases/tag/v1.2.0
|
|
75
|
+
[1.1.0]: https://github.com/MathiasPaulenko/enumpy/releases/tag/v1.1.0
|
|
76
|
+
[1.0.0]: https://github.com/MathiasPaulenko/enumpy/releases/tag/v1.0.0
|
|
@@ -17,6 +17,8 @@ Thank you for your interest in contributing to enumplus! This document describes
|
|
|
17
17
|
pip install -e ".[dev]"
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
+
> **Note:** The git repository is named `enumpy`, while the package name is `enumplus`. This is expected — the repository name predates the package rename.
|
|
21
|
+
|
|
20
22
|
## Development Workflow
|
|
21
23
|
|
|
22
24
|
1. Create a branch for your feature or bugfix:
|
|
@@ -26,9 +28,9 @@ Thank you for your interest in contributing to enumplus! This document describes
|
|
|
26
28
|
2. Make your changes, keeping code style consistent with the existing codebase.
|
|
27
29
|
3. Run the checks before committing:
|
|
28
30
|
```bash
|
|
29
|
-
ruff check enumplus tests
|
|
30
|
-
mypy enumplus
|
|
31
|
-
pytest
|
|
31
|
+
ruff check enumplus/ tests/
|
|
32
|
+
mypy --strict enumplus/ tests/
|
|
33
|
+
pytest --tb=short
|
|
32
34
|
```
|
|
33
35
|
4. Commit using [conventional commits](https://www.conventionalcommits.org/):
|
|
34
36
|
```bash
|
|
@@ -51,12 +53,23 @@ Thank you for your interest in contributing to enumplus! This document describes
|
|
|
51
53
|
- Run the full suite with `pytest`.
|
|
52
54
|
- Do not weaken or delete existing tests without explicit justification.
|
|
53
55
|
|
|
56
|
+
## Cross-Version Testing
|
|
57
|
+
|
|
58
|
+
CI tests Python 3.11, 3.12, 3.13, and 3.14. To test locally against multiple Python versions, use the Python launcher (Windows) or `pyenv` (macOS/Linux):
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
py -3.11 -m pip install -e ".[dev]"
|
|
62
|
+
py -3.11 -m pytest --tb=short
|
|
63
|
+
py -3.11 -m mypy --strict enumplus/ tests/
|
|
64
|
+
```
|
|
65
|
+
|
|
54
66
|
## Pull Request Guidelines
|
|
55
67
|
|
|
56
68
|
- Keep PRs focused and small.
|
|
57
69
|
- Reference any related issues (e.g., `Closes #123`).
|
|
58
70
|
- Ensure all CI checks pass before requesting review.
|
|
59
71
|
- Update documentation (`README.md`) if your change affects the public API.
|
|
72
|
+
- Add a `CHANGELOG.md` entry under the `[Unreleased]` section.
|
|
60
73
|
|
|
61
74
|
## Reporting Issues
|
|
62
75
|
|