Skip to content

Conversation

@koxudaxi
Copy link
Owner

@koxudaxi koxudaxi commented Jan 5, 2026

Summary by CodeRabbit

  • New Features

    • Added automatic detection and support for multiple JSON Schema versions (draft-04 through 2020-12) and OpenAPI versions (3.0 and 3.1).
    • Enhanced version-aware feature handling for improved cross-version schema compatibility.
  • Tests

    • Added comprehensive test coverage for version detection and schema feature validation.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 5, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This PR introduces schema versioning support and feature detection for JSON Schema and OpenAPI. It exposes new public enums, adds version detection utilities, and implements version-aware feature flags and data format mappings across parser classes.

Changes

Cohort / File(s) Summary
Public API exports
src/datamodel_code_generator/__init__.py
Exposes three new enums (JsonSchemaVersion, OpenAPIVersion, VersionMode) and two lazy-loaded detection functions (detect_jsonschema_version, detect_openapi_version) to public API.
New enum definitions
src/datamodel_code_generator/enums.py
Adds three enums for version tracking: JsonSchemaVersion (draft-04 through 2020-12 with auto-detection), OpenAPIVersion (3.0, 3.1, auto), and VersionMode (lenient, strict). Updates __all__ exports.
JSON Schema parser versioning
src/datamodel_code_generator/parser/jsonschema.py
Introduces schema_features cached property for version-aware behavior. Extends _get_type with optional data_formats parameter. Refactors type resolution via _data_formats property. Adds version-aware schema path handling (schema_paths), array item detection (_get_array_items), and root ID context resolution.
OpenAPI parser versioning
src/datamodel_code_generator/parser/openapi.py
Adds schema_features cached property deriving OpenAPI-specific features from detected version. Imports cached_property, OpenAPIVersion, and type-checking import for OpenAPISchemaFeatures.
New schema versioning module
src/datamodel_code_generator/parser/schema_version.py
Creates comprehensive versioning logic: JsonSchemaFeatures and OpenAPISchemaFeatures dataclasses with feature flags and from_version()/from_openapi_version() classmethods. Implements version detection (detect_jsonschema_version, detect_openapi_version). Provides data format mappings via get_data_formats() function.
Test coverage
tests/parser/test_schema_version.py
Comprehensive test suite covering version detection across all JSON Schema drafts, OpenAPI versions, feature flag inheritance, data format mappings, and parser-specific feature detection.
Test fixture cleanup
tests/data/expected/main/openapi/same_name_objects.py
Removes Error and Resolved model classes from expected output fixture.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • koxudaxi/datamodel-code-generator#2877: Modifies parser class initialization and configuration handling, which could interact with the new schema-versioning properties added to JsonSchemaParser and OpenAPIParser.

Suggested labels

breaking-change-analyzed

Poem

🐰 A Schema's Tale

Versions hop through drafts and specs,
Four-to-twenty features check!
Features flag the paths we take,
OpenAPI and JSON shake.
Schema speaks in coded tongue—
Version bells have rung! 🔔

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: introducing version-specific schema processing capabilities through a new schema_features property/system across multiple parser modules.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 5, 2026

📚 Docs Preview: https://pr-2934.datamodel-code-generator.pages.dev

from datamodel_code_generator.enums import JsonSchemaVersion, OpenAPIVersion

if TYPE_CHECKING:
from datamodel_code_generator.types import Types

Check notice

Code scanning / CodeQL

Unused import

Import of 'Types' is not used.

Copilot Autofix

AI 3 days ago

To fix the problem, remove the unused import of Types from datamodel_code_generator.types inside the if TYPE_CHECKING: block. This resolves the static analysis warning without changing any runtime behavior, since if TYPE_CHECKING: blocks are ignored at runtime.

Concretely, in src/datamodel_code_generator/parser/schema_version.py, delete the line from datamodel_code_generator.types import Types that appears under if TYPE_CHECKING:. No other code changes or new imports are needed.

Suggested changeset 1
src/datamodel_code_generator/parser/schema_version.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/datamodel_code_generator/parser/schema_version.py b/src/datamodel_code_generator/parser/schema_version.py
--- a/src/datamodel_code_generator/parser/schema_version.py
+++ b/src/datamodel_code_generator/parser/schema_version.py
@@ -13,7 +13,7 @@
 from datamodel_code_generator.enums import JsonSchemaVersion, OpenAPIVersion
 
 if TYPE_CHECKING:
