base-typed-string 0.1.0__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.
- base_typed_string-0.1.0/LICENSE +9 -0
- base_typed_string-0.1.0/PKG-INFO +536 -0
- base_typed_string-0.1.0/README.md +489 -0
- base_typed_string-0.1.0/pyproject.toml +140 -0
- base_typed_string-0.1.0/setup.cfg +4 -0
- base_typed_string-0.1.0/src/base_typed_string/__init__.py +15 -0
- base_typed_string-0.1.0/src/base_typed_string/_base_typed_string.py +84 -0
- base_typed_string-0.1.0/src/base_typed_string/_exceptions.py +10 -0
- base_typed_string-0.1.0/src/base_typed_string/py.typed +0 -0
- base_typed_string-0.1.0/src/base_typed_string.egg-info/PKG-INFO +536 -0
- base_typed_string-0.1.0/src/base_typed_string.egg-info/SOURCES.txt +19 -0
- base_typed_string-0.1.0/src/base_typed_string.egg-info/dependency_links.txt +1 -0
- base_typed_string-0.1.0/src/base_typed_string.egg-info/requires.txt +28 -0
- base_typed_string-0.1.0/src/base_typed_string.egg-info/top_level.txt +1 -0
- base_typed_string-0.1.0/tests/test_constructor.py +86 -0
- base_typed_string-0.1.0/tests/test_internal_invariants.py +49 -0
- base_typed_string-0.1.0/tests/test_pickle_support.py +53 -0
- base_typed_string-0.1.0/tests/test_pydantic_support.py +132 -0
- base_typed_string-0.1.0/tests/test_runtime_behavior.py +135 -0
- base_typed_string-0.1.0/tests/testing_assertions.py +23 -0
- base_typed_string-0.1.0/tests/testing_types.py +20 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eldeniz Guseinli
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: base-typed-string
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Strict typed string base class with exact runtime subtype preservation and optional Pydantic v2 support.
|
|
5
|
+
Author-email: Eldeniz Guseinli <eldenizfamilyanskicode@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/eldenizfamilyanskicode/base-typed-string
|
|
8
|
+
Project-URL: Repository, https://github.com/eldenizfamilyanskicode/base-typed-string
|
|
9
|
+
Project-URL: Issues, https://github.com/eldenizfamilyanskicode/base-typed-string/issues
|
|
10
|
+
Keywords: typing,typed-string,value-object,pydantic,domain-model
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Provides-Extra: pydantic
|
|
25
|
+
Requires-Dist: pydantic<3,>=2.6; extra == "pydantic"
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Requires-Dist: pytest>=8.0; extra == "test"
|
|
28
|
+
Requires-Dist: pytest-cov>=5.0; extra == "test"
|
|
29
|
+
Provides-Extra: lint
|
|
30
|
+
Requires-Dist: ruff>=0.5; extra == "lint"
|
|
31
|
+
Provides-Extra: typecheck
|
|
32
|
+
Requires-Dist: mypy>=1.10; extra == "typecheck"
|
|
33
|
+
Requires-Dist: pyright>=1.1; extra == "typecheck"
|
|
34
|
+
Provides-Extra: build
|
|
35
|
+
Requires-Dist: build>=1.2; extra == "build"
|
|
36
|
+
Requires-Dist: twine>=5.1; extra == "build"
|
|
37
|
+
Provides-Extra: dev
|
|
38
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
39
|
+
Requires-Dist: twine>=5.1; extra == "dev"
|
|
40
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
41
|
+
Requires-Dist: pyright>=1.1; extra == "dev"
|
|
42
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
43
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
44
|
+
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
45
|
+
Requires-Dist: pydantic<3,>=2.6; extra == "dev"
|
|
46
|
+
Dynamic: license-file
|
|
47
|
+
|
|
48
|
+
# base-typed-string
|
|
49
|
+
|
|
50
|
+
Strict typed string base class with exact runtime subtype preservation.
|
|
51
|
+
|
|
52
|
+
`base_typed_string` is a small Python library for building domain-specific string types that remain real `str` objects at runtime.
|
|
53
|
+
|
|
54
|
+
It is designed for codebases where values such as `UserName`, `EmailAddress`, `AccountKey`, or `RawInputStr` should be:
|
|
55
|
+
|
|
56
|
+
- strongly named in type annotations
|
|
57
|
+
- real `str` objects at runtime
|
|
58
|
+
- serializable as plain strings
|
|
59
|
+
- reconstructable at validation boundaries
|
|
60
|
+
- lightweight and predictable
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Why
|
|
65
|
+
|
|
66
|
+
Sometimes a value is semantically important enough to deserve its own type, but operationally it should still behave like a normal Python string.
|
|
67
|
+
|
|
68
|
+
Examples:
|
|
69
|
+
|
|
70
|
+
- `UserName`
|
|
71
|
+
- `EmailAddress`
|
|
72
|
+
- `AccountKey`
|
|
73
|
+
- `RawInputStr`
|
|
74
|
+
- `IntegrationName`
|
|
75
|
+
- `ValidatedInputStr`
|
|
76
|
+
|
|
77
|
+
Using plain `str` everywhere loses domain meaning.
|
|
78
|
+
Using wrappers changes runtime behavior.
|
|
79
|
+
Using `NewType` helps only static typing.
|
|
80
|
+
|
|
81
|
+
`base_typed_string` gives you a middle ground:
|
|
82
|
+
domain-specific names in type annotations, while keeping real `str` behavior at runtime.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## What it guarantees
|
|
87
|
+
|
|
88
|
+
- accepts only `str`
|
|
89
|
+
- preserves the exact subclass type at construction time
|
|
90
|
+
- behaves like normal `str`
|
|
91
|
+
- normal string operations return plain `str`
|
|
92
|
+
- preserves subtype through pickle roundtrip
|
|
93
|
+
- supports Pydantic v2, but does not require it
|
|
94
|
+
- ships `py.typed`
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## What it intentionally does not do
|
|
99
|
+
|
|
100
|
+
- no built-in validation rules
|
|
101
|
+
- no normalization
|
|
102
|
+
- no regex engine
|
|
103
|
+
- no domain-specific methods
|
|
104
|
+
- no custom JSON layer
|
|
105
|
+
|
|
106
|
+
This package is intentionally minimal.
|
|
107
|
+
|
|
108
|
+
Domain rules should live in your subclasses or in your application layer.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Why not plain `str` / `NewType` / custom wrapper?
|
|
113
|
+
|
|
114
|
+
### Why not plain `str`?
|
|
115
|
+
|
|
116
|
+
Because plain `str` does not communicate domain intent.
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
def create_user(user_name: str, email_address: str) -> None:
|
|
120
|
+
...
|
|
121
|
+
````
|
|
122
|
+
|
|
123
|
+
This is easy to misuse:
|
|
124
|
+
|
|
125
|
+
* parameters can be swapped accidentally
|
|
126
|
+
* type annotations do not explain domain meaning
|
|
127
|
+
* static analysis cannot distinguish semantic string types
|
|
128
|
+
|
|
129
|
+
With typed subclasses:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
def create_user(user_name: UserName, email_address: EmailAddress) -> None:
|
|
133
|
+
...
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
the intent is explicit.
|
|
137
|
+
|
|
138
|
+
### Why not `typing.NewType`?
|
|
139
|
+
|
|
140
|
+
`NewType` is a static typing tool, not a runtime type.
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from typing import NewType
|
|
144
|
+
|
|
145
|
+
UserName = NewType("UserName", str)
|
|
146
|
+
|
|
147
|
+
user_name: UserName = UserName("alice")
|
|
148
|
+
|
|
149
|
+
assert type(user_name) is str
|
|
150
|
+
assert isinstance(user_name, str)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
This means:
|
|
154
|
+
|
|
155
|
+
* runtime values are still plain `str`
|
|
156
|
+
* there is no real subclass at runtime
|
|
157
|
+
* runtime boundaries cannot preserve a concrete semantic subtype
|
|
158
|
+
* introspection and runtime behavior cannot distinguish `UserName` from plain `str`
|
|
159
|
+
|
|
160
|
+
`base_typed_string` creates a real runtime subtype instead.
|
|
161
|
+
|
|
162
|
+
### Why not a custom wrapper class?
|
|
163
|
+
|
|
164
|
+
A wrapper can model a domain value, but it stops being a real string.
|
|
165
|
+
|
|
166
|
+
Typical trade-offs:
|
|
167
|
+
|
|
168
|
+
* `isinstance(value, str)` becomes `False`
|
|
169
|
+
* JSON serialization often needs custom handling
|
|
170
|
+
* many libraries expect plain `str`, not wrapper objects
|
|
171
|
+
* you often need explicit `.value` extraction
|
|
172
|
+
* interoperability becomes noisier
|
|
173
|
+
|
|
174
|
+
A wrapper is useful when you want rich behavior and strict encapsulation.
|
|
175
|
+
|
|
176
|
+
`base_typed_string` is for the opposite case:
|
|
177
|
+
keep the value operationally identical to `str`, while still having a named domain type.
|
|
178
|
+
|
|
179
|
+
### When `base_typed_string` is the right choice
|
|
180
|
+
|
|
181
|
+
Use it when you want:
|
|
182
|
+
|
|
183
|
+
* semantic string types in annotations
|
|
184
|
+
* real `str` behavior at runtime
|
|
185
|
+
* plain string serialization
|
|
186
|
+
* clean interoperability with Python and library code
|
|
187
|
+
|
|
188
|
+
Do not use it when you need:
|
|
189
|
+
|
|
190
|
+
* heavy domain logic on the value object
|
|
191
|
+
* mutable state
|
|
192
|
+
* multiple fields
|
|
193
|
+
* non-string runtime representation
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Installation
|
|
198
|
+
|
|
199
|
+
### Base package
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
pip install base-typed-string
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### With Pydantic v2 support
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
pip install "base-typed-string[pydantic]"
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
If Pydantic v2 is already installed in your project, integration works automatically.
|
|
212
|
+
|
|
213
|
+
### For development
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
pip install "base-typed-string[dev]"
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Quick start
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
from base_typed_string import BaseTypedString
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class UserName(BaseTypedString):
|
|
228
|
+
pass
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
user_name: UserName = UserName("alice")
|
|
232
|
+
|
|
233
|
+
assert user_name == "alice"
|
|
234
|
+
assert isinstance(user_name, str)
|
|
235
|
+
assert isinstance(user_name, UserName)
|
|
236
|
+
assert type(user_name) is UserName
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## How to use it in your project
|
|
242
|
+
|
|
243
|
+
Create a module for your domain string types.
|
|
244
|
+
|
|
245
|
+
For example, create a file named `domain_typings.py`:
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
from base_typed_string import BaseTypedString
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class UserName(BaseTypedString):
|
|
252
|
+
"""User login name."""
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class EmailAddress(BaseTypedString):
|
|
256
|
+
"""User email address."""
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Then use these types in your application code:
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
from .domain_typings import EmailAddress, UserName
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def create_user(user_name: UserName, email_address: EmailAddress) -> None:
|
|
266
|
+
print(user_name, email_address)
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
This gives you:
|
|
270
|
+
|
|
271
|
+
* domain-specific names in type annotations
|
|
272
|
+
* real `str` values at runtime
|
|
273
|
+
* plain string serialization behavior
|
|
274
|
+
* reconstruction through validation layers such as Pydantic
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## Runtime behavior
|
|
279
|
+
|
|
280
|
+
`BaseTypedString` is a real `str` subclass.
|
|
281
|
+
|
|
282
|
+
```python
|
|
283
|
+
from base_typed_string import BaseTypedString
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
class UserName(BaseTypedString):
|
|
287
|
+
pass
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
user_name: UserName = UserName("alice")
|
|
291
|
+
|
|
292
|
+
assert isinstance(user_name, str)
|
|
293
|
+
assert isinstance(user_name, UserName)
|
|
294
|
+
assert type(user_name) is UserName
|
|
295
|
+
assert user_name == "alice"
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Normal string operations return plain `str`
|
|
299
|
+
|
|
300
|
+
```python
|
|
301
|
+
from base_typed_string import BaseTypedString
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
class UserName(BaseTypedString):
|
|
305
|
+
pass
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
user_name: UserName = UserName("alice")
|
|
309
|
+
|
|
310
|
+
uppercased_value: str = user_name.upper()
|
|
311
|
+
concatenated_value: str = user_name + "!"
|
|
312
|
+
replaced_value: str = user_name.replace("a", "A")
|
|
313
|
+
|
|
314
|
+
assert type(uppercased_value) is str
|
|
315
|
+
assert type(concatenated_value) is str
|
|
316
|
+
assert type(replaced_value) is str
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
This behavior is intentional.
|
|
320
|
+
|
|
321
|
+
The typed subtype is preserved at construction and validation boundaries, not across ordinary string operations.
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Constructor rules
|
|
326
|
+
|
|
327
|
+
Only `str` values are accepted.
|
|
328
|
+
|
|
329
|
+
```python
|
|
330
|
+
from base_typed_string import BaseTypedString
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
class UserName(BaseTypedString):
|
|
334
|
+
pass
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
UserName("alice") # valid
|
|
338
|
+
UserName(123) # raises BaseTypedStringInvalidInputValueError
|
|
339
|
+
UserName(None) # raises BaseTypedStringInvalidInputValueError
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Existing typed string instances are also accepted because they are still real strings:
|
|
343
|
+
|
|
344
|
+
```python
|
|
345
|
+
from base_typed_string import BaseTypedString
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
class UserName(BaseTypedString):
|
|
349
|
+
pass
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
source_user_name: UserName = UserName("alice")
|
|
353
|
+
copied_user_name: UserName = UserName(source_user_name)
|
|
354
|
+
|
|
355
|
+
assert copied_user_name == "alice"
|
|
356
|
+
assert type(copied_user_name) is UserName
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Direct instantiation of the base class is also supported:
|
|
360
|
+
|
|
361
|
+
```python
|
|
362
|
+
from base_typed_string import BaseTypedString
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
plain_typed_value: BaseTypedString = BaseTypedString("value")
|
|
366
|
+
|
|
367
|
+
assert plain_typed_value == "value"
|
|
368
|
+
assert type(plain_typed_value) is BaseTypedString
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Pydantic v2 support
|
|
374
|
+
|
|
375
|
+
When used as a Pydantic field type:
|
|
376
|
+
|
|
377
|
+
* validation accepts strict strings
|
|
378
|
+
* runtime model values preserve the exact subtype
|
|
379
|
+
* exported payloads are plain strings
|
|
380
|
+
|
|
381
|
+
```python
|
|
382
|
+
from pydantic import BaseModel
|
|
383
|
+
|
|
384
|
+
from base_typed_string import BaseTypedString
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
class EmailAddress(BaseTypedString):
|
|
388
|
+
pass
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
class ContactModel(BaseModel):
|
|
392
|
+
primary_email: EmailAddress
|
|
393
|
+
backup_email: EmailAddress
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
contact_model: ContactModel = ContactModel.model_validate(
|
|
397
|
+
{
|
|
398
|
+
"primary_email": "primary@example.com",
|
|
399
|
+
"backup_email": "backup@example.com",
|
|
400
|
+
}
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
assert type(contact_model.primary_email) is EmailAddress
|
|
404
|
+
assert type(contact_model.backup_email) is EmailAddress
|
|
405
|
+
|
|
406
|
+
dumped_python: dict[str, object] = contact_model.model_dump()
|
|
407
|
+
|
|
408
|
+
assert dumped_python == {
|
|
409
|
+
"primary_email": "primary@example.com",
|
|
410
|
+
"backup_email": "backup@example.com",
|
|
411
|
+
}
|
|
412
|
+
assert type(dumped_python["primary_email"]) is str
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Important boundary
|
|
416
|
+
|
|
417
|
+
Inside the validated model, the exact subtype is preserved.
|
|
418
|
+
|
|
419
|
+
After serialization or export, values intentionally become plain strings.
|
|
420
|
+
|
|
421
|
+
This is a feature, not a bug.
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## Pickle support
|
|
426
|
+
|
|
427
|
+
Pickle roundtrip preserves the exact subtype.
|
|
428
|
+
|
|
429
|
+
```python
|
|
430
|
+
import pickle
|
|
431
|
+
|
|
432
|
+
from base_typed_string import BaseTypedString
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
class EmailAddress(BaseTypedString):
|
|
436
|
+
pass
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
source_email: EmailAddress = EmailAddress("hello@example.com")
|
|
440
|
+
serialized_email: bytes = pickle.dumps(source_email)
|
|
441
|
+
restored_email: object = pickle.loads(serialized_email)
|
|
442
|
+
|
|
443
|
+
assert restored_email == "hello@example.com"
|
|
444
|
+
assert type(restored_email) is EmailAddress
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## Public API
|
|
450
|
+
|
|
451
|
+
```python
|
|
452
|
+
from base_typed_string import BaseTypedString
|
|
453
|
+
from base_typed_string import BaseTypedStringError
|
|
454
|
+
from base_typed_string import BaseTypedStringInvalidInputValueError
|
|
455
|
+
from base_typed_string import BaseTypedStringInvariantViolationError
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### Exceptions
|
|
459
|
+
|
|
460
|
+
#### `BaseTypedStringError`
|
|
461
|
+
|
|
462
|
+
Root exception for all package-specific errors.
|
|
463
|
+
|
|
464
|
+
#### `BaseTypedStringInvalidInputValueError`
|
|
465
|
+
|
|
466
|
+
Raised when a non-string input value is provided.
|
|
467
|
+
|
|
468
|
+
#### `BaseTypedStringInvariantViolationError`
|
|
469
|
+
|
|
470
|
+
Raised when an internal invariant or contract is violated.
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
## Design notes
|
|
475
|
+
|
|
476
|
+
`BaseTypedString` is intended for projects that want domain-specific names without giving up normal `str` runtime behavior.
|
|
477
|
+
|
|
478
|
+
This is especially useful when you have many semantic string types such as:
|
|
479
|
+
|
|
480
|
+
* `AccountKey`
|
|
481
|
+
* `PromptKeyStr`
|
|
482
|
+
* `RawInputStr`
|
|
483
|
+
* `IntegrationName`
|
|
484
|
+
* `UserTextInputStr`
|
|
485
|
+
* `ValidatedInputStr`
|
|
486
|
+
|
|
487
|
+
The base class stays intentionally small so that your domain layer remains explicit and predictable.
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## Development
|
|
492
|
+
|
|
493
|
+
### Run tests
|
|
494
|
+
|
|
495
|
+
```bash
|
|
496
|
+
pytest
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### Run lint
|
|
500
|
+
|
|
501
|
+
```bash
|
|
502
|
+
ruff check .
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Run type checking
|
|
506
|
+
|
|
507
|
+
```bash
|
|
508
|
+
mypy .
|
|
509
|
+
pyright
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### Build package
|
|
513
|
+
|
|
514
|
+
```bash
|
|
515
|
+
python -m build
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### Validate distribution metadata
|
|
519
|
+
|
|
520
|
+
```bash
|
|
521
|
+
twine check dist/*
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
## Compatibility
|
|
527
|
+
|
|
528
|
+
* Python 3.10+
|
|
529
|
+
* CPython
|
|
530
|
+
* optional Pydantic v2 support
|
|
531
|
+
|
|
532
|
+
---
|
|
533
|
+
|
|
534
|
+
## License
|
|
535
|
+
|
|
536
|
+
MIT
|