Commit 81022e6
feat: migrate data models from dataclasses to Pydantic v2 (#306)
* chore: capture regression baselines for Pydantic v2 migration
Capture CLI output (status, report adoc/md, export) for all 12 in-repo
test datasets + reqstool-demo + filtered exports + generate-json alias.
Also save full pytest output (212 passed, 2 skipped, 92% coverage).
These baselines will be used to verify zero regressions after each
migration phase. Remove before merging to main.
Ref: #140
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: correct JSON Schema design issues in 3 schema files
Fix 1: common.schema.json — move requirement_ids, svc_ids, mvr_ids
from patternProperties to properties. These are fixed field names, not
dynamic keys. The regex also had an operator-precedence bug that
accidentally accepted malformed keys.
Fix 2: annotations.schema.json — move implementations and tests from
patternProperties to properties. Same issue as Fix 1.
Fix 3: reqstool_config.schema.json — move misplaced
additionalProperties:false from inside properties block to the
resources sub-object where it belongs.
All fixes are non-breaking: every valid YAML is still accepted.
Regression verified: 212 tests pass, CLI output identical across
all 12 datasets + reqstool-demo.
Ref: #140
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: add Pydantic v2 deps and generate models from JSON Schemas
- Add pydantic==2.12.5 to project dependencies
- Add datamodel-code-generator==0.54.1 to dev dependencies
- Add hatch dev script 'codegen' for reproducible model generation
- Generate Pydantic v2 models from all 6 JSON Schemas
- All 49 YAML fixtures validate against generated models (100% pass)
- All 212 existing tests pass unchanged
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: migrate model generators to use Pydantic model_validate()
- MVRsModelGenerator: uses generated MVRsPydanticModel
- AnnotationsModelGenerator: uses generated AnnotationsPydanticModel
- SVCsModelGenerator: uses generated SVCsPydanticModel
- RequirementsModelGenerator: uses generated RequirementsPydanticModel
All generators now parse YAML via model_validate() instead of manual
dict['key'] access. Internal dataclass models (RequirementData, SVCData,
etc.) are preserved — generators convert from Pydantic to dataclass.
212 tests pass, zero regression diffs across all CLI commands.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: replace jsonpickle with stdlib json serialization
- Remove jsonpickle dependency and custom handlers (UrnIdHandler,
RevisionHandler, JsonEnumHandler)
- Add _serialize() function using dataclasses.fields() for recursive
serialization of UrnId, Version, Enum, and nested dataclasses
- Remove post-processing regex hack for json:// artifacts
- Fix: LIFECYCLESTATE and IMPLEMENTATION enums now serialize to clean
values instead of leaking jsonpickle internals (_value_, _name_,
__objclass__, py/type)
- All other JSON fields remain structurally identical
212 tests pass, reports/status output byte-identical to baseline.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: convert data model dataclasses to Pydantic BaseModel
Convert all @DataClass data models to Pydantic v2 BaseModel:
- UrnId: ConfigDict(frozen=True) for hashability
- LifecycleData: fix reason default (was type object)
- RequirementData/SVCData/MVRData/AnnotationData/TestData: strict Dict[UrnId, X] types
- CombinedIndexedDataset/RawDataset: Pydantic with Optional fields
- StatisticsContainer: rename _private fields to public (Pydantic PrivateAttr incompatible)
- Filters, configs, indata: BaseModel with model_post_init
- Replace dataclasses.replace() with model_copy(update=...)
- Fix annotations nesting bug: append->extend (List[List[T]] -> List[T])
- Fix type annotations: Dict[str,...] -> Dict[UrnId,...] where UrnId keys used
- Fix CombinedRequirementTestItem defaults (was type objects)
- Use VersionField (BeforeValidator) for packaging.version.Version coercion
- Access model_fields on class not instance: type(obj).model_fields
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: remove unnecessary @DataClass decorators and dead code
- Remove @DataClass from implementations.py and imports.py subclasses
(empty classes inheriting from LocationResolver, no own fields)
- Remove is_dataclass fallback from generate_json.py _serialize()
(dead code — CombinedIndexedDataset has no dataclass fields)
- Update CONTRIBUTING.md with model generation documentation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: add frozen models, Pydantic serializers, and baselines docs
- Add frozen=True to immutable data models: RequirementData, ReferenceData,
MetaData, MVRData, AnnotationData, TestData, LifecycleData
- Add model_serializer to UrnId for automatic str serialization
- Add PlainSerializer to VersionField for {major, minor, patch} output
- Add field_serializer for sorted Set serialization
- Replace custom _serialize() in generate_json.py with model_dump(mode='json')
- Deduplicate VersionField: svcs.py now imports from requirements.py
- Add baselines/README.md with regression testing instructions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: migrate location classes from dataclass to Pydantic
- Convert LocationInterface, LocationResolver, and all location classes
(GitLocation, LocalLocation, MavenLocation, PypiLocation, LocalMavenLocation,
LocalPypiLocation) from @DataClass to Pydantic BaseModel
- Replace dataclasses.replace() with model_copy(update=...) in LocationResolver
- Replace __post_init__ with model_post_init in LocationResolver
- Rename _current_unresolved to current_unresolved (Pydantic PrivateAttr)
- Make env_token Optional[str] in GitLocation and MavenLocation
- Zero @DataClass usage remains in the codebase (except model generators
which are infrastructure, not data models)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: rename common/dataclasses/ to common/models/
After the Pydantic v2 migration, this directory contains Pydantic BaseModel
classes (UrnId, LifecycleData), not Python dataclasses. Rename for clarity.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* style: fix formatting and remove unused imports
Apply black formatting and remove unused imports flagged by flake8:
- PrivateAttr, model_validator (group_by.py)
- Requirement (annotations_model_generator.py)
- field (indexed_dataset_filter_processor.py)
- LOCATIONTYPES (requirements_model_generator.py)
- PrivateAttr (requirements_indata.py)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* ci: add codegen-check to validate generated models stay in sync
- Add codegen-check hatch script (codegen + --check + --disable-timestamp)
- Add --disable-timestamp to codegen script to avoid timestamp-only diffs
- Add validation step to lint.yml workflow
- Regenerate models with current datamodel-code-generator version
CI will now fail if JSON Schemas are changed but generated Pydantic
models are not regenerated.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: count 1 per requirement with implementation instead of summing annotations
The TotalStatisticsItem.update() was accumulating all annotation counts
instead of counting 1 per requirement that has any implementation, causing
the "Implemented" count to exceed total requirements.
Also changed the Implementation column from text (Implemented/Missing) to
numeric count, and added implementation total to the Total row.
Signed-off-by: jimisola <jimisola@jimisola.com>
---------
Signed-off-by: jimisola <jimisola@jimisola.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Jimisola Laursen <jimisola.laursen@resurs.se>1 parent e3c934b commit 81022e6
188 files changed
Lines changed: 11196 additions & 644 deletions
File tree
- .github/workflows
- baselines
- src/reqstool
- commands
- generate_json
- report
- criterias
- status
- common
- models
- validators
- expression_languages
- filters
- location_resolver
- locations
- model_generators
- models
- generated
- reqstool_config
- requirements_indata
- resources/schemas/v1
- tests/unit/reqstool
- commands/status
- common
- models
- validators
- expression_languages
- filters
- model_generators
- models
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| 26 | + | |
| 27 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
0 commit comments