I want a python type-hint friendly way to create a Type that has constrained range of values.
For example, a URL Type based on type str
that would only accept strings that look like an "http" URL.
# this code is made up and will not compile
class URL(typing.NewType('_URL', str)):
def __init__(self, value: str, *args, **kwargs):
if not (value.startswith('http://') or value.startswith('https://')):
raise ValueError('string is not an acceptable URL')
overriding built-in immutable types works well
overriding
str
; http URL stringsHere is an example overriding
str
. This does not require thetyping
module but still works with type-hinting.This
str
derived class asserts the initialized string looks like an http URL string.This results in a class that will only allow some strings. Otherwise, it behaves like an immutable
str
instance.(update: later on I found the purl Python library)
Another example,
overriding
int
; constrained integer rangeNumber
This
int
derived class only allows values1
through9
inclusive.This has a special feature, too. In case an instance is initialized with nothing (
Number()
) then that value equates to0
(this behavior is derived from theint
class). In that case, the__str__
should be a'.'
(program requirement).This ensures errant inputs are handled sooner rather than later. Otherwise, it behaves just like an
int
.And the special "feature"
Technique for inheriting immutable types is derived from this SO answer.
Subclassing builtin types can lead to some odd cases (consider code which checks exactly
type(...) is str
)Here is a pure-typing approach which is typesafe and fully preserves the type of your strings:
The approach here "hides" the runtime checking behind a function which looks like a constructor from an api perspective, but in reality is just a tiny type (I couldn't find a canonical reference to "tiny types" this appears to just be the best resource I could find).