valid8r 0.7.0__tar.gz → 0.7.1__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/.coveragerc +12 -0
- valid8r-0.7.1/.cursorrules +325 -0
- valid8r-0.7.1/.github/CICD_TEST.md +28 -0
- valid8r-0.7.1/.github/CODEOWNERS +33 -0
- valid8r-0.7.1/.github/CONVENTIONAL_COMMITS.md +338 -0
- valid8r-0.7.1/.github/ISSUE_TEMPLATE/bug_report.yml +95 -0
- valid8r-0.7.1/.github/ISSUE_TEMPLATE/documentation.yml +73 -0
- valid8r-0.7.1/.github/ISSUE_TEMPLATE/feature_request.yml +77 -0
- valid8r-0.7.1/.github/PYPI_TOKEN_SETUP_GUIDE.md +297 -0
- valid8r-0.7.1/.github/QUICK_REFERENCE.md +119 -0
- valid8r-0.7.1/.github/README.md +423 -0
- valid8r-0.7.1/.github/SETUP_CHECKLIST.md +318 -0
- valid8r-0.7.1/.github/WORKFLOWS.md +488 -0
- valid8r-0.7.1/.github/WORKFLOW_DIAGRAM.md +191 -0
- valid8r-0.7.1/.github/dependabot.yml +60 -0
- valid8r-0.7.1/.github/labeler.yml +63 -0
- valid8r-0.7.1/.github/pull_request_template.md +115 -0
- valid8r-0.7.1/.github/release.yml +54 -0
- valid8r-0.7.1/.github/workflows/ci.yml +215 -0
- valid8r-0.7.1/.github/workflows/labeler.yml +19 -0
- valid8r-0.7.1/.github/workflows/publish-pypi.yml +235 -0
- valid8r-0.7.1/.github/workflows/semantic-release.yml +56 -0
- valid8r-0.7.1/.github/workflows/size-label.yml +31 -0
- valid8r-0.7.1/.github/workflows/stale.yml +65 -0
- valid8r-0.7.1/.github/workflows/version-and-release.yml +212 -0
- valid8r-0.7.1/.github/workflows/welcome.yml +46 -0
- valid8r-0.7.1/.gitignore +59 -0
- valid8r-0.7.1/.pre-commit-config.yaml +47 -0
- valid8r-0.7.1/.python-version +4 -0
- valid8r-0.7.1/.readthedocs.yaml +25 -0
- valid8r-0.7.1/CICD_SETUP_SUMMARY.md +513 -0
- valid8r-0.7.1/CLAUDE.md +376 -0
- valid8r-0.7.1/CODE_OF_CONDUCT.md +55 -0
- valid8r-0.7.1/CONTRIBUTING.md +472 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/PKG-INFO +12 -13
- valid8r-0.7.1/QA_REPORT_WEB_PARSERS_V0.6.0.md +449 -0
- valid8r-0.7.1/QA_VALIDATION_SUMMARY.md +86 -0
- valid8r-0.7.1/ROADMAP.md +206 -0
- valid8r-0.7.1/SECURITY.md +166 -0
- valid8r-0.7.1/docs/__init__.py +1 -0
- valid8r-0.7.1/docs/_static/css/custom.css +88 -0
- valid8r-0.7.1/docs/api/core.rst +760 -0
- valid8r-0.7.1/docs/api/prompt.rst +584 -0
- valid8r-0.7.1/docs/conf.py +195 -0
- valid8r-0.7.1/docs/development/changelog.rst +67 -0
- valid8r-0.7.1/docs/development/contributing.rst +188 -0
- valid8r-0.7.1/docs/development/testing.rst +264 -0
- valid8r-0.7.1/docs/examples/basic_example.rst +486 -0
- valid8r-0.7.1/docs/examples/chaining_validators.rst +476 -0
- valid8r-0.7.1/docs/examples/custom_validators.rst +619 -0
- valid8r-0.7.1/docs/examples/fastapi_integration.rst +481 -0
- valid8r-0.7.1/docs/examples/interactive_prompts.rst +833 -0
- valid8r-0.7.1/docs/index.rst +389 -0
- valid8r-0.7.1/docs/migration-poetry-to-uv.md +310 -0
- valid8r-0.7.1/docs/user_guide/advanced_usage.rst +627 -0
- valid8r-0.7.1/docs/user_guide/getting_started.rst +244 -0
- valid8r-0.7.1/docs/user_guide/maybe_monad.rst +286 -0
- valid8r-0.7.1/docs/user_guide/parsers.rst +964 -0
- valid8r-0.7.1/docs/user_guide/prompting.rst +390 -0
- valid8r-0.7.1/docs/user_guide/testing.rst +227 -0
- valid8r-0.7.1/docs/user_guide/validators.rst +759 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/pyproject.toml +68 -59
- valid8r-0.7.1/scripts/__init__.py +1 -0
- valid8r-0.7.1/scripts/docs.py +45 -0
- valid8r-0.7.1/smoke_test.py +43 -0
- valid8r-0.7.1/tests/bdd/__init__.py +0 -0
- valid8r-0.7.1/tests/bdd/conftest.py +0 -0
- valid8r-0.7.1/tests/bdd/environment.py +40 -0
- valid8r-0.7.1/tests/bdd/features/clean_type_parsing.feature +126 -0
- valid8r-0.7.1/tests/bdd/features/collection_parsing.feature +43 -0
- valid8r-0.7.1/tests/bdd/features/interactive_prompts.feature +43 -0
- valid8r-0.7.1/tests/bdd/features/phone_parsing.feature +426 -0
- valid8r-0.7.1/tests/bdd/features/testing_utilities.feature +47 -0
- valid8r-0.7.1/tests/bdd/features/url_email_parsing.feature +128 -0
- valid8r-0.7.1/tests/bdd/features/validator_combinators.feature +51 -0
- valid8r-0.7.1/tests/bdd/features/validators.feature +55 -0
- valid8r-0.7.1/tests/bdd/features/web_parsers.feature +329 -0
- valid8r-0.7.1/tests/bdd/steps/__init__.py +30 -0
- valid8r-0.7.1/tests/bdd/steps/clean_type_parsing_steps.py +337 -0
- valid8r-0.7.1/tests/bdd/steps/collection_parsing_steps.py +123 -0
- valid8r-0.7.1/tests/bdd/steps/interactive_prompts_steps.py +167 -0
- valid8r-0.7.1/tests/bdd/steps/phone_parsing_steps.py +315 -0
- valid8r-0.7.1/tests/bdd/steps/testing_utilities_steps.py +275 -0
- valid8r-0.7.1/tests/bdd/steps/url_email_parsing_steps.py +244 -0
- valid8r-0.7.1/tests/bdd/steps/validator_combinators_steps.py +121 -0
- valid8r-0.7.1/tests/bdd/steps/validators_steps.py +115 -0
- valid8r-0.7.1/tests/bdd/steps/web_parsers_steps.py +288 -0
- valid8r-0.7.1/tests/integration/__init__.py +0 -0
- valid8r-0.7.1/tests/integration/test_validator.py +233 -0
- valid8r-0.7.1/tests/qa_security_web_parsers.py +447 -0
- valid8r-0.7.1/tests/unit/__init__.py +0 -0
- valid8r-0.7.1/tests/unit/conftest.py +0 -0
- valid8r-0.7.1/tests/unit/test_combinators.py +205 -0
- valid8r-0.7.1/tests/unit/test_decimal_parser.py +95 -0
- valid8r-0.7.1/tests/unit/test_dict_parser.py +114 -0
- valid8r-0.7.1/tests/unit/test_generators.py +268 -0
- valid8r-0.7.1/tests/unit/test_ip_parsers.py +192 -0
- valid8r-0.7.1/tests/unit/test_list_parser.py +61 -0
- valid8r-0.7.1/tests/unit/test_maybe.py +318 -0
- valid8r-0.7.1/tests/unit/test_parsers.py +741 -0
- valid8r-0.7.1/tests/unit/test_phone_parsing.py +345 -0
- valid8r-0.7.1/tests/unit/test_prompt.py +316 -0
- valid8r-0.7.1/tests/unit/test_public_api.py +30 -0
- valid8r-0.7.1/tests/unit/test_testing_utilities.py +290 -0
- valid8r-0.7.1/tests/unit/test_url_email_parsers.py +231 -0
- valid8r-0.7.1/tests/unit/test_uuid_parser.py +64 -0
- valid8r-0.7.1/tests/unit/test_validators.py +341 -0
- valid8r-0.7.1/tests/unit/test_web_parsers.py +172 -0
- valid8r-0.7.1/tox.ini +69 -0
- valid8r-0.7.1/uv.lock +1755 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/valid8r/core/maybe.py +1 -1
- valid8r-0.7.1/valid8r/py.typed +0 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/LICENSE +0 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/README.md +0 -0
- /valid8r-0.7.0/valid8r/py.typed → /valid8r-0.7.1/tests/__init__.py +0 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/valid8r/__init__.py +0 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/valid8r/core/__init__.py +0 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/valid8r/core/combinators.py +0 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/valid8r/core/parsers.py +0 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/valid8r/core/validators.py +0 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/valid8r/prompt/__init__.py +0 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/valid8r/prompt/basic.py +0 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/valid8r/testing/__init__.py +0 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/valid8r/testing/assertions.py +0 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/valid8r/testing/generators.py +0 -0
- {valid8r-0.7.0 → valid8r-0.7.1}/valid8r/testing/mock_input.py +0 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
# .cursorrules
|
|
2
|
+
# Goal: Make Cursor an excellent software engineering companion. Combine general, language-agnostic engineering rules
|
|
3
|
+
# with repo-specific testing/style guidance already in use.
|
|
4
|
+
|
|
5
|
+
Cursor Project Rules
|
|
6
|
+
|
|
7
|
+
[available_instructions]
|
|
8
|
+
|
|
9
|
+
# ---------- Language-agnostic AI operating rules ----------
|
|
10
|
+
ai_alignment:
|
|
11
|
+
# Clarify the ask and fit the context
|
|
12
|
+
• Restate the task, inputs, outputs, constraints, and success criteria before writing code.
|
|
13
|
+
• Detect and follow the project’s stack, runtime, CI, testing style, and naming/layout conventions.
|
|
14
|
+
• Surface tradeoffs: propose a primary approach and at least one viable alternative with pros/cons.
|
|
15
|
+
|
|
16
|
+
ai_small_steps:
|
|
17
|
+
# Keep changes tiny and reversible
|
|
18
|
+
• Prefer minimal, incremental diffs gated by tests; one responsibility per change.
|
|
19
|
+
• Use feature flags/toggles or adapters for risky changes.
|
|
20
|
+
• Avoid speculative generality; implement the smallest thing that could possibly work.
|
|
21
|
+
|
|
22
|
+
ai_correct_first:
|
|
23
|
+
# Make it work before making it fast/fancy
|
|
24
|
+
• Provide runnable examples and tests that demonstrate behavior.
|
|
25
|
+
• Specify behavior via public surfaces; avoid coupling tests to internals.
|
|
26
|
+
• Cover golden path, edge cases, and failure modes.
|
|
27
|
+
|
|
28
|
+
ai_readability:
|
|
29
|
+
# Clear beats clever
|
|
30
|
+
• Favor descriptive names, short functions, cohesive modules.
|
|
31
|
+
• Remove duplication; maintain a single source of truth.
|
|
32
|
+
• Isolate complex logic behind simple interfaces.
|
|
33
|
+
|
|
34
|
+
ai_design_for_change:
|
|
35
|
+
# Stable boundaries, evolvable internals
|
|
36
|
+
• Program to interfaces/abstractions; hide implementation details.
|
|
37
|
+
• Validate at the edges; keep core logic working on trusted data.
|
|
38
|
+
• For legacy code, prefer strangler patterns and incremental replacement over rewrites.
|
|
39
|
+
|
|
40
|
+
ai_refactoring:
|
|
41
|
+
# Improve safely with a net
|
|
42
|
+
• Refactor only with passing tests; preserve behavior.
|
|
43
|
+
• Apply the scout rule: leave touched code cleaner.
|
|
44
|
+
• For perf-sensitive areas, capture before/after metrics.
|
|
45
|
+
|
|
46
|
+
ai_security_reliability:
|
|
47
|
+
# Non-optional requirements
|
|
48
|
+
• Enforce least privilege for code, data, secrets, and CI.
|
|
49
|
+
• Validate and sanitize all inputs (type/range/format); fail closed with secure defaults.
|
|
50
|
+
• Add observability at service/module boundaries: structured logs, key metrics, trace points.
|
|
51
|
+
|
|
52
|
+
ai_performance:
|
|
53
|
+
# Pragmatic optimization
|
|
54
|
+
• Make it work, then measure; optimize only with evidence.
|
|
55
|
+
• Prefer simpler algorithms until data proves otherwise.
|
|
56
|
+
• Call out expected time/space/IO complexity and resource budgets.
|
|
57
|
+
|
|
58
|
+
ai_dependency_hygiene:
|
|
59
|
+
# Keep the supply chain tidy
|
|
60
|
+
• Prefer standard libraries and fewer dependencies when reasonable.
|
|
61
|
+
• Track versions, licenses, and security advisories; pin/lock where appropriate.
|
|
62
|
+
• Wrap third-party libraries behind thin, swappable adapters.
|
|
63
|
+
|
|
64
|
+
ai_docs:
|
|
65
|
+
# Documentation that earns its keep
|
|
66
|
+
• Update API/module docs when behavior or surfaces change; describe behavior, inputs, outputs, invariants.
|
|
67
|
+
• Prefer runnable examples to prose where possible.
|
|
68
|
+
• Delete or update stale docs; stale docs are bugs.
|
|
69
|
+
|
|
70
|
+
ai_vcs_etiquette:
|
|
71
|
+
# Version control best practices
|
|
72
|
+
• Make atomic commits with messages that explain “why” before “what.”
|
|
73
|
+
• Ensure tests/linters/static analysis pass locally before opening a PR/MR.
|
|
74
|
+
• PR/MR descriptions should include context, decisions, risks, and validation notes.
|
|
75
|
+
|
|
76
|
+
ai_collaboration:
|
|
77
|
+
# Human-friendly by default
|
|
78
|
+
• Ask clarifying questions when requirements are ambiguous; do not guess silently.
|
|
79
|
+
• Offer 2–3 options with consequences when tradeoffs exist.
|
|
80
|
+
• Match the project’s code style, directory layout, and tooling.
|
|
81
|
+
|
|
82
|
+
ai_ethics_guardrails:
|
|
83
|
+
# Do the right thing
|
|
84
|
+
• Respect licenses; verify compatibility before suggesting code.
|
|
85
|
+
• Attribute significant ideas/snippets that are not original.
|
|
86
|
+
• Never expose secrets or PII in code, logs, examples, or test data.
|
|
87
|
+
|
|
88
|
+
ai_definition_of_done:
|
|
89
|
+
# Quality bar for AI-produced changes
|
|
90
|
+
• Task restated; constraints and acceptance criteria confirmed.
|
|
91
|
+
• Approach and alternatives documented (in PR/MR or design note).
|
|
92
|
+
• Code compiles/runs cleanly; linting/formatting/static analysis are clean.
|
|
93
|
+
• Tests exist, pass locally, and demonstrate behavior and edge cases.
|
|
94
|
+
• Security, error handling, and observability addressed where relevant.
|
|
95
|
+
• Public surfaces documented; docs/doctests updated.
|
|
96
|
+
|
|
97
|
+
ai_escalation:
|
|
98
|
+
# Know when to pause and propose a design
|
|
99
|
+
• Conflicting requirements or missing success criteria.
|
|
100
|
+
• Meaningful risk of data loss/security exposure without a rollback plan.
|
|
101
|
+
• Changes imply architectural shifts; produce a short design note first.
|
|
102
|
+
|
|
103
|
+
ai_operating_sequence:
|
|
104
|
+
# Step-by-step workflow for Cursor
|
|
105
|
+
1. Confirm: restate task/constraints/acceptance criteria; ask blocking questions.
|
|
106
|
+
2. Plan: outline a tiny increment that delivers user value; note tradeoffs.
|
|
107
|
+
3. Propose: show tests first, then implementation; keep diff small.
|
|
108
|
+
4. Validate: enumerate edge cases, security checks, and perf notes.
|
|
109
|
+
5. Refine: simplify names/structure; remove duplication.
|
|
110
|
+
6. Deliver: provide patch + tests + concise PR description with rationale and follow-ups.
|
|
111
|
+
7. Iterate: accept feedback; repeat in small steps.
|
|
112
|
+
|
|
113
|
+
# ---------- Existing repo-specific testing/style guidance ----------
|
|
114
|
+
pytest_naming:
|
|
115
|
+
Use pytest discovery configuration from pyproject.toml:
|
|
116
|
+
• test paths: tests
|
|
117
|
+
• test files: it_*.py, test_*.py
|
|
118
|
+
• test classes: Describe[A-Z]*
|
|
119
|
+
• test functions: it_*
|
|
120
|
+
When creating new tests:
|
|
121
|
+
• Mirror src/valid8r/... structure under tests/....
|
|
122
|
+
• Use classes like DescribeThing with methods it_describes_behavior.
|
|
123
|
+
• Prefer @pytest.mark.parametrize (see parametrization_policy).
|
|
124
|
+
• For async code, mark tests with @pytest.mark.asyncio.
|
|
125
|
+
|
|
126
|
+
testing_principles:
|
|
127
|
+
Adopt Software Engineering at Google testing practices:
|
|
128
|
+
• Test behavior, not implementation (assert on public surface; avoid peeking at internals/private state).
|
|
129
|
+
• Small and hermetic: no network, no real filesystem (use tmp_path), no time dependence (inject a clock or freeze time).
|
|
130
|
+
• Deterministic: seed randomness; avoid sleeps and flakiness; keep timeouts tight.
|
|
131
|
+
• DAMP not DRY in tests: prioritize clarity over reuse; duplication in tests is fine when it improves readability.
|
|
132
|
+
• One concept per test: each test should fail for a single understandable reason.
|
|
133
|
+
• Clear names as specification: DescribeFoo.it_rejects_empty_input style; prefer long, descriptive names.
|
|
134
|
+
• Use fakes over mocks when possible; prefer dependency injection to make seams explicit.
|
|
135
|
+
• Don’t assert on log messages unless the log is a defined behavior.
|
|
136
|
+
• Coverage is a byproduct, not the goal; prioritize risk and critical paths.
|
|
137
|
+
• Keep fixtures simple and local; avoid deep fixture hierarchies that obscure intent.
|
|
138
|
+
|
|
139
|
+
fixtures_and_mocks:
|
|
140
|
+
• Prefer pytest fixtures for setup; avoid xUnit setup/teardown.
|
|
141
|
+
• Use MagicMock/AsyncMock sparingly; favor fakes/simple test doubles.
|
|
142
|
+
• For static data, use pytest_lambda.static_fixture.
|
|
143
|
+
• Use monkeypatch for env vars and module-level patching.
|
|
144
|
+
• Isolate global state; reset or inject dependencies per test.
|
|
145
|
+
|
|
146
|
+
io_and_time_isolation:
|
|
147
|
+
• Use tmp_path/tmp_path_factory for any filesystem work.
|
|
148
|
+
• For time, inject a clock callable or use freezegun.freeze_time in tests.
|
|
149
|
+
|
|
150
|
+
parametrization_policy:
|
|
151
|
+
Prefer parametrized tests. Use indirect parametrization when constructing objects/fixtures is non-trivial or when parameters map to fixtures.
|
|
152
|
+
|
|
153
|
+
Direct example:
|
|
154
|
+
|
|
155
|
+
@pytest.mark.parametrize(
|
|
156
|
+
"raw,expected",
|
|
157
|
+
[
|
|
158
|
+
pytest.param("42", 42, id="pos-42"),
|
|
159
|
+
pytest.param("0", 0, id="zero"),
|
|
160
|
+
pytest.param("-1", -1, id="neg-1"),
|
|
161
|
+
],
|
|
162
|
+
)
|
|
163
|
+
def it_parses_integers(raw, expected):
|
|
164
|
+
assert parsers.int(raw) == expected
|
|
165
|
+
|
|
166
|
+
Indirect example:
|
|
167
|
+
|
|
168
|
+
@pytest.fixture
|
|
169
|
+
def user(request):
|
|
170
|
+
return User(name=request.param["name"], role=request.param["role"])
|
|
171
|
+
|
|
172
|
+
@pytest.mark.parametrize(
|
|
173
|
+
"user,allowed",
|
|
174
|
+
[
|
|
175
|
+
pytest.param({"name": "alice", "role": "admin"}, True, id="admin-allowed"),
|
|
176
|
+
pytest.param({"name": "bob", "role": "viewer"}, False, id="viewer-denied"),
|
|
177
|
+
],
|
|
178
|
+
indirect=["user"],
|
|
179
|
+
)
|
|
180
|
+
def it_checks_access(user, allowed):
|
|
181
|
+
assert can_access(user) is allowed
|
|
182
|
+
|
|
183
|
+
IDs:
|
|
184
|
+
Provide excellent, human-readable ids for each case:
|
|
185
|
+
• Short, kebab-case descriptions of behavior (e.g., empty-input, admin-allowed, viewer-denied).
|
|
186
|
+
• Include critical parameter hints when useful (e.g., neg-1, boundary-0, unicode-snowman).
|
|
187
|
+
• Avoid opaque numeric-only ids.
|
|
188
|
+
|
|
189
|
+
public_api_reexports:
|
|
190
|
+
valid8r top-level must re-export:
|
|
191
|
+
• modules: parsers, validators, combinators, and prompt (with ask exposed in valid8r.prompt).
|
|
192
|
+
• types: Maybe from valid8r.core.maybe.
|
|
193
|
+
Maintain backward compatibility for deep imports.
|
|
194
|
+
When changing exports:
|
|
195
|
+
• Update __all__ in valid8r/__init__.py and valid8r/prompt/__init__.py.
|
|
196
|
+
• Update public API tests (see public_api_test_template).
|
|
197
|
+
• Public API code should have high-quality docstrings and doctests (see public_api_docs).
|
|
198
|
+
|
|
199
|
+
Mini __init__.py export pattern:
|
|
200
|
+
|
|
201
|
+
# valid8r/__init__.py
|
|
202
|
+
from __future__ import annotations
|
|
203
|
+
|
|
204
|
+
from . import parsers, validators, combinators, prompt
|
|
205
|
+
from .core.maybe import Maybe
|
|
206
|
+
|
|
207
|
+
__all__ = [
|
|
208
|
+
"parsers",
|
|
209
|
+
"validators",
|
|
210
|
+
"combinators",
|
|
211
|
+
"prompt",
|
|
212
|
+
"Maybe",
|
|
213
|
+
]
|
|
214
|
+
|
|
215
|
+
# valid8r/prompt/__init__.py
|
|
216
|
+
from __future__ import annotations
|
|
217
|
+
|
|
218
|
+
from .ask import ask
|
|
219
|
+
|
|
220
|
+
__all__ = ["ask"]
|
|
221
|
+
|
|
222
|
+
Tiny indirect parametrized test using the public API:
|
|
223
|
+
|
|
224
|
+
import pytest
|
|
225
|
+
from valid8r import prompt
|
|
226
|
+
|
|
227
|
+
@pytest.fixture
|
|
228
|
+
def question(request):
|
|
229
|
+
# Imagine 'ask' uses this question text internally
|
|
230
|
+
return request.param
|
|
231
|
+
|
|
232
|
+
@pytest.mark.parametrize(
|
|
233
|
+
"question,expected_callable",
|
|
234
|
+
[
|
|
235
|
+
pytest.param("What is your name?", True, id="simple-question"),
|
|
236
|
+
pytest.param("Choose an option: [a/b]", True, id="multiple-choice"),
|
|
237
|
+
],
|
|
238
|
+
indirect=["question"],
|
|
239
|
+
)
|
|
240
|
+
def it_exposes_prompt_ask_as_callable(question, expected_callable):
|
|
241
|
+
# Public API behavior: 'ask' must always be callable
|
|
242
|
+
assert callable(prompt.ask) is expected_callable
|
|
243
|
+
|
|
244
|
+
public_api_test_template:
|
|
245
|
+
Create/maintain tests/it_public_api.py:
|
|
246
|
+
|
|
247
|
+
import importlib
|
|
248
|
+
|
|
249
|
+
def it_exposes_expected_symbols():
|
|
250
|
+
v = importlib.import_module("valid8r")
|
|
251
|
+
assert hasattr(v, "parsers")
|
|
252
|
+
assert hasattr(v, "validators")
|
|
253
|
+
assert hasattr(v, "combinators")
|
|
254
|
+
from valid8r import prompt, Maybe # noqa: F401
|
|
255
|
+
assert callable(prompt.ask)
|
|
256
|
+
|
|
257
|
+
def it_preserves_deep_imports_for_backcompat():
|
|
258
|
+
assert importlib.import_module("valid8r.core.maybe").Maybe is not None
|
|
259
|
+
|
|
260
|
+
public_api_docs:
|
|
261
|
+
Public API must include detailed docstrings with realistic doctests (serve as examples and executable checks).
|
|
262
|
+
• Write WHY in comments/docstrings; code should explain WHAT via names/types.
|
|
263
|
+
• Example:
|
|
264
|
+
|
|
265
|
+
def parse_positive_int(text: str) -> int:
|
|
266
|
+
"""
|
|
267
|
+
Parse a string into a positive integer.
|
|
268
|
+
|
|
269
|
+
Accepts optional leading/trailing whitespace and '+' sign.
|
|
270
|
+
Raises ValueError for non-integer or non-positive values.
|
|
271
|
+
|
|
272
|
+
Examples:
|
|
273
|
+
>>> parse_positive_int(" +7 ")
|
|
274
|
+
7
|
|
275
|
+
>>> parse_positive_int("0")
|
|
276
|
+
Traceback (most recent call last):
|
|
277
|
+
...
|
|
278
|
+
ValueError: expected a positive integer
|
|
279
|
+
"""
|
|
280
|
+
...
|
|
281
|
+
|
|
282
|
+
• Keep doctests fast and hermetic; avoid I/O and network.
|
|
283
|
+
|
|
284
|
+
comment_policy:
|
|
285
|
+
Keep comments minimal. Only explain WHY something is done if it is non-obvious or encodes a business rule.
|
|
286
|
+
• Do not narrate obvious steps.
|
|
287
|
+
• Public API is the exception: include rich docstrings + doctests.
|
|
288
|
+
|
|
289
|
+
typing_and_style:
|
|
290
|
+
• All new/changed Python must be fully type-annotated.
|
|
291
|
+
• Code must pass mypy (repo config) and ruff (repo rules).
|
|
292
|
+
• Avoid unrelated reformatting; only change lines necessary for the task.
|
|
293
|
+
|
|
294
|
+
run_tests_locally:
|
|
295
|
+
In constrained environments without pytest installed, create smoke_test.py:
|
|
296
|
+
|
|
297
|
+
from valid8r import parsers, validators, prompt, Maybe
|
|
298
|
+
assert callable(prompt.ask)
|
|
299
|
+
print("ok")
|
|
300
|
+
|
|
301
|
+
Make it runnable with: python smoke_test.py
|
|
302
|
+
|
|
303
|
+
ci_expectations:
|
|
304
|
+
• Follow TDD: write a failing test, write the minimum code to pass, then refactor both.
|
|
305
|
+
• Unit tests should be fast (<1s each where practical); mark slower ones @pytest.mark.slow.
|
|
306
|
+
• Tests are hermetic by default; mark any external integrations as @pytest.mark.integration.
|
|
307
|
+
|
|
308
|
+
# ---------- Defaults applied to all requests ----------
|
|
309
|
+
[default]
|
|
310
|
+
# Operating mode summary (language-agnostic)
|
|
311
|
+
• Apply ai_operating_sequence; keep changes small and reversible.
|
|
312
|
+
• Follow ai_alignment, ai_correct_first, ai_readability, ai_design_for_change.
|
|
313
|
+
• Enforce ai_security_reliability, ai_performance, ai_dependency_hygiene.
|
|
314
|
+
• Honor ai_vcs_etiquette, ai_docs, ai_collaboration, ai_ethics_guardrails.
|
|
315
|
+
• Meet ai_definition_of_done; use ai_escalation when needed.
|
|
316
|
+
|
|
317
|
+
# Repo-specific testing/style
|
|
318
|
+
• Use Describe*/it_* names that read like a spec; mirror src under tests.
|
|
319
|
+
• Apply Google testing principles: behavior-based, small, hermetic, deterministic, DAMP.
|
|
320
|
+
• Prefer parametrization; use indirect parametrization for non-trivial setup; use pytest.param with excellent ids.
|
|
321
|
+
• Keep comments minimal (WHY only). Public API gets rich docstrings + doctests.
|
|
322
|
+
• Prefer fixtures + (Async)MagicMock (sparingly) + pytest_lambda.static_fixture.
|
|
323
|
+
• Use tmp_path, monkeypatch, and frozen/injected time for isolation.
|
|
324
|
+
• Maintain public API exports and back-compat; keep public API tests and docs in sync.
|
|
325
|
+
• Match repo style (ruff) and types (mypy); avoid drive-by reformatting.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# CI/CD Pipeline Test
|
|
2
|
+
|
|
3
|
+
This file was created to test the automated CI/CD pipeline for valid8r.
|
|
4
|
+
|
|
5
|
+
## Test Purpose
|
|
6
|
+
|
|
7
|
+
Verify that the complete automation workflow functions correctly:
|
|
8
|
+
|
|
9
|
+
1. ✅ CI runs on PR (tests, linting, type checking)
|
|
10
|
+
2. ✅ Auto version bump on merge to main (0.1.0 → 0.2.0)
|
|
11
|
+
3. ✅ GitHub Release created automatically
|
|
12
|
+
4. ✅ Package builds and publishes to PyPI
|
|
13
|
+
5. ✅ `pip install valid8r` installs the latest version
|
|
14
|
+
|
|
15
|
+
## Test Date
|
|
16
|
+
|
|
17
|
+
2025-10-21
|
|
18
|
+
|
|
19
|
+
## Expected Result
|
|
20
|
+
|
|
21
|
+
- Version bumps from 0.1.0 to 0.2.0 (feat: triggers minor bump)
|
|
22
|
+
- GitHub Release created with changelog
|
|
23
|
+
- Package available on PyPI
|
|
24
|
+
- Installable via: `pip install valid8r==0.2.0`
|
|
25
|
+
|
|
26
|
+
## Notes
|
|
27
|
+
|
|
28
|
+
This test uses a conventional commit with `feat:` prefix to trigger a minor version bump.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# CODEOWNERS
|
|
2
|
+
# This file defines code ownership for the valid8r project.
|
|
3
|
+
# Each line is a file pattern followed by one or more owners.
|
|
4
|
+
# These owners will be automatically requested for review when a PR modifies matching files.
|
|
5
|
+
#
|
|
6
|
+
# More information: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
|
|
7
|
+
|
|
8
|
+
# Default owner for everything in the repo
|
|
9
|
+
* @mikelane
|
|
10
|
+
|
|
11
|
+
# Core library code
|
|
12
|
+
/valid8r/core/ @mikelane
|
|
13
|
+
/valid8r/prompt/ @mikelane
|
|
14
|
+
/valid8r/testing/ @mikelane
|
|
15
|
+
|
|
16
|
+
# Tests
|
|
17
|
+
/tests/ @mikelane
|
|
18
|
+
|
|
19
|
+
# Documentation
|
|
20
|
+
/docs/ @mikelane
|
|
21
|
+
*.md @mikelane
|
|
22
|
+
CLAUDE.md @mikelane
|
|
23
|
+
|
|
24
|
+
# Configuration files
|
|
25
|
+
pyproject.toml @mikelane
|
|
26
|
+
poetry.lock @mikelane
|
|
27
|
+
tox.ini @mikelane
|
|
28
|
+
|
|
29
|
+
# GitHub workflows and templates
|
|
30
|
+
/.github/ @mikelane
|
|
31
|
+
|
|
32
|
+
# CI/CD
|
|
33
|
+
/.github/workflows/ @mikelane
|