-    from datamodel_code_generator.types import Types
+    ...
 
 
 @dataclass(frozen=True)
EOF
@@ -13,7 +13,7 @@
from datamodel_code_generator.enums import JsonSchemaVersion, OpenAPIVersion

if TYPE_CHECKING:
from datamodel_code_generator.types import Types
...


@dataclass(frozen=True)
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
discriminator_support: bool

@classmethod
def from_openapi_version(cls, version: OpenAPIVersion) -> OpenAPISchemaFeatures:

Check notice

Code scanning / CodeQL

Explicit returns mixed with implicit (fall through) returns

Mixing implicit and explicit returns may indicate an error, as implicit returns always return None.

Copilot Autofix

AI 3 days ago

In general, to fix “explicit returns mixed with implicit returns”, ensure that every code path in a function with a non-None return annotation ends with an explicit return, including the fall-through at the end of the function. This avoids any possibility of returning None implicitly.

For OpenAPISchemaFeatures.from_openapi_version, the match currently has case OpenAPIVersion.V30: and a fallback case _: that both return cls(...). To eliminate any potential implicit return, we can simply add a final return after the match that returns a sensible default instance. Because the case _: branch already represents the default behavior, the safest and behavior-preserving change is to construct and return the same values as in the wildcard case at the end of the function. In practice, this return should be unreachable, but it satisfies the analyzer and guarantees the function never returns None, even if the match were later changed in a way that forgets a return.

Concretely, within src/datamodel_code_generator/parser/schema_version.py, after line 123 (the end of the case _: block in from_openapi_version), add an explicit return cls(...) with the same arguments as in the wildcard case. No new imports or additional helpers are needed.

Suggested changeset 1
src/datamodel_code_generator/parser/schema_version.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/datamodel_code_generator/parser/schema_version.py b/src/datamodel_code_generator/parser/schema_version.py
--- a/src/datamodel_code_generator/parser/schema_version.py
+++ b/src/datamodel_code_generator/parser/schema_version.py
@@ -121,6 +121,17 @@
                     nullable_keyword=False,
                     discriminator_support=True,
                 )
+        # Fallback return to avoid any implicit None; mirrors the default case.
+        return cls(
+            null_in_type_array=True,
+            defs_not_definitions=True,
+            prefix_items=True,
+            boolean_schemas=True,
+            id_field="$id",
+            definitions_key="$defs",
+            nullable_keyword=False,
+            discriminator_support=True,
+        )
 
 
 SchemaFeaturesT = TypeVar("SchemaFeaturesT", bound=JsonSchemaFeatures)
EOF
@@ -121,6 +121,17 @@
nullable_keyword=False,
discriminator_support=True,
)
# Fallback return to avoid any implicit None; mirrors the default case.
return cls(
null_in_type_array=True,
defs_not_definitions=True,
prefix_items=True,
boolean_schemas=True,
id_field="$id",
definitions_key="$defs",
nullable_keyword=False,
discriminator_support=True,
)


SchemaFeaturesT = TypeVar("SchemaFeaturesT", bound=JsonSchemaFeatures)
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
@codspeed-hq
Copy link

codspeed-hq bot commented Jan 5, 2026

CodSpeed Performance Report

Merging #2934 will not alter performance

Comparing feature/version-specific-processing (dd2aef2) with feature/schema-object-refactoring (811cf13)

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

Summary

✅ 11 untouched
⏩ 98 skipped1

Footnotes

  1. 98 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
src/datamodel_code_generator/parser/schema_version.py (1)

190-190: Remove unused noqa directives.

The # noqa: PLC0415 comments on lines 190 and 251 are not needed as the PLC0415 rule is not enabled in your Ruff configuration.

🔎 Proposed fix
-    from datamodel_code_generator.types import Types  # noqa: PLC0415
+    from datamodel_code_generator.types import Types

Apply the same change on line 251.

Also applies to: 251-251

src/datamodel_code_generator/parser/openapi.py (1)

176-176: Remove unused noqa directive.

The # noqa: PLC0415 comment on line 176 is not needed as the PLC0415 rule is not enabled.

