types - Common data types¶
Overview¶
This module provides collection of classes that are often used by other library modules or applications.
Exceptions¶
- exception firebird.base.types.Error(*args, **kwargs)[source]¶
Bases:
ExceptionException intended as a base for application-related errors.
Unlike the standard
Exception, this class accepts arbitrary keyword arguments during initialization. These keyword arguments are stored as attributes on the exception instance.Attribute lookup on instances of
Error(or its subclasses) will returnNonefor any attribute that was not explicitly set via keyword arguments during__init__, preventingAttributeErrorfor common checks.Important
Attribute lookup on this class never fails, as all attributes that are not actually set, have
Nonevalue. The special attribute__notes__(used byadd_notesince Python 3.11) is explicitly excluded from this behavior to ensure compatibility.Example:
try: if condition: raise Error("Error message", err_code=1) else: raise Error("Unknown error") except Error as e: if e.err_code is None: ... elif e.err_code == 1: ...
Note
Warnings are not errors and should typically derive from
Warning, not this class.
Singletons¶
Singleton is a pattern that restricts the instantiation of a class to one “single” instance. This is useful when exactly one object is needed to coordinate actions across the system.
Common uses:
The abstract factory, factory method, builder, and prototype patterns can use singletons in their implementation.
Facade objects are often singletons because only one facade object is required.
State objects are often singletons.
Singletons are often preferred to global variables because:
They do not pollute the global namespace with unnecessary variables.
They permit lazy allocation and initialization.
To create your own singletons, use Singleton as the base class.
example
>>> class MySingleton(Singleton):
... "Description"
... ...
...
>>> obj1 = MySingleton()
>>> obj1 = MySingleton()
>>> obj1 is obj2
True
- class firebird.base.types.Singleton(*args, **kwargs)[source]¶
Bases:
objectBase class for singletons.
Ensures that only one instance of a class derived from
Singletonexists. Subsequent attempts to ‘create’ an instance will return the existing one.Important
If a descendant class’s
__init__method accepts arguments, these arguments are only used the first time the instance is created. Subsequent calls that retrieve the cached instance will not invoke__init__again.Example:
class MyService(Singleton): def __init__(self, config_param=None): if hasattr(self, '_initialized'): # Prevent re-init return print("Initializing MyService...") self.config = config_param self._initialized = True def do_something(self): print(f"Doing something with config: {self.config}") service1 = MyService("config1") # Prints "Initializing MyService..." service2 = MyService("config2") # Does *not* print, returns existing instance print(service1 is service2) # Output: True service2.do_something() # Output: Doing something with config: config1
- Return type:
Sentinels¶
The Sentinel Object pattern is a standard Pythonic approach that’s used both in the
Standard Library and beyond. The pattern most often uses Python’s built-in None object,
but in situations where None might be a useful value, a unique sentinel object() can be
used instead to indicate missing or unspecified data, or other specific condition.
However, the plain object() sentinel has not very useful str and repr values.
The Sentinel class provides named sentinels, with meaningful str and repr.
- class firebird.base.types.Sentinel(name, bases=None, namespace=None, /, *, repr=None)[source]¶
Bases:
_SentinelMetaBase class for creating unique sentinel objects.
Sentinels are special singleton objects used to signal unique states or conditions, particularly useful when
Nonemight be a valid data value. They offer a more explicit and readable alternative to magic constants or usingobject().You can define specific sentinels in two primary ways:
By Subclassing: Inherit directly from
Sentinel. The name of the subclass becomes the sentinel’s identity.class DEFAULT(Sentinel): "Represents a default value placeholder." class ALL(Sentinel): "Represents all possible values."
This creates classes
DEFAULTandALL, each acting as a unique sentinel object.Using the Functional Call: Use the
Sentinelbase class itself as a factory function.# Signature: Sentinel(name: str, *, repr: str | None = None) -> Sentinel NOT_FOUND = Sentinel("NOT_FOUND", repr="<Value Not Found>") UNKNOWN = Sentinel("UNKNOWN")
The required
nameargument (e.g.,"NOT_FOUND") specifies the__name__of the dynamically created sentinel class.The optional
reprkeyword argument provides a custom string to be returned byrepr()for this specific sentinel. If omitted,repr()defaults to the sentinel’s name.
This dynamically creates new classes derived from
Sentinel, assigns them to the variables (NOT_FOUND,UNKNOWN), and sets a custom__repr__if provided.
Behavior:
Regardless of the creation method:
Each sentinel is a unique object (a class behaving as a singleton).
Sentinels are identified using the
isoperator.They cannot be instantiated (e.g.,
DEFAULT()raisesTypeError).They cannot be subclassed further after their initial definition.
str(MySentinel)returns the sentinel’s name (MySentinel.__name__).repr(MySentinel)returns the customreprif provided via the functional call, otherwise it defaults to the sentinel’s name.
Example Usage:
# Define using subclassing class DEFAULT_SETTING(Sentinel): "Indicates a setting should use its compiled-in default." # Define using functional call with custom repr NOT_APPLICABLE = Sentinel("NOT_APPLICABLE", repr="<N/A>") def get_config(key, user_override=NOT_APPLICABLE): if user_override is NOT_APPLICABLE: # User did not provide an override, check stored config value = read_stored_config(key, default=DEFAULT_SETTING) if value is DEFAULT_SETTING: return get_hardcoded_default(key) return value else: # User provided an override (which could be None) return user_override config1 = get_config("timeout") # Uses stored or hardcoded default config2 = get_config("retries", user_override=None) # Explicitly set to None config3 = get_config("feature_flag", user_override=NOT_APPLICABLE) # Same as providing nothing print(repr(DEFAULT_SETTING)) # Output: DEFAULT_SETTING print(repr(NOT_APPLICABLE)) # Output: <N/A>
Predefined sentinels¶
- firebird.base.types.NOT_FOUND = NOT_FOUND[source]¶
Sentinel that denotes a condition when value was not found
- firebird.base.types.SUSPEND = SUSPEND[source]¶
Sentinel that denotes suspend request (in message queue)
Distinct objects¶
Some complex data structures or data processing algorithms require unique object identification (ie object identity). In Python, an object identity is defined internally as unique instance identity that is not suitable for complex objects whose identity is derived from content.
The Distinct abstract base class is intended as a unified solution to these needs.
See also
module firebird.base.collections
- class firebird.base.types.Distinct[source]¶
Bases:
ABCAbstract base class for objects with distinct instances based on a key.
Instances are considered equal (
==) if their keys, returned byget_key(), are equal. The hash of an instance is derived from the hash of its key by default.Important
If used with
@dataclass, it must be defined witheq=Falseto prevent overriding the custom__eq__and__hash__methods:from dataclasses import dataclass @dataclass(eq=False) class MyDistinctData(Distinct): id: int name: str def get_key(self) -> Hashable: return self.id
- class firebird.base.types.CachedDistinct(*args, **kwargs)[source]¶
Bases:
DistinctAbstract
Distinctdescendant that caches instances.Behaves like
Distinct, but ensures only one instance is created per unique key. Subsequent attempts to create an instance with the same key (as determined byextract_keyfrom the constructor arguments) will return the cached instance instead of creating a new one.Instances are stored in a class-level
WeakValueDictionary, allowing them to be garbage-collected if no longer referenced elsewhere.Requires implementation of both
get_key()(for instance equality/hashing) andextract_key()(for retrieving the key from constructor arguments before instance creation). These two methods should conceptually return the same identifier for a given object identity.Important
Like
Distinct, if used with@dataclass, define witheq=False.Example:
from dataclasses import dataclass @dataclass(eq=False) # Important! class User(CachedDistinct): user_id: int name: str def get_key(self) -> int: return self.user_id @classmethod def extract_key(cls, user_id: int, name: str) -> int: # Extracts the key from __init__ args return user_id user1 = User(1, "Alice") user2 = User(2, "Bob") user3 = User(1, "Alice") # Name might be different here, but key is the same print(user1 is user3) # Output: True (cached instance returned) print(user1 == user3) # Output: True (equality based on get_key) print(user1 is user2) # Output: False
- Return type:
- abstract classmethod extract_key(*args, **kwargs) Hashable[source]¶
Returns key from arguments passed to
__init__().Important
The key is used to store instance in cache. It should be the same as key returned by instance
Distinct.get_key()!- Return type:
Enums¶
- class firebird.base.types.ByteOrder(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]¶
Bases:
EnumByte order for storing numbers in binary
MemoryBuffer.- BIG = 'big'¶
- LITTLE = 'little'¶
- NETWORK = 'big'¶
- class firebird.base.types.ZMQTransport(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]¶
Bases:
IntEnumZeroMQ transport protocol.
- EPGM = 5¶
- INPROC = 1¶
- IPC = 2¶
- PGM = 4¶
- TCP = 3¶
- UNKNOWN = 0¶
- VMCI = 6¶
Custom string types¶
Some string values have unified structure and carry specific information (like network
address or database connection string). Typical repeating operation with these values
are validation and parsing. It makes sense to put these operations under one roof.
One such approach uses custom descendants of builtin str type.
Caution
Custom string types have an inherent weakness. They support all inherited string methods,
but any method that returns string value return a base str type, not the descendant class
type. That same apply when you assign strings to variables that should be of custom
string type.
Tip
Module strconv could help you to safely translate strings stored
externally to typed strings.
- class firebird.base.types.ZMQAddress(value: AnyStr, encoding: str = 'utf8')[source]¶
Bases:
strZeroMQ endpoint address.
It behaves like
str, but checks that value is valid ZMQ endpoint address, has additional R/O properties and meaningfulrepr().- Raises:
ValueError – When string value passed to constructor is not a valid ZMQ endpoint address.
- Parameters:
value (AnyStr) –
encoding (str) –
- Return type:
Self
Example:
addr_str = "tcp://127.0.0.1:5555" zmq_addr = ZMQAddress(addr_str) print(zmq_addr) # Output: tcp://127.0.0.1:5555 print(repr(zmq_addr)) # Output: ZMQAddress('tcp://127.0.0.1:5555') print(zmq_addr.protocol) # Output: ZMQTransport.TCP print(zmq_addr.address) # Output: 127.0.0.1:5555 print(zmq_addr.domain) # Output: ZMQDomain.NODE try: invalid = ZMQAddress("myfile.txt") except ValueError as e: print(e) # Output: Protocol specification required
- property protocol: ZMQTransport¶
Transport protocol (e.g., TCP, IPC, INPROC).
- class firebird.base.types.MIME(value: str)[source]¶
Bases:
strMIME type specification string (e.g., ‘text/plain; charset=utf-8’).
Behaves like
str, but validates the input format (type/subtype[;params]) upon creation and provides convenient read-only properties to access parts of the specification.- Raises:
ValueError – If the input string is not a valid MIME type specification (missing ‘/’, unsupported type, invalid parameters).
- Parameters:
value (str) –
- Return type:
Self
Example:
mime1_str = "application/json" mime1 = MIME(mime1_str) print(mime1) # Output: application/json print(repr(mime1)) # Output: MIME('application/json') print(mime1.type) # Output: application print(mime1.subtype) # Output: json print(mime1.params) # Output: {} mime2_str = "text/html; charset=UTF-8" mime2 = MIME(mime2_str) print(mime2.mime_type) # Output: text/html print(mime2.params) # Output: {'charset': 'UTF-8'} try: invalid_mime = MIME("application") except ValueError as e: print(e) # Output: MIME type specification must be 'type/subtype[;param=value;...]' try: invalid_mime = MIME("myapp/data") # 'myapp' is not a standard type except ValueError as e: print(e) # Output: MIME type 'myapp' not supported
- class firebird.base.types.PyExpr(value: str)[source]¶
Bases:
strSource code string representing a single Python expression.
Behaves like
str, but validates that the content is a syntactically valid Python expression during initialization by attempting to compile it in ‘eval’ mode. Provides access to the compiled code object and a helper to create a callable function from the expression.- Raises:
SyntaxError – If the string value is not a valid Python expression.
- Parameters:
value (str) –
- Return type:
Self
Example:
expr_str = "a + b * 2" py_expr = PyExpr(expr_str) print(py_expr) # Output: a + b * 2 print(repr(py_expr)) # Output: PyExpr('a + b * 2') # Get the compiled code object code_obj = py_expr.expr print(eval(code_obj, {'a': 10, 'b': 5})) # Output: 20 # Get a callable function func = py_expr.get_callable(arguments='a, b') print(func(a=3, b=4)) # Output: 11 # Using a namespace import math log_expr = PyExpr("math.log10(x)") log_func = log_expr.get_callable(arguments='x', namespace={'math': math}) print(log_func(x=100)) # Output: 2.0 try: invalid_expr = PyExpr("a = 5") # Assignment is not an expression except SyntaxError as e: print(e) # Output: invalid syntax (<string>, line 1) or similar
- get_callable(arguments: str = '', namespace: dict[str, Any] | None = None) Callable[source]¶
Returns the expression wrapped in a callable function.
- Parameters:
- Returns:
A callable function that takes the specified arguments and returns the result of evaluating the expression.
- Return type:
- property expr: code¶
The compiled expression code object, ready for
eval().
- class firebird.base.types.PyCode(value: str)[source]¶
Bases:
strSource code string representing a block of Python statements.
Behaves like
str, but validates that the content is a syntactically valid Python code block (potentially multiple statements) during initialization by attempting to compile it in ‘exec’ mode. Provides access to the compiled code object.- Raises:
SyntaxError – If the string value is not a valid Python code block.
- Parameters:
value (str) –
- Return type:
Self
Example:
code_str = ''' import math result = math.sqrt(x * y) print(f"Result: {result}") ''' py_code = PyCode(code_str) print(py_code[:20]) # Output: import math\nresult print(repr(py_code)) # Output: PyCode('import math\nresult = ...') # Get the compiled code object code_obj = py_code.code # Execute the code block exec_namespace = {'x': 4, 'y': 9} exec(code_obj, exec_namespace) # Output: Result: 6.0 print(exec_namespace['result']) # Output: 6.0 try: # Invalid syntax (e.g., unmatched parenthesis) invalid_code = PyCode("print('Hello'") except SyntaxError as e: print(e) # Output: unexpected EOF while parsing (<string>, line 1) or similar
- property code: code¶
The compiled Python code object, ready for
exec().
- class firebird.base.types.PyCallable(value: str)[source]¶
Bases:
strSource code string representing a Python callable (function or class definition).
Behaves like
str, but validates that the content is a syntactically valid Python function or class definition during initialization. It compiles and executes the definition to capture the resulting callable object.Instances of
PyCallableare themselves callable, acting as a proxy to the defined function or class.- Raises:
ValueError – If the string does not contain a recognizable ‘def ‘ or ‘class ‘ definition at the top level.
SyntaxError – If the string contains syntactically invalid Python code.
NameError – If the definition relies on names not available during its execution.
- Parameters:
value (str) –
- Return type:
Self
Example:
func_str = ''' def greet(name): "Greets the person." return f"Hello, {name}!" ''' py_func = PyCallable(func_str) print(py_func.name) # Output: greet print(py_func.__doc__) # Output: Greets the person. print(repr(py_func)) # Output: PyCallable('def greet(name):\n ...') # Call the instance directly message = py_func(name="World") print(message) # Output: Hello, World! class_str = ''' class MyNumber: def __init__(self, value): self.value = value def double(self): return self.value * 2 ''' py_class = PyCallable(class_str) print(py_class.name) # Output: MyNumber instance = py_class(value=10) # Instantiate the class via the PyCallable object print(instance.double()) # Output: 20 try: # Missing 'def' or 'class' invalid = PyCallable("print('Hello')") except ValueError as e: print(e) # Output: Python function or class definition not found try: # Syntax error in definition invalid = PyCallable("def my_func(x:") except SyntaxError as e: print(e) # Output: invalid syntax (<string>, line 1) or similar
Meta classes¶
- class firebird.base.types.SingletonMeta[source]¶
Bases:
typeMetaclass for
Singletonclasses.Manages internal cache of class instances. If instance for a class is in cache, it’s returned without calling the constructor, otherwise the instance is created normally and stored in cache for later use.
- class firebird.base.types._SentinelMeta(name, bases, namespace)[source]¶
Bases:
typeMetaclass for Sentinel objects.
This metaclass ensures that classes defined using it behave as proper sentinels:
They cannot be instantiated directly (e.g.,
MySentinel()).They cannot be subclassed after initial definition.
Provides a basic
__repr__and__str__based on the class name.Allows defining sentinels via class definition (
class NAME(Sentinel): ...) or potentially a functional call (though class definition is preferred).Neuters
__call__inherited fromtypeto prevent unintended behavior.
- property name¶
- class firebird.base.types.CachedDistinctMeta(name, bases, namespace, /, **kwargs)[source]¶
Bases:
ABCMetaMetaclass for
CachedDistinct.Intercepts class instantiation (
__call__) to implement the instance caching mechanism based on the key extracted bycls.extract_key(). Ensures that only one instance exists per unique key.
- firebird.base.types.conjunctive(name, bases, attrs) type[source]¶
Returns a metaclass that is conjunctive descendant of all metaclasses used by parent classes. It’s necessary to create a class with multiple inheritance, where multiple parent classes use different metaclasses.
Example
class A(type): pass
class B(type): pass
class AA(metaclass=A):pass
class BB(metaclass=B):pass
class CC(AA, BB, metaclass=Conjunctive): pass
- Return type:
Functions¶
- firebird.base.types.load(spec: str) Any[source]¶
Dynamically load an object (class, function, variable) from a module.
The module is imported automatically if it hasn’t been already.
- Parameters:
spec (str) – Object specification string in the format
'module[.submodule...]:object_name[.attribute...]'.- Returns:
The loaded object.
- Raises:
ImportError – If the module cannot be imported.
AttributeError – If the specified object cannot be found within the module.
- Return type:
Example:
# Assuming 'my_package/my_module.py' contains: class MyClass: pass MyClassRef = load("my_package.my_module:MyClass") instance = MyClassRef() # Load a function pprint_func = load("pprint:pprint") pprint_func({"a": 1})