Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6afa967
Add compatibility for Pydantic V2 regex (renamed param from regex to …
stickm4n Dec 1, 2024
e19734f
Merge branch 'fastapi:main' into main
stickm4n Feb 22, 2025
2d6bb87
Merge branch 'main' into main
svlandeg Feb 24, 2025
5de3c0b
Add test for field regex/pattern parameter
stickm4n Aug 30, 2025
926bd78
Split test case with `VaidationError` into two
YuriiMotov Oct 7, 2025
f45a40f
Fix failing test
YuriiMotov Oct 7, 2025
a26b384
Merge branch 'main' into main
YuriiMotov Oct 7, 2025
2b6de42
Merge branch 'main' into main
svlandeg Oct 8, 2025
71cb27d
Merge branch 'fastapi:main' into main
stickm4n Oct 11, 2025
91e8e7e
Remove unused ignore comment
stickm4n Oct 12, 2025
8e9105b
Merge remote-tracking branch 'upstream/main' into stickM4N_main
YuriiMotov Jan 28, 2026
57c6c53
Deprecate `regex` parameter in favor of `pattern`
YuriiMotov Jan 28, 2026
01b3954
Add warning when `pattern` is passed via `schema_extra`
YuriiMotov Jan 28, 2026
570be83
Rename tests
YuriiMotov Jan 28, 2026
2b342da
Update deprecations to be consistent with other PRs
YuriiMotov Jan 28, 2026
6eda60a
Merge branch 'main' into main
YuriiMotov Feb 21, 2026
879d4b8
Fix `discriminator` type annotation
YuriiMotov Feb 21, 2026
7ecd621
Merge branch 'main' into main
YuriiMotov Apr 3, 2026
1acc4b9
Update type hints for regex and pattern parameters to support `re.Pat…
stickm4n Apr 5, 2026
98a52b1
Remove support for `re.Pattern` in regex parameter type hints
stickm4n Apr 5, 2026
cfc88f3
Add `re` import in main.py
stickm4n Apr 5, 2026
f7f9b5f
Merge branch 'fastapi:main' into main
stickm4n Jul 14, 2026
bc43eb7
Merge branch 'main' into main
YuriiMotov Sep 1, 2026
54d0764
🎨 Auto format
pre-commit-ci-lite[bot] Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions sqlmodel/main.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@

import builtins
import ipaddress
import re
import uuid
import warnings
from collections.abc import Callable, Mapping, Sequence, Set
Expand DownExpand Up@@ -97,6 +98,9 @@
MAX_ITEMS_DEPRECATION_MSG = (
"`max_items` is deprecated and will be removed, use `max_length` instead"
)
REGEX_PARAM_DEPRECATION_MSG = (
"The `regex` parameter is deprecated. \nUse `pattern` parameter instead."
)


def __dataclass_transform__(
Expand DownExpand Up@@ -274,7 +278,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -323,7 +331,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -381,7 +393,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
sa_column: Column[Any] | UndefinedType = Undefined,
Expand DownExpand Up@@ -420,7 +436,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand All@@ -445,10 +465,17 @@ def Field(
warnings.warn(MAX_ITEMS_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
if max_length is None:
max_length = max_items
if regex:
warnings.warn(REGEX_PARAM_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
for param_name in ("pattern",):
if param_name in current_schema_extra:
msg = f"Pass `{param_name}` parameter directly to Field instead of passing it via `schema_extra`"
warnings.warn(msg, UserWarning, stacklevel=2)

# Extract possible alias settings from schema_extra so we can control precedence
schema_validation_alias = current_schema_extra.pop("validation_alias", None)
schema_serialization_alias = current_schema_extra.pop("serialization_alias", None)
current_pattern = pattern or regex or current_schema_extra.pop("pattern", None)
field_info_kwargs = {
"alias": alias,
"title": title,
Expand All@@ -467,7 +494,7 @@ def Field(
"min_length": min_length,
"max_length": max_length,
"allow_mutation": allow_mutation,
"regex": regex,
"pattern": current_pattern,
Comment thread
stickm4n marked this conversation as resolved.
"discriminator": discriminator,
"repr": repr,
"primary_key": primary_key,
Expand Down
35 changes: 35 additions & 0 deletions tests/test_pydantic/test_field.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,3 +120,38 @@ class Model(SQLModel):
Model(items=[1, 2, 3])
assert len(exc_info.value.errors()) == 1
assert exc_info.value.errors()[0]["type"] == "too_long"


def test_regex():
with pytest.warns(DeprecationWarning, match="The `regex` parameter is deprecated"):

class DateModel(SQLModel):
date_1: str = Field(regex=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern():
class DateModel(SQLModel):
date_1: str = Field(pattern=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern_via_schema_extra():
with pytest.warns(
UserWarning,
match="Pass `pattern` parameter directly to Field instead of passing it via `schema_extra`",
):

class DateModel(SQLModel):
date_1: str = Field(schema_extra={"pattern": r"^\d{2}-\d{2}-\d{4}$"})

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6afa967
Add compatibility for Pydantic V2 regex (renamed param from regex to …
stickm4n Dec 1, 2024
e19734f
Merge branch 'fastapi:main' into main
stickm4n Feb 22, 2025
2d6bb87
Merge branch 'main' into main
svlandeg Feb 24, 2025
5de3c0b
Add test for field regex/pattern parameter
stickm4n Aug 30, 2025
926bd78
Split test case with `VaidationError` into two
YuriiMotov Oct 7, 2025
f45a40f
Fix failing test
YuriiMotov Oct 7, 2025
a26b384
Merge branch 'main' into main
YuriiMotov Oct 7, 2025
2b6de42
Merge branch 'main' into main
svlandeg Oct 8, 2025
71cb27d
Merge branch 'fastapi:main' into main
stickm4n Oct 11, 2025
91e8e7e
Remove unused ignore comment
stickm4n Oct 12, 2025
8e9105b
Merge remote-tracking branch 'upstream/main' into stickM4N_main
YuriiMotov Jan 28, 2026
57c6c53
Deprecate `regex` parameter in favor of `pattern`
YuriiMotov Jan 28, 2026
01b3954
Add warning when `pattern` is passed via `schema_extra`
YuriiMotov Jan 28, 2026
570be83
Rename tests
YuriiMotov Jan 28, 2026
2b342da
Update deprecations to be consistent with other PRs
YuriiMotov Jan 28, 2026
6eda60a
Merge branch 'main' into main
YuriiMotov Feb 21, 2026
879d4b8
Fix `discriminator` type annotation
YuriiMotov Feb 21, 2026
7ecd621
Merge branch 'main' into main
YuriiMotov Apr 3, 2026
1acc4b9
Update type hints for regex and pattern parameters to support `re.Pat…
stickm4n Apr 5, 2026
98a52b1
Remove support for `re.Pattern` in regex parameter type hints
stickm4n Apr 5, 2026
cfc88f3
Add `re` import in main.py
stickm4n Apr 5, 2026
f7f9b5f
Merge branch 'fastapi:main' into main
stickm4n Jul 14, 2026
bc43eb7
Merge branch 'main' into main
YuriiMotov Sep 1, 2026
54d0764
🎨 Auto format
pre-commit-ci-lite[bot] Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions sqlmodel/main.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@

import builtins
import ipaddress
import re
import uuid
import warnings
from collections.abc import Callable, Mapping, Sequence, Set
Expand DownExpand Up@@ -97,6 +98,9 @@
MAX_ITEMS_DEPRECATION_MSG = (
"`max_items` is deprecated and will be removed, use `max_length` instead"
)
REGEX_PARAM_DEPRECATION_MSG = (
"The `regex` parameter is deprecated. \nUse `pattern` parameter instead."
)


def __dataclass_transform__(
Expand DownExpand Up@@ -274,7 +278,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -323,7 +331,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -381,7 +393,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
sa_column: Column[Any] | UndefinedType = Undefined,
Expand DownExpand Up@@ -420,7 +436,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand All@@ -445,10 +465,17 @@ def Field(
warnings.warn(MAX_ITEMS_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
if max_length is None:
max_length = max_items
if regex:
warnings.warn(REGEX_PARAM_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
for param_name in ("pattern",):
if param_name in current_schema_extra:
msg = f"Pass `{param_name}` parameter directly to Field instead of passing it via `schema_extra`"
warnings.warn(msg, UserWarning, stacklevel=2)

# Extract possible alias settings from schema_extra so we can control precedence
schema_validation_alias = current_schema_extra.pop("validation_alias", None)
schema_serialization_alias = current_schema_extra.pop("serialization_alias", None)
current_pattern = pattern or regex or current_schema_extra.pop("pattern", None)
field_info_kwargs = {
"alias": alias,
"title": title,
Expand All@@ -467,7 +494,7 @@ def Field(
"min_length": min_length,
"max_length": max_length,
"allow_mutation": allow_mutation,
"regex": regex,
"pattern": current_pattern,
Comment thread
stickm4n marked this conversation as resolved.
"discriminator": discriminator,
"repr": repr,
"primary_key": primary_key,
Expand Down
35 changes: 35 additions & 0 deletions tests/test_pydantic/test_field.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,3 +120,38 @@ class Model(SQLModel):
Model(items=[1, 2, 3])
assert len(exc_info.value.errors()) == 1
assert exc_info.value.errors()[0]["type"] == "too_long"


def test_regex():
with pytest.warns(DeprecationWarning, match="The `regex` parameter is deprecated"):

class DateModel(SQLModel):
date_1: str = Field(regex=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern():
class DateModel(SQLModel):
date_1: str = Field(pattern=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern_via_schema_extra():
with pytest.warns(
UserWarning,
match="Pass `pattern` parameter directly to Field instead of passing it via `schema_extra`",
):

class DateModel(SQLModel):
date_1: str = Field(schema_extra={"pattern": r"^\d{2}-\d{2}-\d{4}$"})

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6afa967
Add compatibility for Pydantic V2 regex (renamed param from regex to …
stickm4n Dec 1, 2024
e19734f
Merge branch 'fastapi:main' into main
stickm4n Feb 22, 2025
2d6bb87
Merge branch 'main' into main
svlandeg Feb 24, 2025
5de3c0b
Add test for field regex/pattern parameter
stickm4n Aug 30, 2025
926bd78
Split test case with `VaidationError` into two
YuriiMotov Oct 7, 2025
f45a40f
Fix failing test
YuriiMotov Oct 7, 2025
a26b384
Merge branch 'main' into main
YuriiMotov Oct 7, 2025
2b6de42
Merge branch 'main' into main
svlandeg Oct 8, 2025
71cb27d
Merge branch 'fastapi:main' into main
stickm4n Oct 11, 2025
91e8e7e
Remove unused ignore comment
stickm4n Oct 12, 2025
8e9105b
Merge remote-tracking branch 'upstream/main' into stickM4N_main
YuriiMotov Jan 28, 2026
57c6c53
Deprecate `regex` parameter in favor of `pattern`
YuriiMotov Jan 28, 2026
01b3954
Add warning when `pattern` is passed via `schema_extra`
YuriiMotov Jan 28, 2026
570be83
Rename tests
YuriiMotov Jan 28, 2026
2b342da
Update deprecations to be consistent with other PRs
YuriiMotov Jan 28, 2026
6eda60a
Merge branch 'main' into main
YuriiMotov Feb 21, 2026
879d4b8
Fix `discriminator` type annotation
YuriiMotov Feb 21, 2026
7ecd621
Merge branch 'main' into main
YuriiMotov Apr 3, 2026
1acc4b9
Update type hints for regex and pattern parameters to support `re.Pat…
stickm4n Apr 5, 2026
98a52b1
Remove support for `re.Pattern` in regex parameter type hints
stickm4n Apr 5, 2026
cfc88f3
Add `re` import in main.py
stickm4n Apr 5, 2026
f7f9b5f
Merge branch 'fastapi:main' into main
stickm4n Jul 14, 2026
bc43eb7
Merge branch 'main' into main
YuriiMotov Sep 1, 2026
54d0764
🎨 Auto format
pre-commit-ci-lite[bot] Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions sqlmodel/main.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@

import builtins
import ipaddress
import re
import uuid
import warnings
from collections.abc import Callable, Mapping, Sequence, Set
Expand DownExpand Up@@ -97,6 +98,9 @@
MAX_ITEMS_DEPRECATION_MSG = (
"`max_items` is deprecated and will be removed, use `max_length` instead"
)
REGEX_PARAM_DEPRECATION_MSG = (
"The `regex` parameter is deprecated. \nUse `pattern` parameter instead."
)


def __dataclass_transform__(
Expand DownExpand Up@@ -274,7 +278,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -323,7 +331,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -381,7 +393,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
sa_column: Column[Any] | UndefinedType = Undefined,
Expand DownExpand Up@@ -420,7 +436,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand All@@ -445,10 +465,17 @@ def Field(
warnings.warn(MAX_ITEMS_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
if max_length is None:
max_length = max_items
if regex:
warnings.warn(REGEX_PARAM_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
for param_name in ("pattern",):
if param_name in current_schema_extra:
msg = f"Pass `{param_name}` parameter directly to Field instead of passing it via `schema_extra`"
warnings.warn(msg, UserWarning, stacklevel=2)

# Extract possible alias settings from schema_extra so we can control precedence
schema_validation_alias = current_schema_extra.pop("validation_alias", None)
schema_serialization_alias = current_schema_extra.pop("serialization_alias", None)
current_pattern = pattern or regex or current_schema_extra.pop("pattern", None)
field_info_kwargs = {
"alias": alias,
"title": title,
Expand All@@ -467,7 +494,7 @@ def Field(
"min_length": min_length,
"max_length": max_length,
"allow_mutation": allow_mutation,
"regex": regex,
"pattern": current_pattern,
Comment thread
stickm4n marked this conversation as resolved.
"discriminator": discriminator,
"repr": repr,
"primary_key": primary_key,
Expand Down
35 changes: 35 additions & 0 deletions tests/test_pydantic/test_field.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,3 +120,38 @@ class Model(SQLModel):
Model(items=[1, 2, 3])
assert len(exc_info.value.errors()) == 1
assert exc_info.value.errors()[0]["type"] == "too_long"


def test_regex():
with pytest.warns(DeprecationWarning, match="The `regex` parameter is deprecated"):

class DateModel(SQLModel):
date_1: str = Field(regex=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern():
class DateModel(SQLModel):
date_1: str = Field(pattern=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern_via_schema_extra():
with pytest.warns(
UserWarning,
match="Pass `pattern` parameter directly to Field instead of passing it via `schema_extra`",
):

class DateModel(SQLModel):
date_1: str = Field(schema_extra={"pattern": r"^\d{2}-\d{2}-\d{4}$"})

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6afa967
Add compatibility for Pydantic V2 regex (renamed param from regex to …
stickm4n Dec 1, 2024
e19734f
Merge branch 'fastapi:main' into main
stickm4n Feb 22, 2025
2d6bb87
Merge branch 'main' into main
svlandeg Feb 24, 2025
5de3c0b
Add test for field regex/pattern parameter
stickm4n Aug 30, 2025
926bd78
Split test case with `VaidationError` into two
YuriiMotov Oct 7, 2025
f45a40f
Fix failing test
YuriiMotov Oct 7, 2025
a26b384
Merge branch 'main' into main
YuriiMotov Oct 7, 2025
2b6de42
Merge branch 'main' into main
svlandeg Oct 8, 2025
71cb27d
Merge branch 'fastapi:main' into main
stickm4n Oct 11, 2025
91e8e7e
Remove unused ignore comment
stickm4n Oct 12, 2025
8e9105b
Merge remote-tracking branch 'upstream/main' into stickM4N_main
YuriiMotov Jan 28, 2026
57c6c53
Deprecate `regex` parameter in favor of `pattern`
YuriiMotov Jan 28, 2026
01b3954
Add warning when `pattern` is passed via `schema_extra`
YuriiMotov Jan 28, 2026
570be83
Rename tests
YuriiMotov Jan 28, 2026
2b342da
Update deprecations to be consistent with other PRs
YuriiMotov Jan 28, 2026
6eda60a
Merge branch 'main' into main
YuriiMotov Feb 21, 2026
879d4b8
Fix `discriminator` type annotation
YuriiMotov Feb 21, 2026
7ecd621
Merge branch 'main' into main
YuriiMotov Apr 3, 2026
1acc4b9
Update type hints for regex and pattern parameters to support `re.Pat…
stickm4n Apr 5, 2026
98a52b1
Remove support for `re.Pattern` in regex parameter type hints
stickm4n Apr 5, 2026
cfc88f3
Add `re` import in main.py
stickm4n Apr 5, 2026
f7f9b5f
Merge branch 'fastapi:main' into main
stickm4n Jul 14, 2026
bc43eb7
Merge branch 'main' into main
YuriiMotov Sep 1, 2026
54d0764
🎨 Auto format
pre-commit-ci-lite[bot] Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions sqlmodel/main.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@

import builtins
import ipaddress
import re
import uuid
import warnings
from collections.abc import Callable, Mapping, Sequence, Set
Expand DownExpand Up@@ -97,6 +98,9 @@
MAX_ITEMS_DEPRECATION_MSG = (
"`max_items` is deprecated and will be removed, use `max_length` instead"
)
REGEX_PARAM_DEPRECATION_MSG = (
"The `regex` parameter is deprecated. \nUse `pattern` parameter instead."
)


def __dataclass_transform__(
Expand DownExpand Up@@ -274,7 +278,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -323,7 +331,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -381,7 +393,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
sa_column: Column[Any] | UndefinedType = Undefined,
Expand DownExpand Up@@ -420,7 +436,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand All@@ -445,10 +465,17 @@ def Field(
warnings.warn(MAX_ITEMS_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
if max_length is None:
max_length = max_items
if regex:
warnings.warn(REGEX_PARAM_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
for param_name in ("pattern",):
if param_name in current_schema_extra:
msg = f"Pass `{param_name}` parameter directly to Field instead of passing it via `schema_extra`"
warnings.warn(msg, UserWarning, stacklevel=2)

# Extract possible alias settings from schema_extra so we can control precedence
schema_validation_alias = current_schema_extra.pop("validation_alias", None)
schema_serialization_alias = current_schema_extra.pop("serialization_alias", None)
current_pattern = pattern or regex or current_schema_extra.pop("pattern", None)
field_info_kwargs = {
"alias": alias,
"title": title,
Expand All@@ -467,7 +494,7 @@ def Field(
"min_length": min_length,
"max_length": max_length,
"allow_mutation": allow_mutation,
"regex": regex,
"pattern": current_pattern,
Comment thread
stickm4n marked this conversation as resolved.
"discriminator": discriminator,
"repr": repr,
"primary_key": primary_key,
Expand Down
35 changes: 35 additions & 0 deletions tests/test_pydantic/test_field.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,3 +120,38 @@ class Model(SQLModel):
Model(items=[1, 2, 3])
assert len(exc_info.value.errors()) == 1
assert exc_info.value.errors()[0]["type"] == "too_long"


def test_regex():
with pytest.warns(DeprecationWarning, match="The `regex` parameter is deprecated"):

class DateModel(SQLModel):
date_1: str = Field(regex=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern():
class DateModel(SQLModel):
date_1: str = Field(pattern=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern_via_schema_extra():
with pytest.warns(
UserWarning,
match="Pass `pattern` parameter directly to Field instead of passing it via `schema_extra`",
):

class DateModel(SQLModel):
date_1: str = Field(schema_extra={"pattern": r"^\d{2}-\d{2}-\d{4}$"})

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6afa967
Add compatibility for Pydantic V2 regex (renamed param from regex to …
stickm4n Dec 1, 2024
e19734f
Merge branch 'fastapi:main' into main
stickm4n Feb 22, 2025
2d6bb87
Merge branch 'main' into main
svlandeg Feb 24, 2025
5de3c0b
Add test for field regex/pattern parameter
stickm4n Aug 30, 2025
926bd78
Split test case with `VaidationError` into two
YuriiMotov Oct 7, 2025
f45a40f
Fix failing test
YuriiMotov Oct 7, 2025
a26b384
Merge branch 'main' into main
YuriiMotov Oct 7, 2025
2b6de42
Merge branch 'main' into main
svlandeg Oct 8, 2025
71cb27d
Merge branch 'fastapi:main' into main
stickm4n Oct 11, 2025
91e8e7e
Remove unused ignore comment
stickm4n Oct 12, 2025
8e9105b
Merge remote-tracking branch 'upstream/main' into stickM4N_main
YuriiMotov Jan 28, 2026
57c6c53
Deprecate `regex` parameter in favor of `pattern`
YuriiMotov Jan 28, 2026
01b3954
Add warning when `pattern` is passed via `schema_extra`
YuriiMotov Jan 28, 2026
570be83
Rename tests
YuriiMotov Jan 28, 2026
2b342da
Update deprecations to be consistent with other PRs
YuriiMotov Jan 28, 2026
6eda60a
Merge branch 'main' into main
YuriiMotov Feb 21, 2026
879d4b8
Fix `discriminator` type annotation
YuriiMotov Feb 21, 2026
7ecd621
Merge branch 'main' into main
YuriiMotov Apr 3, 2026
1acc4b9
Update type hints for regex and pattern parameters to support `re.Pat…
stickm4n Apr 5, 2026
98a52b1
Remove support for `re.Pattern` in regex parameter type hints
stickm4n Apr 5, 2026
cfc88f3
Add `re` import in main.py
stickm4n Apr 5, 2026
f7f9b5f
Merge branch 'fastapi:main' into main
stickm4n Jul 14, 2026
bc43eb7
Merge branch 'main' into main
YuriiMotov Sep 1, 2026
54d0764
🎨 Auto format
pre-commit-ci-lite[bot] Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions sqlmodel/main.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@

import builtins
import ipaddress
import re
import uuid
import warnings
from collections.abc import Callable, Mapping, Sequence, Set
Expand DownExpand Up@@ -97,6 +98,9 @@
MAX_ITEMS_DEPRECATION_MSG = (
"`max_items` is deprecated and will be removed, use `max_length` instead"
)
REGEX_PARAM_DEPRECATION_MSG = (
"The `regex` parameter is deprecated. \nUse `pattern` parameter instead."
)


def __dataclass_transform__(
Expand DownExpand Up@@ -274,7 +278,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -323,7 +331,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -381,7 +393,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
sa_column: Column[Any] | UndefinedType = Undefined,
Expand DownExpand Up@@ -420,7 +436,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand All@@ -445,10 +465,17 @@ def Field(
warnings.warn(MAX_ITEMS_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
if max_length is None:
max_length = max_items
if regex:
warnings.warn(REGEX_PARAM_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
for param_name in ("pattern",):
if param_name in current_schema_extra:
msg = f"Pass `{param_name}` parameter directly to Field instead of passing it via `schema_extra`"
warnings.warn(msg, UserWarning, stacklevel=2)

# Extract possible alias settings from schema_extra so we can control precedence
schema_validation_alias = current_schema_extra.pop("validation_alias", None)
schema_serialization_alias = current_schema_extra.pop("serialization_alias", None)
current_pattern = pattern or regex or current_schema_extra.pop("pattern", None)
field_info_kwargs = {
"alias": alias,
"title": title,
Expand All@@ -467,7 +494,7 @@ def Field(
"min_length": min_length,
"max_length": max_length,
"allow_mutation": allow_mutation,
"regex": regex,
"pattern": current_pattern,
Comment thread
stickm4n marked this conversation as resolved.
"discriminator": discriminator,
"repr": repr,
"primary_key": primary_key,
Expand Down
35 changes: 35 additions & 0 deletions tests/test_pydantic/test_field.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,3 +120,38 @@ class Model(SQLModel):
Model(items=[1, 2, 3])
assert len(exc_info.value.errors()) == 1
assert exc_info.value.errors()[0]["type"] == "too_long"


def test_regex():
with pytest.warns(DeprecationWarning, match="The `regex` parameter is deprecated"):

class DateModel(SQLModel):
date_1: str = Field(regex=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern():
class DateModel(SQLModel):
date_1: str = Field(pattern=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern_via_schema_extra():
with pytest.warns(
UserWarning,
match="Pass `pattern` parameter directly to Field instead of passing it via `schema_extra`",
):

class DateModel(SQLModel):
date_1: str = Field(schema_extra={"pattern": r"^\d{2}-\d{2}-\d{4}$"})

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6afa967
Add compatibility for Pydantic V2 regex (renamed param from regex to …
stickm4n Dec 1, 2024
e19734f
Merge branch 'fastapi:main' into main
stickm4n Feb 22, 2025
2d6bb87
Merge branch 'main' into main
svlandeg Feb 24, 2025
5de3c0b
Add test for field regex/pattern parameter
stickm4n Aug 30, 2025
926bd78
Split test case with `VaidationError` into two
YuriiMotov Oct 7, 2025
f45a40f
Fix failing test
YuriiMotov Oct 7, 2025
a26b384
Merge branch 'main' into main
YuriiMotov Oct 7, 2025
2b6de42
Merge branch 'main' into main
svlandeg Oct 8, 2025
71cb27d
Merge branch 'fastapi:main' into main
stickm4n Oct 11, 2025
91e8e7e
Remove unused ignore comment
stickm4n Oct 12, 2025
8e9105b
Merge remote-tracking branch 'upstream/main' into stickM4N_main
YuriiMotov Jan 28, 2026
57c6c53
Deprecate `regex` parameter in favor of `pattern`
YuriiMotov Jan 28, 2026
01b3954
Add warning when `pattern` is passed via `schema_extra`
YuriiMotov Jan 28, 2026
570be83
Rename tests
YuriiMotov Jan 28, 2026
2b342da
Update deprecations to be consistent with other PRs
YuriiMotov Jan 28, 2026
6eda60a
Merge branch 'main' into main
YuriiMotov Feb 21, 2026
879d4b8
Fix `discriminator` type annotation
YuriiMotov Feb 21, 2026
7ecd621
Merge branch 'main' into main
YuriiMotov Apr 3, 2026
1acc4b9
Update type hints for regex and pattern parameters to support `re.Pat…
stickm4n Apr 5, 2026
98a52b1
Remove support for `re.Pattern` in regex parameter type hints
stickm4n Apr 5, 2026
cfc88f3
Add `re` import in main.py
stickm4n Apr 5, 2026
f7f9b5f
Merge branch 'fastapi:main' into main
stickm4n Jul 14, 2026
bc43eb7
Merge branch 'main' into main
YuriiMotov Sep 1, 2026
54d0764
🎨 Auto format
pre-commit-ci-lite[bot] Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions sqlmodel/main.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@

import builtins
import ipaddress
import re
import uuid
import warnings
from collections.abc import Callable, Mapping, Sequence, Set
Expand DownExpand Up@@ -97,6 +98,9 @@
MAX_ITEMS_DEPRECATION_MSG = (
"`max_items` is deprecated and will be removed, use `max_length` instead"
)
REGEX_PARAM_DEPRECATION_MSG = (
"The `regex` parameter is deprecated. \nUse `pattern` parameter instead."
)


def __dataclass_transform__(
Expand DownExpand Up@@ -274,7 +278,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -323,7 +331,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -381,7 +393,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
sa_column: Column[Any] | UndefinedType = Undefined,
Expand DownExpand Up@@ -420,7 +436,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand All@@ -445,10 +465,17 @@ def Field(
warnings.warn(MAX_ITEMS_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
if max_length is None:
max_length = max_items
if regex:
warnings.warn(REGEX_PARAM_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
for param_name in ("pattern",):
if param_name in current_schema_extra:
msg = f"Pass `{param_name}` parameter directly to Field instead of passing it via `schema_extra`"
warnings.warn(msg, UserWarning, stacklevel=2)

# Extract possible alias settings from schema_extra so we can control precedence
schema_validation_alias = current_schema_extra.pop("validation_alias", None)
schema_serialization_alias = current_schema_extra.pop("serialization_alias", None)
current_pattern = pattern or regex or current_schema_extra.pop("pattern", None)
field_info_kwargs = {
"alias": alias,
"title": title,
Expand All@@ -467,7 +494,7 @@ def Field(
"min_length": min_length,
"max_length": max_length,
"allow_mutation": allow_mutation,
"regex": regex,
"pattern": current_pattern,
Comment thread
stickm4n marked this conversation as resolved.
"discriminator": discriminator,
"repr": repr,
"primary_key": primary_key,
Expand Down
35 changes: 35 additions & 0 deletions tests/test_pydantic/test_field.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,3 +120,38 @@ class Model(SQLModel):
Model(items=[1, 2, 3])
assert len(exc_info.value.errors()) == 1
assert exc_info.value.errors()[0]["type"] == "too_long"


def test_regex():
with pytest.warns(DeprecationWarning, match="The `regex` parameter is deprecated"):

class DateModel(SQLModel):
date_1: str = Field(regex=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern():
class DateModel(SQLModel):
date_1: str = Field(pattern=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern_via_schema_extra():
with pytest.warns(
UserWarning,
match="Pass `pattern` parameter directly to Field instead of passing it via `schema_extra`",
):

class DateModel(SQLModel):
date_1: str = Field(schema_extra={"pattern": r"^\d{2}-\d{2}-\d{4}$"})

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6afa967
Add compatibility for Pydantic V2 regex (renamed param from regex to …
stickm4n Dec 1, 2024
e19734f
Merge branch 'fastapi:main' into main
stickm4n Feb 22, 2025
2d6bb87
Merge branch 'main' into main
svlandeg Feb 24, 2025
5de3c0b
Add test for field regex/pattern parameter
stickm4n Aug 30, 2025
926bd78
Split test case with `VaidationError` into two
YuriiMotov Oct 7, 2025
f45a40f
Fix failing test
YuriiMotov Oct 7, 2025
a26b384
Merge branch 'main' into main
YuriiMotov Oct 7, 2025
2b6de42
Merge branch 'main' into main
svlandeg Oct 8, 2025
71cb27d
Merge branch 'fastapi:main' into main
stickm4n Oct 11, 2025
91e8e7e
Remove unused ignore comment
stickm4n Oct 12, 2025
8e9105b
Merge remote-tracking branch 'upstream/main' into stickM4N_main
YuriiMotov Jan 28, 2026
57c6c53
Deprecate `regex` parameter in favor of `pattern`
YuriiMotov Jan 28, 2026
01b3954
Add warning when `pattern` is passed via `schema_extra`
YuriiMotov Jan 28, 2026
570be83
Rename tests
YuriiMotov Jan 28, 2026
2b342da
Update deprecations to be consistent with other PRs
YuriiMotov Jan 28, 2026
6eda60a
Merge branch 'main' into main
YuriiMotov Feb 21, 2026
879d4b8
Fix `discriminator` type annotation
YuriiMotov Feb 21, 2026
7ecd621
Merge branch 'main' into main
YuriiMotov Apr 3, 2026
1acc4b9
Update type hints for regex and pattern parameters to support `re.Pat…
stickm4n Apr 5, 2026
98a52b1
Remove support for `re.Pattern` in regex parameter type hints
stickm4n Apr 5, 2026
cfc88f3
Add `re` import in main.py
stickm4n Apr 5, 2026
f7f9b5f
Merge branch 'fastapi:main' into main
stickm4n Jul 14, 2026
bc43eb7
Merge branch 'main' into main
YuriiMotov Sep 1, 2026
54d0764
🎨 Auto format
pre-commit-ci-lite[bot] Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions sqlmodel/main.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@

import builtins
import ipaddress
import re
import uuid
import warnings
from collections.abc import Callable, Mapping, Sequence, Set
Expand DownExpand Up@@ -97,6 +98,9 @@
MAX_ITEMS_DEPRECATION_MSG = (
"`max_items` is deprecated and will be removed, use `max_length` instead"
)
REGEX_PARAM_DEPRECATION_MSG = (
"The `regex` parameter is deprecated. \nUse `pattern` parameter instead."
)


def __dataclass_transform__(
Expand DownExpand Up@@ -274,7 +278,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -323,7 +331,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -381,7 +393,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
sa_column: Column[Any] | UndefinedType = Undefined,
Expand DownExpand Up@@ -420,7 +436,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand All@@ -445,10 +465,17 @@ def Field(
warnings.warn(MAX_ITEMS_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
if max_length is None:
max_length = max_items
if regex:
warnings.warn(REGEX_PARAM_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
for param_name in ("pattern",):
if param_name in current_schema_extra:
msg = f"Pass `{param_name}` parameter directly to Field instead of passing it via `schema_extra`"
warnings.warn(msg, UserWarning, stacklevel=2)

# Extract possible alias settings from schema_extra so we can control precedence
schema_validation_alias = current_schema_extra.pop("validation_alias", None)
schema_serialization_alias = current_schema_extra.pop("serialization_alias", None)
current_pattern = pattern or regex or current_schema_extra.pop("pattern", None)
field_info_kwargs = {
"alias": alias,
"title": title,
Expand All@@ -467,7 +494,7 @@ def Field(
"min_length": min_length,
"max_length": max_length,
"allow_mutation": allow_mutation,
"regex": regex,
"pattern": current_pattern,
Comment thread
stickm4n marked this conversation as resolved.
"discriminator": discriminator,
"repr": repr,
"primary_key": primary_key,
Expand Down
35 changes: 35 additions & 0 deletions tests/test_pydantic/test_field.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,3 +120,38 @@ class Model(SQLModel):
Model(items=[1, 2, 3])
assert len(exc_info.value.errors()) == 1
assert exc_info.value.errors()[0]["type"] == "too_long"


def test_regex():
with pytest.warns(DeprecationWarning, match="The `regex` parameter is deprecated"):

class DateModel(SQLModel):
date_1: str = Field(regex=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern():
class DateModel(SQLModel):
date_1: str = Field(pattern=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern_via_schema_extra():
with pytest.warns(
UserWarning,
match="Pass `pattern` parameter directly to Field instead of passing it via `schema_extra`",
):

class DateModel(SQLModel):
date_1: str = Field(schema_extra={"pattern": r"^\d{2}-\d{2}-\d{4}$"})

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6afa967
Add compatibility for Pydantic V2 regex (renamed param from regex to …
stickm4n Dec 1, 2024
e19734f
Merge branch 'fastapi:main' into main
stickm4n Feb 22, 2025
2d6bb87
Merge branch 'main' into main
svlandeg Feb 24, 2025
5de3c0b
Add test for field regex/pattern parameter
stickm4n Aug 30, 2025
926bd78
Split test case with `VaidationError` into two
YuriiMotov Oct 7, 2025
f45a40f
Fix failing test
YuriiMotov Oct 7, 2025
a26b384
Merge branch 'main' into main
YuriiMotov Oct 7, 2025
2b6de42
Merge branch 'main' into main
svlandeg Oct 8, 2025
71cb27d
Merge branch 'fastapi:main' into main
stickm4n Oct 11, 2025
91e8e7e
Remove unused ignore comment
stickm4n Oct 12, 2025
8e9105b
Merge remote-tracking branch 'upstream/main' into stickM4N_main
YuriiMotov Jan 28, 2026
57c6c53
Deprecate `regex` parameter in favor of `pattern`
YuriiMotov Jan 28, 2026
01b3954
Add warning when `pattern` is passed via `schema_extra`
YuriiMotov Jan 28, 2026
570be83
Rename tests
YuriiMotov Jan 28, 2026
2b342da
Update deprecations to be consistent with other PRs
YuriiMotov Jan 28, 2026
6eda60a
Merge branch 'main' into main
YuriiMotov Feb 21, 2026
879d4b8
Fix `discriminator` type annotation
YuriiMotov Feb 21, 2026
7ecd621
Merge branch 'main' into main
YuriiMotov Apr 3, 2026
1acc4b9
Update type hints for regex and pattern parameters to support `re.Pat…
stickm4n Apr 5, 2026
98a52b1
Remove support for `re.Pattern` in regex parameter type hints
stickm4n Apr 5, 2026
cfc88f3
Add `re` import in main.py
stickm4n Apr 5, 2026
f7f9b5f
Merge branch 'fastapi:main' into main
stickm4n Jul 14, 2026
bc43eb7
Merge branch 'main' into main
YuriiMotov Sep 1, 2026
54d0764
🎨 Auto format
pre-commit-ci-lite[bot] Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions sqlmodel/main.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@

import builtins
import ipaddress
import re
import uuid
import warnings
from collections.abc import Callable, Mapping, Sequence, Set
Expand DownExpand Up@@ -97,6 +98,9 @@
MAX_ITEMS_DEPRECATION_MSG = (
"`max_items` is deprecated and will be removed, use `max_length` instead"
)
REGEX_PARAM_DEPRECATION_MSG = (
"The `regex` parameter is deprecated. \nUse `pattern` parameter instead."
)


def __dataclass_transform__(
Expand DownExpand Up@@ -274,7 +278,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -323,7 +331,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand DownExpand Up@@ -381,7 +393,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
sa_column: Column[Any] | UndefinedType = Undefined,
Expand DownExpand Up@@ -420,7 +436,11 @@ def Field(
min_length: int | None = None,
max_length: int | None = None,
allow_mutation: bool = True,
regex: str | None = None,
regex: Annotated[
str | None,
deprecated(REGEX_PARAM_DEPRECATION_MSG),
] = None,
pattern: str | re.Pattern[str] | None = None,
discriminator: str | Discriminator | None = None,
repr: bool = True,
primary_key: bool | UndefinedType = Undefined,
Expand All@@ -445,10 +465,17 @@ def Field(
warnings.warn(MAX_ITEMS_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
if max_length is None:
max_length = max_items
if regex:
warnings.warn(REGEX_PARAM_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
for param_name in ("pattern",):
if param_name in current_schema_extra:
msg = f"Pass `{param_name}` parameter directly to Field instead of passing it via `schema_extra`"
warnings.warn(msg, UserWarning, stacklevel=2)

# Extract possible alias settings from schema_extra so we can control precedence
schema_validation_alias = current_schema_extra.pop("validation_alias", None)
schema_serialization_alias = current_schema_extra.pop("serialization_alias", None)
current_pattern = pattern or regex or current_schema_extra.pop("pattern", None)
field_info_kwargs = {
"alias": alias,
"title": title,
Expand All@@ -467,7 +494,7 @@ def Field(
"min_length": min_length,
"max_length": max_length,
"allow_mutation": allow_mutation,
"regex": regex,
"pattern": current_pattern,
Comment thread
stickm4n marked this conversation as resolved.
"discriminator": discriminator,
"repr": repr,
"primary_key": primary_key,
Expand Down
35 changes: 35 additions & 0 deletions tests/test_pydantic/test_field.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,3 +120,38 @@ class Model(SQLModel):
Model(items=[1, 2, 3])
assert len(exc_info.value.errors()) == 1
assert exc_info.value.errors()[0]["type"] == "too_long"


def test_regex():
with pytest.warns(DeprecationWarning, match="The `regex` parameter is deprecated"):

class DateModel(SQLModel):
date_1: str = Field(regex=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern():
class DateModel(SQLModel):
date_1: str = Field(pattern=r"^\d{2}-\d{2}-\d{4}$")

DateModel(date_1="12-31-2024")

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")


def test_pattern_via_schema_extra():
with pytest.warns(
UserWarning,
match="Pass `pattern` parameter directly to Field instead of passing it via `schema_extra`",
):

class DateModel(SQLModel):
date_1: str = Field(schema_extra={"pattern": r"^\d{2}-\d{2}-\d{4}$"})

with pytest.raises(ValidationError):
DateModel(date_1="incorrect")
Loading