🔎 Proposed fix
-        from datamodel_code_generator.parser.schema_version import (  # noqa: PLC0415
+        from datamodel_code_generator.parser.schema_version import (
             OpenAPISchemaFeatures,
             detect_openapi_version,
         )
src/datamodel_code_generator/__init__.py (1)

46-46: LGTM! Clean public API exposure.

The new version enums and detection functions are properly integrated:

  • Enums imported from enums module
  • Detection functions configured for lazy loading
  • All additions included in __all__ exports

The lazy import pattern is consistent with existing entries like generate_dynamic_models.

However, the # noqa: F822 comments on lines 987-989 can be removed as Ruff is not flagging these lines:

🔎 Proposed fix
-    "clear_dynamic_models_cache",  # noqa: F822
-    "detect_jsonschema_version",  # noqa: F822
-    "detect_openapi_version",  # noqa: F822
+    "clear_dynamic_models_cache",
+    "detect_jsonschema_version",
+    "detect_openapi_version",

Also applies to: 50-50, 54-54, 936-937, 974-974, 979-979, 986-986, 988-989

src/datamodel_code_generator/parser/jsonschema.py (1)

929-941: Consider using _get_array_items helper in existing code.

The _get_array_items staticmethod correctly handles version-aware array item resolution (prefixItems vs items), but it's not called anywhere in this file.

Similar logic exists in parse_array_fields (lines 2959-2970) that could potentially be refactored to use this helper for consistency and DRY.

Is this method intended for:

  1. Future refactoring of parse_array_fields?
  2. Use by openapi.py (listed as a dependent)?
  3. Public API for version-aware item handling?

If not actively used yet, consider either integrating it now or adding a TODO comment explaining its intended use.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between da32bb7 and 2e1b066.

📒 Files selected for processing (7)
  • src/datamodel_code_generator/__init__.py
  • src/datamodel_code_generator/enums.py
  • src/datamodel_code_generator/parser/jsonschema.py
  • src/datamodel_code_generator/parser/openapi.py
  • src/datamodel_code_generator/parser/schema_version.py
  • tests/data/expected/main/openapi/same_name_objects.py
  • tests/parser/test_schema_version.py
💤 Files with no reviewable changes (1)
  • tests/data/expected/main/openapi/same_name_objects.py
🧰 Additional context used
🧬 Code graph analysis (6)
tests/parser/test_schema_version.py (2)
src/datamodel_code_generator/enums.py (3)
  • JsonSchemaVersion (243-254)
  • OpenAPIVersion (257-265)
  • VersionMode (268-276)
src/datamodel_code_generator/parser/schema_version.py (7)
  • JsonSchemaFeatures (20-81)
  • OpenAPISchemaFeatures (85-123)
  • detect_jsonschema_version (139-165)
  • detect_openapi_version (168-182)
  • from_version (43-81)
  • from_openapi_version (99-123)
  • get_data_formats (261-277)
src/datamodel_code_generator/enums.py (1)
src/datamodel_code_generator/model/enum.py (1)
  • Enum (39-121)
src/datamodel_code_generator/__init__.py (1)
src/datamodel_code_generator/enums.py (3)
  • JsonSchemaVersion (243-254)
  • OpenAPIVersion (257-265)
  • VersionMode (268-276)
src/datamodel_code_generator/parser/openapi.py (2)
src/datamodel_code_generator/enums.py (1)
  • OpenAPIVersion (257-265)
src/datamodel_code_generator/parser/schema_version.py (3)
  • OpenAPISchemaFeatures (85-123)
  • detect_openapi_version (168-182)
  • from_openapi_version (99-123)
src/datamodel_code_generator/parser/schema_version.py (2)
src/datamodel_code_generator/enums.py (2)
  • JsonSchemaVersion (243-254)
  • OpenAPIVersion (257-265)
src/datamodel_code_generator/types.py (1)
  • Types (955-994)
src/datamodel_code_generator/parser/jsonschema.py (2)
src/datamodel_code_generator/enums.py (1)
  • JsonSchemaVersion (243-254)
src/datamodel_code_generator/parser/schema_version.py (3)
  • JsonSchemaFeatures (20-81)
  • detect_jsonschema_version (139-165)
  • from_version (43-81)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/__init__.py

987-987: Unused noqa directive (unused: F822)

Remove unused noqa directive

(RUF100)


988-988: Unused noqa directive (unused: F822)

Remove unused noqa directive

(RUF100)


989-989: Unused noqa directive (unused: F822)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/parser/openapi.py

176-176: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/parser/schema_version.py

190-190: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


251-251: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/parser/jsonschema.py

790-790: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: py312-isort5 on Ubuntu
  • GitHub Check: py312-isort6 on Ubuntu
  • GitHub Check: py312-isort7 on Ubuntu
  • GitHub Check: 3.13 on Windows
  • GitHub Check: 3.11 on Windows
  • GitHub Check: py312-pydantic1 on Ubuntu
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.14 on Windows
  • GitHub Check: Analyze (python)
  • GitHub Check: benchmarks
🔇 Additional comments (13)
src/datamodel_code_generator/enums.py (1)

243-276: LGTM! Well-structured version enums.

The three new enums (JsonSchemaVersion, OpenAPIVersion, VersionMode) are cleanly defined with clear docstrings explaining their purpose and the Auto variant behavior. The enum values follow standard naming conventions for their respective specifications.

src/datamodel_code_generator/parser/schema_version.py (3)

19-123: LGTM! Feature flags correctly mapped across versions.

The frozen dataclasses provide immutable feature flag sets for each schema version. The version-to-feature mappings are accurate:

  • Draft 4's use of id vs later drafts' $id
  • Boolean schemas introduced in Draft 6
  • $defs replacing definitions in 2019-09
  • OpenAPI 3.0's nullable keyword vs 3.1's type arrays

The default case for Auto and future versions sensibly enables all modern features.


139-165: LGTM! Robust version detection with sensible fallbacks.

The detection priority is well-designed:

  1. Explicit $schema field (with type check)
  2. Heuristics ($defs vs definitions)
  3. Draft 7 fallback (most widely used)

The string type check on line 156 prevents errors when $schema contains unexpected values.


168-182: LGTM! Clean OpenAPI version detection.

The implementation correctly uses startswith to handle patch versions (e.g., 3.0.3, 3.1.0) and includes a type check to handle non-string values. Defaulting to V31 (latest) is appropriate.

src/datamodel_code_generator/parser/openapi.py (1)

173-182: LGTM! Consistent schema features implementation.

The schema_features property follows the same pattern as JsonSchemaParser, using cached_property for efficient lazy evaluation and local imports to avoid circular dependencies. The fallback to Auto when raw_obj is unavailable is appropriate.

tests/parser/test_schema_version.py (1)

1-423: LGTM! Excellent test coverage.

This comprehensive test suite validates:

  • Version detection across all JSON Schema drafts and OpenAPI versions
  • Edge cases (non-string values, missing fields, heuristics)
  • Feature flag mappings for each version
  • Immutability of frozen dataclasses
  • Lazy import exposure from the main module
  • Data format mappings with and without OpenAPI-specific formats
  • Parser integration with real raw_obj data

The tests provide strong confidence in the correctness of the new versioning infrastructure.

src/datamodel_code_generator/parser/jsonschema.py (7)

31-31: LGTM! Clean imports for version-aware schema processing.

The imports of JsonSchemaVersion and JsonSchemaFeatures enable the new version-specific behavior throughout the parser.

Also applies to: 91-91


195-200: LGTM! Helpful documentation clarification.

The enhanced docstring properly documents that Discriminator is an OpenAPI-specific concept and explains why it's located in the JSON Schema parser (circular import avoidance).


519-533: LGTM! Well-designed for version-specific format handling.

Adding the data_formats parameter with a default fallback enables version-aware and parser-specific type mappings while maintaining backward compatibility.


748-756: LGTM! Good extensibility point for parser-specific formats.

The _data_formats cached property provides a clean override point for subclasses (e.g., OpenAPI parser) while maintaining backward compatibility.


757-772: LGTM! Correctly integrated version-aware format mappings.

The method now uses self._data_formats instead of the global mapping, enabling parser-specific and version-specific format resolution while respecting custom type mappings.


3617-3628: LGTM! Correct version-aware root ID handling.

The root_id_context now properly uses schema_features.id_field to support both Draft 4's "id" and Draft 6+'s "$id", with appropriate fallback checks for lenient compatibility with mixed-version schemas.


774-796: Remove unused noqa directive.

Line 790 has an unused noqa directive for PLC0415 (import-outside-toplevel) which is not enabled in your Ruff configuration.

Otherwise, the version-aware schema_paths and schema_features implementation looks excellent. The lenient approach of checking both $defs and definitions (with version-appropriate prioritization) provides good compatibility with mixed-version schemas.

🔎 Proposed fix
     def schema_features(self) -> JsonSchemaFeatures:
         """Get schema features based on detected version."""
-        from datamodel_code_generator.parser.schema_version import (  # noqa: PLC0415
+        from datamodel_code_generator.parser.schema_version import (
             JsonSchemaFeatures,
             detect_jsonschema_version,
         )
⛔ Skipped due to learnings
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/model/pydantic/__init__.py:43-43
Timestamp: 2025-12-25T09:22:22.481Z
Learning: In datamodel-code-generator project, defensive `# noqa: PLC0415` directives should be kept on lazy imports (imports inside functions/methods) even when Ruff reports them as unused via RUF100, to prepare for potential future Ruff configuration changes that might enable the import-outside-top-level rule.
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2681
File: tests/cli_doc/test_cli_doc_coverage.py:82-82
Timestamp: 2025-12-18T13:43:16.235Z
Learning: In datamodel-code-generator project, Ruff preview mode is enabled via `lint.preview = true` in pyproject.toml. This enables preview rules like PLR6301 (no-self-use), so `noqa: PLR6301` directives are necessary and should not be removed even if RUF100 suggests they are unused.

@koxudaxi koxudaxi changed the base branch from main to feature/cli-version-options January 5, 2026 18:17
@koxudaxi koxudaxi force-pushed the feature/version-specific-processing branch from 2e1b066 to 9e57fb9 Compare January 5, 2026 18:21
@koxudaxi koxudaxi changed the base branch from feature/cli-version-options to main January 5, 2026 18:21
@koxudaxi koxudaxi changed the base branch from main to feature/cli-version-options January 5, 2026 18:22
@koxudaxi koxudaxi changed the base branch from feature/cli-version-options to main January 5, 2026 18:23
@koxudaxi koxudaxi changed the base branch from main to feature/cli-version-options January 5, 2026 18:23
@koxudaxi koxudaxi force-pushed the feature/version-specific-processing branch 3 times, most recently from 18f34ac to 837b245 Compare January 5, 2026 18:54
Base automatically changed from feature/cli-version-options to feature/schema-object-refactoring January 6, 2026 15:42
@koxudaxi koxudaxi force-pushed the feature/schema-object-refactoring branch from 4c3c9e9 to 811cf13 Compare January 6, 2026 15:46
@koxudaxi koxudaxi force-pushed the feature/version-specific-processing branch from 72d1df4 to dbc8045 Compare January 6, 2026 15:49
@koxudaxi koxudaxi force-pushed the feature/version-specific-processing branch from dbc8045 to dd2aef2 Compare January 6, 2026 16:07
@koxudaxi koxudaxi merged commit 68ffafa into feature/schema-object-refactoring Jan 6, 2026
6 checks passed
@koxudaxi koxudaxi deleted the feature/version-specific-processing branch January 6, 2026 16:08
koxudaxi added a commit that referenced this pull request Jan 6, 2026
* Add schema_features property to parsers for version detection

* Add version-specific schema processing using schema_features (#2934)

* Add --jsonschema-version and --openapi-version CLI options

* Add --schema-version and --schema-version-mode CLI options

* Regenerate CLI docs

* Add version-specific schema processing using schema_features

* Implement flag-based behavior control for schema version

* Add comprehensive version-specific feature checks with exclusive_as_number flag

* Replace getattr with direct config access for schema_version_mode

* docs: update llms.txt files

Generated by GitHub Actions

* docs: update CLI reference documentation and prompt data

🤖 Generated by GitHub Actions

* Add SchemaFeaturesT generic type parameter to Parser

* Fix test snapshot: add exclusive_as_number field

* Refactor: genericize _create_default_config using _get_config_class

* Add parameterized e2e tests for --schema-version and --schema-version-mode

* docs: update CLI reference documentation and prompt data

🤖 Generated by GitHub Actions

* docs: update llms.txt files

Generated by GitHub Actions

* Refactor: use _config_class_name class variable instead of method override

* docs: update CLI reference documentation and prompt data

🤖 Generated by GitHub Actions

* docs: update llms.txt files

Generated by GitHub Actions

* Add Schema Version Support to docs navigation

* docs: update llms.txt files

Generated by GitHub Actions

* Docs: add detailed unsupported features tables

* docs: update llms.txt files

Generated by GitHub Actions

* Docs: add version info to unsupported features tables

* docs: update llms.txt files

Generated by GitHub Actions

* Add e2e tests for schema version error handling and strict mode warnings

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants