base-typed-string 0.1.0__tar.gz → 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. {base_typed_string-0.1.0/src/base_typed_string.egg-info → base_typed_string-0.1.2}/PKG-INFO +35 -2
  2. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/README.md +33 -1
  3. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/pyproject.toml +2 -1
  4. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/src/base_typed_string/__init__.py +1 -1
  5. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/src/base_typed_string/_base_typed_string.py +11 -4
  6. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/src/base_typed_string/_exceptions.py +1 -1
  7. {base_typed_string-0.1.0 → base_typed_string-0.1.2/src/base_typed_string.egg-info}/PKG-INFO +35 -2
  8. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/src/base_typed_string.egg-info/requires.txt +1 -0
  9. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/tests/test_runtime_behavior.py +8 -0
  10. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/LICENSE +0 -0
  11. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/setup.cfg +0 -0
  12. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/src/base_typed_string/py.typed +0 -0
  13. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/src/base_typed_string.egg-info/SOURCES.txt +0 -0
  14. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/src/base_typed_string.egg-info/dependency_links.txt +0 -0
  15. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/src/base_typed_string.egg-info/top_level.txt +0 -0
  16. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/tests/test_constructor.py +0 -0
  17. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/tests/test_internal_invariants.py +0 -0
  18. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/tests/test_pickle_support.py +0 -0
  19. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/tests/test_pydantic_support.py +0 -0
  20. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/tests/testing_assertions.py +0 -0
  21. {base_typed_string-0.1.0 → base_typed_string-0.1.2}/tests/testing_types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: base-typed-string
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Strict typed string base class with exact runtime subtype preservation and optional Pydantic v2 support.
5
5
  Author-email: Eldeniz Guseinli <eldenizfamilyanskicode@gmail.com>
6
6
  License-Expression: MIT
@@ -26,6 +26,7 @@ Requires-Dist: pydantic<3,>=2.6; extra == "pydantic"
26
26
  Provides-Extra: test
27
27
  Requires-Dist: pytest>=8.0; extra == "test"
28
28
  Requires-Dist: pytest-cov>=5.0; extra == "test"
29
+ Requires-Dist: pydantic<3,>=2.6; extra == "test"
29
30
  Provides-Extra: lint
30
31
  Requires-Dist: ruff>=0.5; extra == "lint"
31
32
  Provides-Extra: typecheck
@@ -101,7 +102,6 @@ domain-specific names in type annotations, while keeping real `str` behavior at
101
102
  - no normalization
102
103
  - no regex engine
103
104
  - no domain-specific methods
104
- - no custom JSON layer
105
105
 
106
106
  This package is intentionally minimal.
107
107
 
@@ -446,6 +446,39 @@ assert type(restored_email) is EmailAddress
446
446
 
447
447
  ---
448
448
 
449
+ ## JSON behavior
450
+
451
+ Since `BaseTypedString` inherits from `str`, standard JSON serialization naturally produces plain JSON strings.
452
+
453
+ ```python
454
+ import json
455
+
456
+ from base_typed_string import BaseTypedString
457
+
458
+
459
+ class EmailAddress(BaseTypedString):
460
+ pass
461
+
462
+
463
+ value: EmailAddress = EmailAddress("hello@example.com")
464
+ serialized_value: str = json.dumps(value)
465
+ restored_value: object = json.loads(serialized_value)
466
+
467
+ assert serialized_value == '"hello@example.com"'
468
+ assert restored_value == "hello@example.com"
469
+ assert type(restored_value) is str
470
+ ```
471
+
472
+ This behavior is intentional.
473
+
474
+ JSON is a plain data boundary.
475
+
476
+ The exact runtime subtype exists only inside Python objects.
477
+ After serialization, values become plain strings and do not carry subtype information.
478
+
479
+ ---
480
+
481
+
449
482
  ## Public API
450
483
 
