From b9fcb76944a9a5a8b8e28d13cfd473652da90a3e Mon Sep 17 00:00:00 2001 From: Jukka Hassinen Date: Fri, 29 Nov 2024 15:10:16 +0000 Subject: [PATCH] fix: some default naming of models/related model schemas Other changes: - documented the use of @property methods as field (related to Support for @property decorated Django model methods #1) - some other documentation improvements - removed some obsolete files --- .coveragerc | 4 +- README.md | 11 ++- django2pydantic/base.py | 9 ++- django2pydantic/schema.py | 2 +- examples.ipynb | 58 ++++++++----- examples.py | 149 ---------------------------------- pyproject.toml | 166 -------------------------------------- 7 files changed, 57 insertions(+), 342 deletions(-) delete mode 100644 examples.py delete mode 100644 pyproject.toml diff --git a/.coveragerc b/.coveragerc index ffee6c5..465e715 100644 --- a/.coveragerc +++ b/.coveragerc @@ -13,4 +13,6 @@ exclude_also = if TYPE_CHECKING: if typing.TYPE_CHECKING: class .*\bProtocol\): - @(abc\.)?abstractmethod \ No newline at end of file + @(abc\.)?abstractmethod + @(pytest\.|pytest\.mark.\.)?skip + @(pytest\.|pytest\.mark.\.)?xfail diff --git a/README.md b/README.md index 70a9ab4..750cf97 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +![PyPI - License](https://img.shields.io/pypi/l/django) +![PyPI - Downloads](https://img.shields.io/pypi/dm/django2pydantic) + # Why django2pydantic is the most complete Pydantic schemas based on Django models. @@ -7,16 +10,18 @@ django2pydantic is the most complete Pydantic schemas based on Django models. django2pydantic is a library that allows to define Pydantic schemas based on Django database models. Similar libraries: + - [Djantic](https://jordaneremieff.github.io/djantic/) - [Django Ninja Schema](https://django-ninja.dev/guides/response/django-pydantic/) - [Ninja Schema](https://github.com/eadwinCode/ninja-schema) # Key features -- Supports all Django model fields +- Supports all Django model field types +- Supports @property decorated Django model methods - Supports all Django model relation fields: - - ForeignKey, OneToOneField, ManyToManyField - - The reverse relations of the above (ManyToOneRel, OneToOneRel, ManyToManyRel) + - ForeignKey, OneToOneField, ManyToManyField + - The reverse relations of the above (ManyToOneRel, OneToOneRel, ManyToManyRel) - Supports defining nested relations - Provides as complete OpenAPI schema details as possible diff --git a/django2pydantic/base.py b/django2pydantic/base.py index ba140bd..d15c3f3 100644 --- a/django2pydantic/base.py +++ b/django2pydantic/base.py @@ -76,6 +76,8 @@ def create_pydantic_model( type[BaseModel]: The Pydantic model. """ + model_name = model_name or f"{django_model.__name__}Schema" + pydantic_fields: dict[ str, tuple[ @@ -237,7 +239,6 @@ def create_pydantic_model( # Finally, create the Pydantic model: # https://docs.pydantic.dev/2.9/concepts/models/#dynamic-model-creation - model_name = model_name or f"{django_model.__name__}Schema" return create_model( model_name, __base__=bases, @@ -283,7 +284,11 @@ def __new__( # pylint: disable=W0222,C0204 msg = f"model field is required in Meta class for {name}" raise ValueError(msg) - model_name = getattr(namespace["Meta"], "name", None) + model_name = getattr( + namespace["Meta"], + "name", + f"{model_class.__name__}Schema", + ) return create_pydantic_model( model_class, diff --git a/django2pydantic/schema.py b/django2pydantic/schema.py index 1619482..e44bfea 100644 --- a/django2pydantic/schema.py +++ b/django2pydantic/schema.py @@ -28,7 +28,7 @@ class Meta: """Pydantic configuration.""" name: str | None = None - models: Model | None = None + model: Model | None = None fields: ClassVar[ModelFields | None] = None @model_validator(mode="wrap") diff --git a/examples.ipynb b/examples.ipynb index 433701c..af2e874 100644 --- a/examples.ipynb +++ b/examples.ipynb @@ -51,6 +51,11 @@ " app_label = \"tests\"\n", " default_related_name = 'books'\n", "\n", + " @property\n", + " def author_names(self) -> str:\n", + " \"\"\"All authors' names separated by comma.\"\"\"\n", + " return \", \".join([author.name for author in self.authors.all()])\n", + "\n", "\n", "class Library(models.Model):\n", " name = models.CharField(max_length=100)\n", @@ -99,7 +104,7 @@ "text/html": [ "
{\n",
        "  \"$defs\": {\n",
-       "    \"None_authors\": {\n",
+       "    \"BookSchema_authors\": {\n",
        "      \"properties\": {\n",
        "        \"name\": {\n",
        "          \"description\": \"Name\",\n",
@@ -111,10 +116,10 @@
        "      \"required\": [\n",
        "        \"name\"\n",
        "      ],\n",
-       "      \"title\": \"None_authors\",\n",
+       "      \"title\": \"BookSchema_authors\",\n",
        "      \"type\": \"object\"\n",
        "    },\n",
-       "    \"None_book_copies\": {\n",
+       "    \"BookSchema_book_copies\": {\n",
        "      \"properties\": {\n",
        "        \"library\": {\n",
        "          \"description\": \"Library\",\n",
@@ -125,10 +130,10 @@
        "      \"required\": [\n",
        "        \"library\"\n",
        "      ],\n",
-       "      \"title\": \"None_book_copies\",\n",
+       "      \"title\": \"BookSchema_book_copies\",\n",
        "      \"type\": \"object\"\n",
        "    },\n",
-       "    \"None_publisher\": {\n",
+       "    \"BookSchema_publisher\": {\n",
        "      \"properties\": {\n",
        "        \"name\": {\n",
        "          \"description\": \"Name\",\n",
@@ -140,7 +145,7 @@
        "      \"required\": [\n",
        "        \"name\"\n",
        "      ],\n",
-       "      \"title\": \"None_publisher\",\n",
+       "      \"title\": \"BookSchema_publisher\",\n",
        "      \"type\": \"object\"\n",
        "    }\n",
        "  },\n",
@@ -167,7 +172,7 @@
        "      \"anyOf\": [\n",
        "        {\n",
        "          \"items\": {\n",
-       "            \"$ref\": \"#/$defs/None_authors\"\n",
+       "            \"$ref\": \"#/$defs/BookSchema_authors\"\n",
        "          },\n",
        "          \"type\": \"array\"\n",
        "        },\n",
@@ -180,7 +185,7 @@
        "      \"title\": \"authors\"\n",
        "    },\n",
        "    \"publisher\": {\n",
-       "      \"$ref\": \"#/$defs/None_publisher\",\n",
+       "      \"$ref\": \"#/$defs/BookSchema_publisher\",\n",
        "      \"description\": \"publisher\",\n",
        "      \"title\": \"publisher\"\n",
        "    },\n",
@@ -188,7 +193,7 @@
        "      \"anyOf\": [\n",
        "        {\n",
        "          \"items\": {\n",
-       "            \"$ref\": \"#/$defs/None_book_copies\"\n",
+       "            \"$ref\": \"#/$defs/BookSchema_book_copies\"\n",
        "          },\n",
        "          \"type\": \"array\"\n",
        "        },\n",
@@ -199,13 +204,19 @@
        "      \"default\": null,\n",
        "      \"description\": \"book_copies\",\n",
        "      \"title\": \"book_copies\"\n",
+       "    },\n",
+       "    \"author_names\": {\n",
+       "      \"description\": \"All authors' names separated by comma.\",\n",
+       "      \"title\": \"Author Names\",\n",
+       "      \"type\": \"string\"\n",
        "    }\n",
        "  },\n",
        "  \"required\": [\n",
        "    \"title\",\n",
        "    \"isbn\",\n",
        "    \"publication_date\",\n",
-       "    \"publisher\"\n",
+       "    \"publisher\",\n",
+       "    \"author_names\"\n",
        "  ],\n",
        "  \"title\": \"BookSchema\",\n",
        "  \"type\": \"object\"\n",
@@ -215,7 +226,7 @@
       "text/plain": [
        "\u001b[1m{\u001b[0m\n",
        "  \u001b[1;34m\"$defs\"\u001b[0m: \u001b[1m{\u001b[0m\n",
-       "    \u001b[1;34m\"None_authors\"\u001b[0m: \u001b[1m{\u001b[0m\n",
+       "    \u001b[1;34m\"BookSchema_authors\"\u001b[0m: \u001b[1m{\u001b[0m\n",
        "      \u001b[1;34m\"properties\"\u001b[0m: \u001b[1m{\u001b[0m\n",
        "        \u001b[1;34m\"name\"\u001b[0m: \u001b[1m{\u001b[0m\n",
        "          \u001b[1;34m\"description\"\u001b[0m: \u001b[32m\"Name\"\u001b[0m,\n",
@@ -227,10 +238,10 @@
        "      \u001b[1;34m\"required\"\u001b[0m: \u001b[1m[\u001b[0m\n",
        "        \u001b[32m\"name\"\u001b[0m\n",
        "      \u001b[1m]\u001b[0m,\n",
-       "      \u001b[1;34m\"title\"\u001b[0m: \u001b[32m\"None_authors\"\u001b[0m,\n",
+       "      \u001b[1;34m\"title\"\u001b[0m: \u001b[32m\"BookSchema_authors\"\u001b[0m,\n",
        "      \u001b[1;34m\"type\"\u001b[0m: \u001b[32m\"object\"\u001b[0m\n",
        "    \u001b[1m}\u001b[0m,\n",
-       "    \u001b[1;34m\"None_book_copies\"\u001b[0m: \u001b[1m{\u001b[0m\n",
+       "    \u001b[1;34m\"BookSchema_book_copies\"\u001b[0m: \u001b[1m{\u001b[0m\n",
        "      \u001b[1;34m\"properties\"\u001b[0m: \u001b[1m{\u001b[0m\n",
        "        \u001b[1;34m\"library\"\u001b[0m: \u001b[1m{\u001b[0m\n",
        "          \u001b[1;34m\"description\"\u001b[0m: \u001b[32m\"Library\"\u001b[0m,\n",
@@ -241,10 +252,10 @@
        "      \u001b[1;34m\"required\"\u001b[0m: \u001b[1m[\u001b[0m\n",
        "        \u001b[32m\"library\"\u001b[0m\n",
        "      \u001b[1m]\u001b[0m,\n",
-       "      \u001b[1;34m\"title\"\u001b[0m: \u001b[32m\"None_book_copies\"\u001b[0m,\n",
+       "      \u001b[1;34m\"title\"\u001b[0m: \u001b[32m\"BookSchema_book_copies\"\u001b[0m,\n",
        "      \u001b[1;34m\"type\"\u001b[0m: \u001b[32m\"object\"\u001b[0m\n",
        "    \u001b[1m}\u001b[0m,\n",
-       "    \u001b[1;34m\"None_publisher\"\u001b[0m: \u001b[1m{\u001b[0m\n",
+       "    \u001b[1;34m\"BookSchema_publisher\"\u001b[0m: \u001b[1m{\u001b[0m\n",
        "      \u001b[1;34m\"properties\"\u001b[0m: \u001b[1m{\u001b[0m\n",
        "        \u001b[1;34m\"name\"\u001b[0m: \u001b[1m{\u001b[0m\n",
        "          \u001b[1;34m\"description\"\u001b[0m: \u001b[32m\"Name\"\u001b[0m,\n",
@@ -256,7 +267,7 @@
        "      \u001b[1;34m\"required\"\u001b[0m: \u001b[1m[\u001b[0m\n",
        "        \u001b[32m\"name\"\u001b[0m\n",
        "      \u001b[1m]\u001b[0m,\n",
-       "      \u001b[1;34m\"title\"\u001b[0m: \u001b[32m\"None_publisher\"\u001b[0m,\n",
+       "      \u001b[1;34m\"title\"\u001b[0m: \u001b[32m\"BookSchema_publisher\"\u001b[0m,\n",
        "      \u001b[1;34m\"type\"\u001b[0m: \u001b[32m\"object\"\u001b[0m\n",
        "    \u001b[1m}\u001b[0m\n",
        "  \u001b[1m}\u001b[0m,\n",
@@ -283,7 +294,7 @@
        "      \u001b[1;34m\"anyOf\"\u001b[0m: \u001b[1m[\u001b[0m\n",
        "        \u001b[1m{\u001b[0m\n",
        "          \u001b[1;34m\"items\"\u001b[0m: \u001b[1m{\u001b[0m\n",
-       "            \u001b[1;34m\"$ref\"\u001b[0m: \u001b[32m\"#/$defs/None_authors\"\u001b[0m\n",
+       "            \u001b[1;34m\"$ref\"\u001b[0m: \u001b[32m\"#/$defs/BookSchema_authors\"\u001b[0m\n",
        "          \u001b[1m}\u001b[0m,\n",
        "          \u001b[1;34m\"type\"\u001b[0m: \u001b[32m\"array\"\u001b[0m\n",
        "        \u001b[1m}\u001b[0m,\n",
@@ -296,7 +307,7 @@
        "      \u001b[1;34m\"title\"\u001b[0m: \u001b[32m\"authors\"\u001b[0m\n",
        "    \u001b[1m}\u001b[0m,\n",
        "    \u001b[1;34m\"publisher\"\u001b[0m: \u001b[1m{\u001b[0m\n",
-       "      \u001b[1;34m\"$ref\"\u001b[0m: \u001b[32m\"#/$defs/None_publisher\"\u001b[0m,\n",
+       "      \u001b[1;34m\"$ref\"\u001b[0m: \u001b[32m\"#/$defs/BookSchema_publisher\"\u001b[0m,\n",
        "      \u001b[1;34m\"description\"\u001b[0m: \u001b[32m\"publisher\"\u001b[0m,\n",
        "      \u001b[1;34m\"title\"\u001b[0m: \u001b[32m\"publisher\"\u001b[0m\n",
        "    \u001b[1m}\u001b[0m,\n",
@@ -304,7 +315,7 @@
        "      \u001b[1;34m\"anyOf\"\u001b[0m: \u001b[1m[\u001b[0m\n",
        "        \u001b[1m{\u001b[0m\n",
        "          \u001b[1;34m\"items\"\u001b[0m: \u001b[1m{\u001b[0m\n",
-       "            \u001b[1;34m\"$ref\"\u001b[0m: \u001b[32m\"#/$defs/None_book_copies\"\u001b[0m\n",
+       "            \u001b[1;34m\"$ref\"\u001b[0m: \u001b[32m\"#/$defs/BookSchema_book_copies\"\u001b[0m\n",
        "          \u001b[1m}\u001b[0m,\n",
        "          \u001b[1;34m\"type\"\u001b[0m: \u001b[32m\"array\"\u001b[0m\n",
        "        \u001b[1m}\u001b[0m,\n",
@@ -315,13 +326,19 @@
        "      \u001b[1;34m\"default\"\u001b[0m: \u001b[3;35mnull\u001b[0m,\n",
        "      \u001b[1;34m\"description\"\u001b[0m: \u001b[32m\"book_copies\"\u001b[0m,\n",
        "      \u001b[1;34m\"title\"\u001b[0m: \u001b[32m\"book_copies\"\u001b[0m\n",
+       "    \u001b[1m}\u001b[0m,\n",
+       "    \u001b[1;34m\"author_names\"\u001b[0m: \u001b[1m{\u001b[0m\n",
+       "      \u001b[1;34m\"description\"\u001b[0m: \u001b[32m\"All authors' names separated by comma.\"\u001b[0m,\n",
+       "      \u001b[1;34m\"title\"\u001b[0m: \u001b[32m\"Author Names\"\u001b[0m,\n",
+       "      \u001b[1;34m\"type\"\u001b[0m: \u001b[32m\"string\"\u001b[0m\n",
        "    \u001b[1m}\u001b[0m\n",
        "  \u001b[1m}\u001b[0m,\n",
        "  \u001b[1;34m\"required\"\u001b[0m: \u001b[1m[\u001b[0m\n",
        "    \u001b[32m\"title\"\u001b[0m,\n",
        "    \u001b[32m\"isbn\"\u001b[0m,\n",
        "    \u001b[32m\"publication_date\"\u001b[0m,\n",
-       "    \u001b[32m\"publisher\"\u001b[0m\n",
+       "    \u001b[32m\"publisher\"\u001b[0m,\n",
+       "    \u001b[32m\"author_names\"\u001b[0m\n",
        "  \u001b[1m]\u001b[0m,\n",
        "  \u001b[1;34m\"title\"\u001b[0m: \u001b[32m\"BookSchema\"\u001b[0m,\n",
        "  \u001b[1;34m\"type\"\u001b[0m: \u001b[32m\"object\"\u001b[0m\n",
@@ -355,6 +372,7 @@
     "            \"authors\": {\"name\": Infer},\n",
     "            \"publisher\": {\"name\": Infer},\n",
     "            \"book_copies\": {\"library\": Infer}, # note: here we use a reverse relation\n",
+    "            \"author_names\": Infer,  # note: here we use the model's @property method\n",
     "        }\n",
     "\n",
     "print_json(data=BookSchema.model_json_schema())\n"
diff --git a/examples.py b/examples.py
deleted file mode 100644
index a3ebe53..0000000
--- a/examples.py
+++ /dev/null
@@ -1,149 +0,0 @@
-# %% [markdown]
-# Lets define some example Django models with all the relationships we can think of:
-
-# %%
-import os
-
-import django
-
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tests.settings")
-
-# Setup Django
-django.setup()
-
-from django.contrib.auth.models import User
-from django.db import models
-
-
-class Author(models.Model):
-    name = models.CharField(max_length=100)
-    birth_date = models.DateField()
-
-    class Meta:
-        app_label = "tests"
-
-
-class Publisher(models.Model):
-    name = models.CharField(max_length=100)
-    address = models.TextField(help_text="Publisher's official address")
-
-    class Meta:
-        app_label = "tests"
-
-
-class BookAuthor(models.Model):
-    book = models.ForeignKey("Book", on_delete=models.CASCADE)
-    author = models.ForeignKey(Author, on_delete=models.CASCADE)
-    date_added = models.DateField()
-
-    class Meta:
-        app_label = "tests"
-        default_related_name = "book_authors"
-        unique_together = ("book", "author")
-
-
-class BookDetails(models.Model):
-    description = models.TextField()
-
-    class Meta:
-        app_label = "tests"
-        default_related_name = "book_details"
-
-
-class Book(models.Model):
-    """Book model example with all the relationships we can think of."""
-
-    title = models.CharField(max_length=200)
-    isbn = models.CharField(max_length=13, unique=True)
-    publication_date = models.DateField(null=True)
-    book_details = models.OneToOneField(
-        BookDetails,
-        on_delete=models.CASCADE,
-        null=True,
-    )
-    authors = models.ManyToManyField(
-        Author,
-        through=BookAuthor,
-    )  # Many-to-Many relationship
-    publisher = models.ForeignKey(
-        Publisher,
-        on_delete=models.CASCADE,
-    )  # Foreign Key relationship
-
-    class Meta:
-        app_label = "tests"
-        default_related_name = "books"
-
-    @property
-    def author_names(self) -> str:
-        """Return a comma separated list of author names."""
-        return ", ".join([author.name for author in self.authors.all()])
-
-
-class Library(models.Model):
-    name = models.CharField(max_length=100)
-    address = models.TextField()
-
-    class Meta:
-        app_label = "tests"
-
-
-class BookCopy(models.Model):
-    book = models.ForeignKey(Book, on_delete=models.CASCADE)  # Foreign Key relationship
-    library = models.ForeignKey(
-        Library,
-        on_delete=models.CASCADE,
-    )  # Foreign Key relationship
-    inventory_number = models.CharField(max_length=20, unique=True)
-
-    class Meta:
-        app_label = "tests"
-        default_related_name = "book_copies"
-
-
-class Borrowing(models.Model):
-    user = models.ForeignKey(User, on_delete=models.CASCADE)  # Foreign Key relationship
-    book_copy = models.ForeignKey(
-        BookCopy,
-        on_delete=models.CASCADE,
-    )  # Foreign Key relationship
-    borrow_date = models.DateField()
-    return_date = models.DateField(null=True, blank=True)
-
-    class Meta:
-        app_label = "tests"
-        default_related_name = "borrowings"
-
-
-# %% [markdown]
-# Now lets do some testing:
-
-# %%
-from typing import ClassVar
-
-from rich import print_json
-
-from django2pydantic.schema import django2pydantic
-from django2pydantic.types import Infer, ModelFields
-
-
-class BookSchema(django2pydantic):
-    """Book schema example with nested fields."""
-
-    class Meta(django2pydantic.Meta):
-        """Here we define the model and the fields we want to infer."""
-
-        model = Book
-        fields: ClassVar[ModelFields] = {
-            "title": Infer,
-            "isbn": Infer,
-            "publication_date": Infer,
-            "book_details": {"description": Infer},
-            "authors": {"name": Infer},
-            "publisher": {"name": Infer},
-            "book_copies": {"library": Infer},  # note: here we use a reverse relation
-            "author_names": Infer,
-        }
-
-
-print_json(data=BookSchema.model_json_schema())
diff --git a/pyproject.toml b/pyproject.toml
deleted file mode 100644
index e624e7b..0000000
--- a/pyproject.toml
+++ /dev/null
@@ -1,166 +0,0 @@
-[project]
-name = "django2pydantic"
-version = "0.1.1"
-description = "Converting Django models to Pydantic models"
-readme = "README.md"
-requires-python = "==3.12.*"
-authors = [
-  {name = "Jukka Hassinen", email = "jukka.hassinen@gmail.com"}
-]
-license = "MIT"
-keywords = [
-    "django",
-    "pydantic",
-    "models",
-    "schema",
-    "converter",
-]
-
-classifiers = [
-    "License :: OSI Approved :: MIT License",
-    "Development Status :: 2 - Pre-Alpha",
-    "Environment :: Console",
-    "Programming Language :: Python :: 3.12",
-    "Framework :: Django :: 5.1",
-    "Framework :: Pydantic :: 2",
-    "Intended Audience :: Developers",
-    "Operating System :: OS Independent",
-    "Topic :: Software Development :: Libraries :: Python Modules",
-    "Typing :: Typed",
-]
-
-dependencies = [
-    "django>=5.1.3",
-    "pydantic>=2.9.2",
-]
-
-
-[project.urls]
-Homepage = "https://github.com/NextGenContributions/django2pydantic"
-Documentation = "https://github.com/NextGenContributions/django2pydantic/blob/main/README.md"
-Repository = "https://github.com/NextGenContributions/django2pydantic.git"
-Issues = "https://github.com/NextGenContributions/django2pydantic/issues"
-Changelog = "https://github.com/NextGenContributions/django2pydantic/blob/main/CHANGELOG.md"
-"Release Notes" = "https://github.com/NextGenContributions/django2pydantic/releases"
-Funding = "https://github.com/sponsors/NextGenContributions"
-
-[build-system]
-requires = ["hatchling"]
-build-backend = "hatchling.build"
-
-[tool.hatch.build.targets.sdist]
-only-include = ["django2pydantic"]
-
-[dependency-groups]
-dev = [
-    "basedpyright>=1.21.0",
-    "beartype>=0.19.0",
-    "debugpy>=1.8.8",
-    "django-ninja>=1.3.0",
-    "django-stubs[compatible-mypy]>=5.1.1",
-    "email-validator>=2.2.0",
-    "hypothesis>=6.118.0",
-    "import-linter>=2.1",
-    "ipykernel>=6.29.5",
-    "isort>=5.13.2",
-    "mypy>=1.13.0",
-    "ninja-schema>=0.13.6",
-    "nox>=2024.10.9",
-    "pylint-django>=2.6.1",
-    "pyre-check>=0.9.23",
-    "pyright>=1.1.388",
-    "pytest>=8.3.3",
-    "pytest-cov>=6.0.0",
-    "pytest-django>=4.9.0",
-    "pytest-instafail>=0.5.0",
-    "pytest-testmon>=2.1.1",
-    "pytest-watch>=4.2.0",
-    "pytype>=2024.10.11",
-    "rich>=13.9.4",
-    "ruff>=0.7.3",
-    "typeguard>=4.4.1",
-    "wemake-python-styleguide>=0.19.2",
-    "django-stubs-ext>=5.1.1",
-    "python-semantic-release>=9.14.0",
-    "semgrep>=1.85.0",
-]
-
-[tool.semantic_release]
-assets = []
-build_command_env = []
-commit_message = "{version}\n\nAutomatically generated by python-semantic-release"
-commit_parser = "angular"
-logging_use_named_masks = false
-major_on_zero = true
-allow_zero_version = true
-no_git_verify = false
-tag_format = "v{version}"
-version_toml = [
-    "pyproject.toml:project.version",
-]
-version_variables = [
-    "django2pydantic/__init__.py:__version__",
-    "uv.lock:\"django2pydantic\"\\nversion",
-]
-
-[tool.semantic_release.branches.main]
-match = "(main|master)"
-prerelease_token = "rc"
-prerelease = false
-
-[tool.semantic_release.changelog]
-exclude_commit_patterns = [
-  '''chore(?:\([^)]*?\))?: .+''',
-  '''ci(?:\([^)]*?\))?: .+''',
-  '''refactor(?:\([^)]*?\))?: .+''',
-  '''style(?:\([^)]*?\))?: .+''',
-  '''test(?:\([^)]*?\))?: .+''',
-  '''build\((?!deps\): .+)''',
-  '''Merged? .*''',
-  '''Initial Commit.*''',
-  # Old semantic-release version commits
-  '''^\d+\.\d+\.\d+''',
-]
-mode = "init"
-insertion_flag = ""
-template_dir = "templates"
-
-[tool.semantic_release.changelog.default_templates]
-changelog_file = "CHANGELOG.md"
-output_format = "md"
-mask_initial_release = false
-
-[tool.semantic_release.changelog.environment]
-block_start_string = "{%"
-block_end_string = "%}"
-variable_start_string = "{{"
-variable_end_string = "}}"
-comment_start_string = "{#"
-comment_end_string = "#}"
-trim_blocks = false
-lstrip_blocks = false
-newline_sequence = "\n"
-keep_trailing_newline = false
-extensions = []
-autoescape = false
-
-[tool.semantic_release.commit_author]
-env = "GIT_COMMIT_AUTHOR"
-default = "semantic-release "
-
-[tool.semantic_release.commit_parser_options]
-minor_tags = ["feat"]
-patch_tags = ["fix", "perf"]
-allowed_tags = ["feat", "fix", "perf", "build", "chore", "ci", "docs", "style", "refactor", "test"]
-default_bump_level = 0
-
-[tool.semantic_release.remote]
-name = "origin"
-type = "github"
-ignore_token_for_push = false
-insecure = false
-
-[tool.semantic_release.publish]
-dist_glob_patterns = ["dist/*"]
-upload_to_vcs_release = true
-