valid8r 0.7.1__tar.gz → 0.7.3__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.
Potentially problematic release.
This version of valid8r might be problematic. Click here for more details.
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/CONVENTIONAL_COMMITS.md +4 -4
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/QUICK_REFERENCE.md +3 -3
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/README.md +8 -8
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/SETUP_CHECKLIST.md +7 -7
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/WORKFLOWS.md +6 -6
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/pull_request_template.md +6 -6
- {valid8r-0.7.1 → valid8r-0.7.3}/.readthedocs.yaml +5 -7
- {valid8r-0.7.1 → valid8r-0.7.3}/CLAUDE.md +14 -3
- {valid8r-0.7.1 → valid8r-0.7.3}/CONTRIBUTING.md +28 -20
- valid8r-0.7.3/PKG-INFO +305 -0
- valid8r-0.7.3/README.md +274 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/development/contributing.rst +17 -14
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/development/testing.rst +21 -18
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/index.rst +7 -1
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/user_guide/getting_started.rst +8 -2
- {valid8r-0.7.1 → valid8r-0.7.3}/pyproject.toml +1 -1
- {valid8r-0.7.1 → valid8r-0.7.3}/uv.lock +1 -1
- valid8r-0.7.1/PKG-INFO +0 -298
- valid8r-0.7.1/README.md +0 -267
- {valid8r-0.7.1 → valid8r-0.7.3}/.coveragerc +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.cursorrules +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/CICD_TEST.md +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/CODEOWNERS +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/ISSUE_TEMPLATE/documentation.yml +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/PYPI_TOKEN_SETUP_GUIDE.md +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/WORKFLOW_DIAGRAM.md +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/dependabot.yml +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/labeler.yml +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/release.yml +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/workflows/ci.yml +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/workflows/labeler.yml +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/workflows/publish-pypi.yml +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/workflows/semantic-release.yml +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/workflows/size-label.yml +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/workflows/stale.yml +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/workflows/version-and-release.yml +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.github/workflows/welcome.yml +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.gitignore +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.pre-commit-config.yaml +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/.python-version +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/CICD_SETUP_SUMMARY.md +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/CODE_OF_CONDUCT.md +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/LICENSE +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/QA_REPORT_WEB_PARSERS_V0.6.0.md +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/QA_VALIDATION_SUMMARY.md +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/ROADMAP.md +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/SECURITY.md +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/__init__.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/_static/css/custom.css +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/api/core.rst +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/api/prompt.rst +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/conf.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/development/changelog.rst +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/examples/basic_example.rst +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/examples/chaining_validators.rst +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/examples/custom_validators.rst +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/examples/fastapi_integration.rst +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/examples/interactive_prompts.rst +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/migration-poetry-to-uv.md +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/user_guide/advanced_usage.rst +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/user_guide/maybe_monad.rst +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/user_guide/parsers.rst +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/user_guide/prompting.rst +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/user_guide/testing.rst +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/docs/user_guide/validators.rst +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/scripts/__init__.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/scripts/docs.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/smoke_test.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/__init__.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/__init__.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/conftest.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/environment.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/features/clean_type_parsing.feature +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/features/collection_parsing.feature +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/features/interactive_prompts.feature +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/features/phone_parsing.feature +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/features/testing_utilities.feature +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/features/url_email_parsing.feature +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/features/validator_combinators.feature +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/features/validators.feature +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/features/web_parsers.feature +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/steps/__init__.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/steps/clean_type_parsing_steps.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/steps/collection_parsing_steps.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/steps/interactive_prompts_steps.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/steps/phone_parsing_steps.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/steps/testing_utilities_steps.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/steps/url_email_parsing_steps.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/steps/validator_combinators_steps.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/steps/validators_steps.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/bdd/steps/web_parsers_steps.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/integration/__init__.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/integration/test_validator.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/qa_security_web_parsers.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/__init__.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/conftest.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_combinators.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_decimal_parser.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_dict_parser.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_generators.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_ip_parsers.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_list_parser.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_maybe.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_parsers.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_phone_parsing.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_prompt.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_public_api.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_testing_utilities.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_url_email_parsers.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_uuid_parser.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_validators.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tests/unit/test_web_parsers.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/tox.ini +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/valid8r/__init__.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/valid8r/core/__init__.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/valid8r/core/combinators.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/valid8r/core/maybe.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/valid8r/core/parsers.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/valid8r/core/validators.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/valid8r/prompt/__init__.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/valid8r/prompt/basic.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/valid8r/py.typed +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/valid8r/testing/__init__.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/valid8r/testing/assertions.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/valid8r/testing/generators.py +0 -0
- {valid8r-0.7.1 → valid8r-0.7.3}/valid8r/testing/mock_input.py +0 -0
|
@@ -25,7 +25,7 @@ This is a quick reference guide for writing conventional commits for the valid8r
|
|
|
25
25
|
| `test` | 🔼 **patch** | Adding or updating tests | `test: add edge cases for validators` |
|
|
26
26
|
| `chore` | 🔼 **patch** | Maintenance tasks | `chore: update dependencies` |
|
|
27
27
|
| `ci` | ⚪ **none** | CI/CD changes | `ci: add Python 3.13 to matrix` |
|
|
28
|
-
| `build` | ⚪ **none** | Build system changes | `build: update
|
|
28
|
+
| `build` | ⚪ **none** | Build system changes | `build: update uv config` |
|
|
29
29
|
|
|
30
30
|
## Breaking Changes (Major Bump)
|
|
31
31
|
|
|
@@ -268,9 +268,9 @@ Before committing, check:
|
|
|
268
268
|
|
|
269
269
|
```bash
|
|
270
270
|
# Run checks before committing
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
271
|
+
uv run ruff check .
|
|
272
|
+
uv run mypy valid8r
|
|
273
|
+
uv run pytest
|
|
274
274
|
|
|
275
275
|
# Then commit
|
|
276
276
|
git commit -m "feat(parsers): add parse_phone_number"
|
|
@@ -31,9 +31,9 @@ git commit -m "feat(parsers): add phone validation"
|
|
|
31
31
|
gh pr create --fill
|
|
32
32
|
|
|
33
33
|
# Run checks locally
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
uv run pytest
|
|
35
|
+
uv run mypy valid8r
|
|
36
|
+
uv run ruff check .
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
### Manual Workflow Triggers
|
|
@@ -184,9 +184,9 @@ git checkout -b feat/add-parser
|
|
|
184
184
|
# ... edit code ...
|
|
185
185
|
|
|
186
186
|
# 3. Run tests locally
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
187
|
+
uv run pytest
|
|
188
|
+
uv run mypy valid8r
|
|
189
|
+
uv run ruff check .
|
|
190
190
|
|
|
191
191
|
# 4. Commit with conventional format
|
|
192
192
|
git commit -m "feat(parsers): add phone number parser"
|
|
@@ -284,11 +284,11 @@ gh workflow run stale.yml
|
|
|
284
284
|
|
|
285
285
|
**Run locally**:
|
|
286
286
|
```bash
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
287
|
+
uv run ruff check .
|
|
288
|
+
uv run ruff format --check .
|
|
289
|
+
uv run mypy valid8r
|
|
290
|
+
uv run pytest
|
|
291
|
+
uv run behave tests/bdd/features
|
|
292
292
|
```
|
|
293
293
|
|
|
294
294
|
Fix issues and push again.
|
|
@@ -121,17 +121,16 @@ Create `test-pypi` environment (optional):
|
|
|
121
121
|
|
|
122
122
|
```bash
|
|
123
123
|
# Ensure version is 0.1.0 in pyproject.toml
|
|
124
|
-
|
|
124
|
+
# Version is managed by semantic-release, but for first publish verify it's set correctly
|
|
125
125
|
|
|
126
126
|
# Build the package
|
|
127
|
-
|
|
127
|
+
uv build
|
|
128
128
|
|
|
129
129
|
# Publish to Test PyPI first (to verify)
|
|
130
|
-
|
|
131
|
-
poetry publish -r testpypi --username __token__ --password pypi-...
|
|
130
|
+
uv publish --publish-url https://test.pypi.org/legacy/ --token pypi-...
|
|
132
131
|
|
|
133
132
|
# If test publish succeeds, publish to production PyPI
|
|
134
|
-
|
|
133
|
+
uv publish --token pypi-...
|
|
135
134
|
```
|
|
136
135
|
|
|
137
136
|
**Option B: Trusted Publisher** (More secure, no tokens needed)
|
|
@@ -219,8 +218,9 @@ Final verification checklist:
|
|
|
219
218
|
**Expected behavior**: The workflow skips publishing if version exists.
|
|
220
219
|
|
|
221
220
|
**If you need to republish**:
|
|
222
|
-
1.
|
|
223
|
-
2. Commit and push to trigger new release
|
|
221
|
+
1. Version bump happens automatically via semantic-release based on conventional commits
|
|
222
|
+
2. Commit with appropriate conventional commit type and push to trigger new release
|
|
223
|
+
3. Or manually trigger version bump: `gh workflow run semantic-release.yml`
|
|
224
224
|
|
|
225
225
|
### Issue: Required checks not appearing in branch protection
|
|
226
226
|
|
|
@@ -240,7 +240,7 @@ vim valid8r/core/parsers.py
|
|
|
240
240
|
vim tests/unit/test_parsers.py
|
|
241
241
|
|
|
242
242
|
# Run tests locally
|
|
243
|
-
|
|
243
|
+
uv run pytest
|
|
244
244
|
|
|
245
245
|
# Commit with conventional format
|
|
246
246
|
git add .
|
|
@@ -386,11 +386,11 @@ gh workflow run version-and-release.yml -f version_bump=patch
|
|
|
386
386
|
1. Check workflow run logs in GitHub Actions tab
|
|
387
387
|
2. Run same checks locally:
|
|
388
388
|
```bash
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
389
|
+
uv run ruff check .
|
|
390
|
+
uv run ruff format --check .
|
|
391
|
+
uv run mypy valid8r
|
|
392
|
+
uv run pytest
|
|
393
|
+
uv run behave tests/bdd/features
|
|
394
394
|
```
|
|
395
395
|
3. Fix issues and push again
|
|
396
396
|
|
|
@@ -31,7 +31,7 @@ Fixes #
|
|
|
31
31
|
|
|
32
32
|
- [ ] Unit tests added/updated
|
|
33
33
|
- [ ] BDD tests added/updated (if applicable)
|
|
34
|
-
- [ ] All tests pass locally (`
|
|
34
|
+
- [ ] All tests pass locally (`uv run tox`)
|
|
35
35
|
- [ ] Test coverage maintained or improved
|
|
36
36
|
|
|
37
37
|
## Test Evidence
|
|
@@ -40,7 +40,7 @@ Fixes #
|
|
|
40
40
|
|
|
41
41
|
```
|
|
42
42
|
# Example:
|
|
43
|
-
$
|
|
43
|
+
$ uv run pytest tests/unit/test_my_feature.py
|
|
44
44
|
================================ test session starts =================================
|
|
45
45
|
collected 15 items
|
|
46
46
|
|
|
@@ -52,9 +52,9 @@ tests/unit/test_my_feature.py ............... [100%]
|
|
|
52
52
|
|
|
53
53
|
## Checklist
|
|
54
54
|
|
|
55
|
-
- [ ] Code follows the project's style guidelines (`
|
|
56
|
-
- [ ] Code is formatted properly (`
|
|
57
|
-
- [ ] Type hints are complete and pass mypy (`
|
|
55
|
+
- [ ] Code follows the project's style guidelines (`uv run ruff check .`)
|
|
56
|
+
- [ ] Code is formatted properly (`uv run ruff format .`)
|
|
57
|
+
- [ ] Type hints are complete and pass mypy (`uv run mypy valid8r`)
|
|
58
58
|
- [ ] Docstrings added/updated for public API
|
|
59
59
|
- [ ] `__all__` exports updated if public API changed
|
|
60
60
|
- [ ] CLAUDE.md updated if architecture/patterns changed
|
|
@@ -72,7 +72,7 @@ N/A
|
|
|
72
72
|
- [ ] README.md updated (if needed)
|
|
73
73
|
- [ ] API documentation updated (docstrings)
|
|
74
74
|
- [ ] Usage examples added (if new feature)
|
|
75
|
-
- [ ] Sphinx docs build successfully (`
|
|
75
|
+
- [ ] Sphinx docs build successfully (`uv run docs-build`)
|
|
76
76
|
|
|
77
77
|
# Additional Notes
|
|
78
78
|
|
|
@@ -10,14 +10,12 @@ build:
|
|
|
10
10
|
tools:
|
|
11
11
|
python: "3.11"
|
|
12
12
|
commands:
|
|
13
|
-
# Install
|
|
14
|
-
- pip install
|
|
15
|
-
# Configure poetry to not create virtualenvs
|
|
16
|
-
- poetry config virtualenvs.create false
|
|
13
|
+
# Install uv
|
|
14
|
+
- pip install uv
|
|
17
15
|
# Install all dependencies including the project itself
|
|
18
|
-
-
|
|
19
|
-
# Let
|
|
20
|
-
-
|
|
16
|
+
- uv sync --group docs
|
|
17
|
+
# Let uv run Sphinx to avoid dependency conflicts
|
|
18
|
+
- uv run sphinx-build -b html docs $READTHEDOCS_OUTPUT/html
|
|
21
19
|
|
|
22
20
|
# Build documentation formats
|
|
23
21
|
formats:
|
|
@@ -77,7 +77,11 @@ All new features MUST follow this exact workflow using the specialized agents de
|
|
|
77
77
|
|
|
78
78
|
## Common Development Commands
|
|
79
79
|
|
|
80
|
-
**Note**: This project uses `uv` for dependency management (
|
|
80
|
+
**Note**: This project uses `uv` for dependency management. The migration from Poetry to uv was completed in November 2025 (PR #48), bringing 60% faster CI pipelines and 300x+ faster dependency resolution.
|
|
81
|
+
|
|
82
|
+
See `docs/migration-poetry-to-uv.md` for the complete migration guide, including command comparisons and troubleshooting.
|
|
83
|
+
|
|
84
|
+
**Install uv:**
|
|
81
85
|
```bash
|
|
82
86
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
83
87
|
```
|
|
@@ -156,15 +160,22 @@ uv run python smoke_test.py
|
|
|
156
160
|
|
|
157
161
|
### Dependency Management
|
|
158
162
|
```bash
|
|
159
|
-
# Add a
|
|
163
|
+
# Add a production dependency
|
|
160
164
|
uv add requests
|
|
161
165
|
|
|
162
166
|
# Add a dev dependency
|
|
163
|
-
uv add --dev pytest-timeout
|
|
167
|
+
uv add --group dev pytest-timeout
|
|
168
|
+
|
|
169
|
+
# Add to specific dependency groups
|
|
170
|
+
uv add --group test pytest-mock
|
|
171
|
+
uv add --group docs sphinx-theme
|
|
164
172
|
|
|
165
173
|
# Update all dependencies
|
|
166
174
|
uv lock --upgrade
|
|
167
175
|
|
|
176
|
+
# Update a specific package
|
|
177
|
+
uv lock --upgrade-package requests
|
|
178
|
+
|
|
168
179
|
# Export requirements for other tools
|
|
169
180
|
uv export > requirements.txt
|
|
170
181
|
```
|
|
@@ -24,8 +24,8 @@ This project adheres to the [Contributor Covenant Code of Conduct](CODE_OF_CONDU
|
|
|
24
24
|
|
|
25
25
|
### Prerequisites
|
|
26
26
|
|
|
27
|
-
- Python 3.11 or higher
|
|
28
|
-
- [
|
|
27
|
+
- Python 3.11 or higher (3.11-3.14 supported)
|
|
28
|
+
- [uv](https://docs.astral.sh/uv/) for dependency management (10-100x faster than Poetry)
|
|
29
29
|
- [pyenv](https://github.com/pyenv/pyenv) (recommended for managing Python versions)
|
|
30
30
|
- Git
|
|
31
31
|
|
|
@@ -56,24 +56,32 @@ pyenv install 3.14.0
|
|
|
56
56
|
pyenv local 3.11.11 3.12.9 3.13.5 3.14.0
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
### 2. Install
|
|
59
|
+
### 2. Install uv
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
|
-
curl -
|
|
62
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Verify installation:**
|
|
66
|
+
```bash
|
|
67
|
+
uv --version
|
|
68
|
+
# Should show: uv 0.9.x or later
|
|
63
69
|
```
|
|
64
70
|
|
|
65
71
|
### 3. Install Dependencies
|
|
66
72
|
|
|
67
73
|
```bash
|
|
68
|
-
|
|
74
|
+
uv sync
|
|
69
75
|
```
|
|
70
76
|
|
|
71
77
|
This installs all dependencies including dev, test, lint, and docs groups.
|
|
72
78
|
|
|
79
|
+
**Note**: If you previously used Poetry, see [docs/migration-poetry-to-uv.md](../docs/migration-poetry-to-uv.md) for migration instructions.
|
|
80
|
+
|
|
73
81
|
### 4. Set Up Pre-commit Hooks
|
|
74
82
|
|
|
75
83
|
```bash
|
|
76
|
-
|
|
84
|
+
uv run pre-commit install
|
|
77
85
|
```
|
|
78
86
|
|
|
79
87
|
Pre-commit hooks automatically:
|
|
@@ -101,16 +109,16 @@ Write clean, well-tested code following our style guidelines.
|
|
|
101
109
|
|
|
102
110
|
```bash
|
|
103
111
|
# Run all tests with coverage
|
|
104
|
-
|
|
112
|
+
uv run tox
|
|
105
113
|
|
|
106
114
|
# Run only unit tests
|
|
107
|
-
|
|
115
|
+
uv run pytest tests/unit
|
|
108
116
|
|
|
109
117
|
# Run BDD tests
|
|
110
|
-
|
|
118
|
+
uv run tox -e bdd
|
|
111
119
|
|
|
112
120
|
# Run linting
|
|
113
|
-
|
|
121
|
+
uv run tox -e lint
|
|
114
122
|
```
|
|
115
123
|
|
|
116
124
|
### 4. Commit Your Changes
|
|
@@ -145,13 +153,13 @@ Then create a Pull Request on GitHub.
|
|
|
145
153
|
|
|
146
154
|
```bash
|
|
147
155
|
# Format code with ruff
|
|
148
|
-
|
|
156
|
+
uv run ruff format .
|
|
149
157
|
|
|
150
158
|
# Check and fix linting issues
|
|
151
|
-
|
|
159
|
+
uv run ruff check . --fix
|
|
152
160
|
|
|
153
161
|
# Check type hints
|
|
154
|
-
|
|
162
|
+
uv run mypy valid8r
|
|
155
163
|
```
|
|
156
164
|
|
|
157
165
|
### Code Patterns
|
|
@@ -312,7 +320,7 @@ See [.github/CONVENTIONAL_COMMITS.md](.github/CONVENTIONAL_COMMITS.md) for more
|
|
|
312
320
|
|
|
313
321
|
### Before Submitting
|
|
314
322
|
|
|
315
|
-
1. Ensure all tests pass: `
|
|
323
|
+
1. Ensure all tests pass: `uv run tox`
|
|
316
324
|
2. Update documentation if needed
|
|
317
325
|
3. Add changelog entry if applicable
|
|
318
326
|
4. Verify your commits follow the conventional commit format
|
|
@@ -403,10 +411,10 @@ def parse_email(text: str) -> Maybe[EmailAddress]:
|
|
|
403
411
|
|
|
404
412
|
```bash
|
|
405
413
|
# Build documentation
|
|
406
|
-
|
|
414
|
+
uv run docs-build
|
|
407
415
|
|
|
408
416
|
# Serve with live reload
|
|
409
|
-
|
|
417
|
+
uv run docs-serve
|
|
410
418
|
```
|
|
411
419
|
|
|
412
420
|
View at http://localhost:8000
|
|
@@ -431,17 +439,17 @@ View at http://localhost:8000
|
|
|
431
439
|
|
|
432
440
|
```bash
|
|
433
441
|
# Run smoke test
|
|
434
|
-
python smoke_test.py
|
|
442
|
+
uv run python smoke_test.py
|
|
435
443
|
|
|
436
444
|
# Check coverage
|
|
437
|
-
|
|
445
|
+
uv run pytest --cov=valid8r --cov-report=html tests/unit
|
|
438
446
|
# View at htmlcov/index.html
|
|
439
447
|
|
|
440
448
|
# Run specific test
|
|
441
|
-
|
|
449
|
+
uv run pytest tests/unit/test_parsers.py::DescribeParseInt::it_parses_positive_integers
|
|
442
450
|
|
|
443
451
|
# Watch mode (requires pytest-watch)
|
|
444
|
-
|
|
452
|
+
uv run ptw tests/unit
|
|
445
453
|
```
|
|
446
454
|
|
|
447
455
|
### Debugging
|
valid8r-0.7.3/PKG-INFO
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: valid8r
|
|
3
|
+
Version: 0.7.3
|
|
4
|
+
Summary: Clean, flexible input validation for Python applications
|
|
5
|
+
Project-URL: Homepage, https://valid8r.readthedocs.io/
|
|
6
|
+
Project-URL: Repository, https://github.com/mikelane/valid8r
|
|
7
|
+
Project-URL: Documentation, https://valid8r.readthedocs.io/
|
|
8
|
+
Project-URL: Issues, https://github.com/mikelane/valid8r/issues
|
|
9
|
+
Author-email: Mike Lane <mikelane@gmail.com>
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: cli,functional-programming,input,maybe-monad,parsing,validation
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.11
|
|
26
|
+
Requires-Dist: email-validator>=2.3.0
|
|
27
|
+
Requires-Dist: pydantic-core>=2.27.0
|
|
28
|
+
Requires-Dist: pydantic>=2.0
|
|
29
|
+
Requires-Dist: uuid-utils>=0.11.0
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# Valid8r
|
|
33
|
+
|
|
34
|
+
[](https://pypi.org/project/valid8r/)
|
|
35
|
+
[](https://pypi.org/project/valid8r/)
|
|
36
|
+
[](https://github.com/mikelane/valid8r/blob/main/LICENSE)
|
|
37
|
+
[](https://github.com/mikelane/valid8r/actions)
|
|
38
|
+
[](https://codecov.io/gh/mikelane/valid8r)
|
|
39
|
+
[](https://valid8r.readthedocs.io/)
|
|
40
|
+
|
|
41
|
+
**Clean, composable input validation for Python using functional programming patterns.**
|
|
42
|
+
|
|
43
|
+
Valid8r makes input validation elegant and type-safe by using the Maybe monad for error handling. No more try-except blocks or boolean validation chains—just clean, composable parsers that tell you exactly what went wrong.
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from valid8r import parsers, validators, prompt
|
|
47
|
+
|
|
48
|
+
# Parse and validate user input with rich error messages
|
|
49
|
+
age = prompt.ask(
|
|
50
|
+
"Enter your age: ",
|
|
51
|
+
parser=parsers.parse_int,
|
|
52
|
+
validator=validators.minimum(0) & validators.maximum(120)
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
print(f"Your age is {age}")
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Why Valid8r?
|
|
59
|
+
|
|
60
|
+
**Type-Safe Parsing**: Every parser returns `Maybe[T]` (Success or Failure), making error handling explicit and composable.
|
|
61
|
+
|
|
62
|
+
**Rich Structured Results**: Network parsers return dataclasses with parsed components—no more manual URL/email splitting.
|
|
63
|
+
|
|
64
|
+
**Chainable Validators**: Combine validators using `&` (and), `|` (or), and `~` (not) operators for complex validation logic.
|
|
65
|
+
|
|
66
|
+
**Zero Dependencies**: Core library uses only Python's standard library (with optional `uuid-utils` for faster UUID parsing).
|
|
67
|
+
|
|
68
|
+
**Interactive Prompts**: Built-in user input prompting with automatic retry and validation.
|
|
69
|
+
|
|
70
|
+
## Quick Start
|
|
71
|
+
|
|
72
|
+
### Installation
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip install valid8r
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Requirements**: Python 3.11 or higher
|
|
79
|
+
|
|
80
|
+
### Basic Parsing
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from valid8r import parsers
|
|
84
|
+
from valid8r.core.maybe import Success, Failure
|
|
85
|
+
|
|
86
|
+
# Parse integers with automatic error handling
|
|
87
|
+
match parsers.parse_int("42"):
|
|
88
|
+
case Success(value):
|
|
89
|
+
print(f"Parsed: {value}") # Parsed: 42
|
|
90
|
+
case Failure(error):
|
|
91
|
+
print(f"Error: {error}")
|
|
92
|
+
|
|
93
|
+
# Parse dates (ISO 8601 format)
|
|
94
|
+
result = parsers.parse_date("2025-01-15")
|
|
95
|
+
assert result.is_success()
|
|
96
|
+
|
|
97
|
+
# Parse UUIDs with version validation
|
|
98
|
+
result = parsers.parse_uuid("550e8400-e29b-41d4-a716-446655440000", version=4)
|
|
99
|
+
assert result.is_success()
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Validation with Combinators
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from valid8r import validators
|
|
106
|
+
|
|
107
|
+
# Combine validators using operators
|
|
108
|
+
age_validator = validators.minimum(0) & validators.maximum(120)
|
|
109
|
+
result = age_validator(42)
|
|
110
|
+
assert result.is_success()
|
|
111
|
+
|
|
112
|
+
# String validation
|
|
113
|
+
password_validator = (
|
|
114
|
+
validators.length(8, 128) &
|
|
115
|
+
validators.matches_regex(r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d@$!%*#?&]')
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# Set validation
|
|
119
|
+
tags_validator = validators.subset_of({'python', 'rust', 'go', 'typescript'})
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Structured Network Parsing
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from valid8r import parsers
|
|
126
|
+
|
|
127
|
+
# Parse URLs into structured components
|
|
128
|
+
match parsers.parse_url("https://user:pass@example.com:8443/path?query=1#fragment"):
|
|
129
|
+
case Success(url):
|
|
130
|
+
print(f"Scheme: {url.scheme}") # https
|
|
131
|
+
print(f"Host: {url.host}") # example.com
|
|
132
|
+
print(f"Port: {url.port}") # 8443
|
|
133
|
+
print(f"Path: {url.path}") # /path
|
|
134
|
+
print(f"Query: {url.query}") # {'query': '1'}
|
|
135
|
+
print(f"Fragment: {url.fragment}") # fragment
|
|
136
|
+
|
|
137
|
+
# Parse emails with normalized domains
|
|
138
|
+
match parsers.parse_email("User@Example.COM"):
|
|
139
|
+
case Success(email):
|
|
140
|
+
print(f"Local: {email.local}") # User
|
|
141
|
+
print(f"Domain: {email.domain}") # example.com (normalized)
|
|
142
|
+
|
|
143
|
+
# Parse phone numbers (NANP format)
|
|
144
|
+
match parsers.parse_phone("+1 (415) 555-2671"):
|
|
145
|
+
case Success(phone):
|
|
146
|
+
print(f"E.164: {phone.e164}") # +14155552671
|
|
147
|
+
print(f"National: {phone.national}") # (415) 555-2671
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Collection Parsing
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from valid8r import parsers
|
|
154
|
+
|
|
155
|
+
# Parse lists with element validation
|
|
156
|
+
result = parsers.parse_list("1,2,3,4,5", element_parser=parsers.parse_int)
|
|
157
|
+
assert result.value_or([]) == [1, 2, 3, 4, 5]
|
|
158
|
+
|
|
159
|
+
# Parse dictionaries with key/value parsers
|
|
160
|
+
result = parsers.parse_dict(
|
|
161
|
+
"name=Alice,age=30",
|
|
162
|
+
key_parser=lambda x: Success(x),
|
|
163
|
+
value_parser=lambda x: parsers.parse_int(x) if x.isdigit() else Success(x)
|
|
164
|
+
)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Interactive Prompting
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
from valid8r import prompt, parsers, validators
|
|
171
|
+
|
|
172
|
+
# Prompt with validation and automatic retry
|
|
173
|
+
email = prompt.ask(
|
|
174
|
+
"Email address: ",
|
|
175
|
+
parser=parsers.parse_email,
|
|
176
|
+
retry=2 # Retry twice on invalid input
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# Combine parsing and validation
|
|
180
|
+
port = prompt.ask(
|
|
181
|
+
"Server port: ",
|
|
182
|
+
parser=parsers.parse_int,
|
|
183
|
+
validator=validators.between(1024, 65535),
|
|
184
|
+
retry=3
|
|
185
|
+
)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Features
|
|
189
|
+
|
|
190
|
+
### Parsers
|
|
191
|
+
|
|
192
|
+
**Basic Types**:
|
|
193
|
+
- `parse_int`, `parse_float`, `parse_bool`, `parse_decimal`, `parse_complex`
|
|
194
|
+
- `parse_date` (ISO 8601), `parse_uuid` (with version validation)
|
|
195
|
+
|
|
196
|
+
**Collections**:
|
|
197
|
+
- `parse_list`, `parse_dict`, `parse_set` (with element parsers)
|
|
198
|
+
|
|
199
|
+
**Network & Communication**:
|
|
200
|
+
- `parse_ipv4`, `parse_ipv6`, `parse_ip`, `parse_cidr`
|
|
201
|
+
- `parse_url` → `UrlParts` (structured URL components)
|
|
202
|
+
- `parse_email` → `EmailAddress` (normalized domain)
|
|
203
|
+
- `parse_phone` → `PhoneNumber` (NANP validation with E.164 formatting)
|
|
204
|
+
|
|
205
|
+
**Advanced**:
|
|
206
|
+
- `parse_enum` (type-safe enum parsing)
|
|
207
|
+
- `create_parser`, `make_parser`, `validated_parser` (custom parser factories)
|
|
208
|
+
|
|
209
|
+
### Validators
|
|
210
|
+
|
|
211
|
+
**Numeric**: `minimum`, `maximum`, `between`
|
|
212
|
+
|
|
213
|
+
**String**: `non_empty_string`, `matches_regex`, `length`
|
|
214
|
+
|
|
215
|
+
**Collection**: `in_set`, `unique_items`, `subset_of`, `superset_of`, `is_sorted`
|
|
216
|
+
|
|
217
|
+
**Custom**: `predicate` (create validators from any function)
|
|
218
|
+
|
|
219
|
+
**Combinators**: Combine validators using `&` (and), `|` (or), `~` (not)
|
|
220
|
+
|
|
221
|
+
### Testing Utilities
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
from valid8r.testing import (
|
|
225
|
+
assert_maybe_success,
|
|
226
|
+
assert_maybe_failure,
|
|
227
|
+
MockInputContext,
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
# Test validation logic
|
|
231
|
+
result = validators.minimum(0)(42)
|
|
232
|
+
assert assert_maybe_success(result, 42)
|
|
233
|
+
|
|
234
|
+
result = validators.minimum(0)(-5)
|
|
235
|
+
assert assert_maybe_failure(result, "at least 0")
|
|
236
|
+
|
|
237
|
+
# Mock user input for testing prompts
|
|
238
|
+
with MockInputContext(["invalid", "valid@example.com"]):
|
|
239
|
+
result = prompt.ask("Email: ", parser=parsers.parse_email, retry=1)
|
|
240
|
+
assert result.is_success()
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Documentation
|
|
244
|
+
|
|
245
|
+
**Full documentation**: [valid8r.readthedocs.io](https://valid8r.readthedocs.io/)
|
|
246
|
+
|
|
247
|
+
- [API Reference](https://valid8r.readthedocs.io/en/latest/api.html)
|
|
248
|
+
- [Parser Guide](https://valid8r.readthedocs.io/en/latest/parsers.html)
|
|
249
|
+
- [Validator Guide](https://valid8r.readthedocs.io/en/latest/validators.html)
|
|
250
|
+
- [Testing Guide](https://valid8r.readthedocs.io/en/latest/testing.html)
|
|
251
|
+
|
|
252
|
+
## Contributing
|
|
253
|
+
|
|
254
|
+
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
255
|
+
|
|
256
|
+
**Quick links**:
|
|
257
|
+
- [Code of Conduct](CODE_OF_CONDUCT.md)
|
|
258
|
+
- [Development Setup](CONTRIBUTING.md#development-setup)
|
|
259
|
+
- [Commit Message Format](CONTRIBUTING.md#commit-messages)
|
|
260
|
+
- [Pull Request Process](CONTRIBUTING.md#pull-request-process)
|
|
261
|
+
|
|
262
|
+
### Development Quick Start
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
# Install uv (fast dependency manager)
|
|
266
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
267
|
+
|
|
268
|
+
# Clone and install dependencies
|
|
269
|
+
git clone https://github.com/mikelane/valid8r
|
|
270
|
+
cd valid8r
|
|
271
|
+
uv sync
|
|
272
|
+
|
|
273
|
+
# Run tests
|
|
274
|
+
uv run tox
|
|
275
|
+
|
|
276
|
+
# Run linters
|
|
277
|
+
uv run ruff check .
|
|
278
|
+
uv run ruff format .
|
|
279
|
+
uv run mypy valid8r
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Project Status
|
|
283
|
+
|
|
284
|
+
Valid8r is in active development (v0.7.x). The API is stabilizing but may change before v1.0.0.
|
|
285
|
+
|
|
286
|
+
- ✅ Core parsers and validators
|
|
287
|
+
- ✅ Maybe monad error handling
|
|
288
|
+
- ✅ Interactive prompting
|
|
289
|
+
- ✅ Network parsers (URL, Email, IP, Phone)
|
|
290
|
+
- ✅ Collection parsers
|
|
291
|
+
- ✅ Comprehensive testing utilities
|
|
292
|
+
- 🚧 Additional validators (in progress)
|
|
293
|
+
- 🚧 Custom error types (planned)
|
|
294
|
+
|
|
295
|
+
See [ROADMAP.md](ROADMAP.md) for planned features.
|
|
296
|
+
|
|
297
|
+
## License
|
|
298
|
+
|
|
299
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
300
|
+
|
|
301
|
+
Copyright (c) 2025 Mike Lane
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
**Made with ❤️ for the Python community**
|