451
484
  ```python
@@ -54,7 +54,6 @@ domain-specific names in type annotations, while keeping real `str` behavior at
54
54
  - no normalization
55
55
  - no regex engine
56
56
  - no domain-specific methods
57
- - no custom JSON layer
58
57
 
59
58
  This package is intentionally minimal.
60
59
 
@@ -399,6 +398,39 @@ assert type(restored_email) is EmailAddress
399
398
 
400
399
  ---
401
400
 
401
+ ## JSON behavior
402
+
403
+ Since `BaseTypedString` inherits from `str`, standard JSON serialization naturally produces plain JSON strings.
404
+
405
+ ```python
406
+ import json
407
+
408
+ from base_typed_string import BaseTypedString
409
+
410
+
411
+ class EmailAddress(BaseTypedString):
412
+ pass
413
+
414
+
415
+ value: EmailAddress = EmailAddress("hello@example.com")
416
+ serialized_value: str = json.dumps(value)
417
+ restored_value: object = json.loads(serialized_value)
418
+
419
+ assert serialized_value == '"hello@example.com"'
420
+ assert restored_value == "hello@example.com"
421
+ assert type(restored_value) is str
422
+ ```
423
+
424
+ This behavior is intentional.
425
+
426
+ JSON is a plain data boundary.
427
+
428
+ The exact runtime subtype exists only inside Python objects.
429
+ After serialization, values become plain strings and do not carry subtype information.
430
+
431
+ ---
432
+
433
+
402
434
  ## Public API
403
435
 
404
436
  ```python
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "base-typed-string"
7
- version = "0.1.0"
7
+ version = "0.1.2"
8
8
  description = "Strict typed string base class with exact runtime subtype preservation and optional Pydantic v2 support."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -40,6 +40,7 @@ pydantic = [
40
40
  test = [
41
41
  "pytest>=8.0",
42
42
  "pytest-cov>=5.0",
43
+ "pydantic>=2.6,<3",
43
44
  ]
44
45
  lint = [
45
46
  "ruff>=0.5",
@@ -12,4 +12,4 @@ __all__: list[str] = [
12
12
  "BaseTypedStringInvariantViolationError",
13
13
  ]
14
14
 
15
- __version__: str = "0.1.0"
15
+ __version__: str = "0.1.2"
@@ -29,9 +29,9 @@ class BaseTypedString(str):
29
29
 
30
30
  def __new__(
31
31
  cls: type[BaseTypedStringType],
32
- value: Any,
32
+ value: str,
33
33
  ) -> BaseTypedStringType:
34
- if not isinstance(value, str):
34
+ if not isinstance(value, str): # pyright: ignore[reportUnnecessaryIsInstance] runtime boundary guard
35
35
  raise BaseTypedStringInvalidInputValueError(
36
36
  "BaseTypedString must be initialized only with str. "
37
37
  f"Got: {type(value).__name__}."
@@ -39,7 +39,6 @@ class BaseTypedString(str):
39
39
 
40
40
  return str.__new__(cls, value)
41
41
 
42
-
43
42
  @classmethod
44
43
  def __get_pydantic_core_schema__(
45
44
  cls,
@@ -56,8 +55,13 @@ class BaseTypedString(str):
56
55
  Serialization:
57
56
  - serializes as plain str
58
57
  """
58
+ del source_type
59
+ del handler
60
+
59
61
  try:
60
- from pydantic_core import core_schema
62
+ from pydantic_core import ( # pyright: ignore[reportMissingImports]
63
+ core_schema,
64
+ )
61
65
  except ImportError as import_error:
62
66
  raise BaseTypedStringInvariantViolationError(
63
67
  "pydantic-core is required to build BaseTypedString schema."
@@ -82,3 +86,6 @@ class BaseTypedString(str):
82
86
  self,
83
87
  ) -> tuple[type[BaseTypedString], tuple[str]]:
84
88
  return (self.__class__, (str(self),))
89
+
90
+ def __repr__(self) -> str:
91
+ return f"{self.__class__.__name__}({str(self)!r})"
@@ -7,4 +7,4 @@ class BaseTypedStringInvalidInputValueError(BaseTypedStringError, TypeError):
7
7
 
8
8
 
9
9
  class BaseTypedStringInvariantViolationError(BaseTypedStringError):
10
- """Raised when an internal invariant or contract is violated."""
10
+ """Raised when an internal invariant or contract is violated."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: base-typed-string
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Strict typed string base class with exact runtime subtype preservation and optional Pydantic v2 support.
5
5
  Author-email: Eldeniz Guseinli <eldenizfamilyanskicode@gmail.com>
6
6
  License-Expression: MIT
@@ -26,6 +26,7 @@ Requires-Dist: pydantic<3,>=2.6; extra == "pydantic"
26
26
  Provides-Extra: test
27
27
  Requires-Dist: pytest>=8.0; extra == "test"
28
28
  Requires-Dist: pytest-cov>=5.0; extra == "test"
29
+ Requires-Dist: pydantic<3,>=2.6; extra == "test"
29
30
  Provides-Extra: lint
30
31
  Requires-Dist: ruff>=0.5; extra == "lint"
31
32
  Provides-Extra: typecheck
@@ -101,7 +102,6 @@ domain-specific names in type annotations, while keeping real `str` behavior at
101
102
  - no normalization
102
103
  - no regex engine
103
104
  - no domain-specific methods
104
- - no custom JSON layer
105
105
 
106
106
  This package is intentionally minimal.
107
107
 
@@ -446,6 +446,39 @@ assert type(restored_email) is EmailAddress
446
446
 
447
447
  ---
448
448
 
449
+ ## JSON behavior
450
+
451
+ Since `BaseTypedString` inherits from `str`, standard JSON serialization naturally produces plain JSON strings.
452
+
453
+ ```python
454
+ import json
455
+
456
+ from base_typed_string import BaseTypedString
457
+
458
+
459
+ class EmailAddress(BaseTypedString):
460
+ pass
461
+
462
+
463
+ value: EmailAddress = EmailAddress("hello@example.com")
464
+ serialized_value: str = json.dumps(value)
465
+ restored_value: object = json.loads(serialized_value)
466
+
467
+ assert serialized_value == '"hello@example.com"'
468
+ assert restored_value == "hello@example.com"
469
+ assert type(restored_value) is str
470
+ ```
471
+
472
+ This behavior is intentional.
473
+
474
+ JSON is a plain data boundary.
475
+
476
+ The exact runtime subtype exists only inside Python objects.
477
+ After serialization, values become plain strings and do not carry subtype information.
478
+
479
+ ---
480
+
481
+
449
482
  ## Public API
450
483
 
451
484
  ```python
@@ -22,6 +22,7 @@ pydantic<3,>=2.6
22
22
  [test]
23
23
  pytest>=8.0
24
24
  pytest-cov>=5.0
25
+ pydantic<3,>=2.6
25
26
 
26
27
  [typecheck]
27
28
  mypy>=1.10
@@ -120,6 +120,14 @@ def test_typed_string_has_same_hash_and_equality_as_plain_string() -> None:
120
120
  assert hash(typed_value) == hash(plain_value)
121
121
 
122
122
 
123
+ def test_repr_uses_exact_runtime_subtype_name_and_plain_string_value() -> None:
124
+ typed_value: AdminUserName = AdminUserName("root")
125
+
126
+ rendered_value: str = repr(typed_value)
127
+
128
+ assert rendered_value == "AdminUserName('root')"
129
+
130
+
123
131
  def test_plain_class_attribute_preserves_exact_runtime_subtype() -> None:
124
132
  typed_value: UserName = UserName("alice")
125
133