Namespace¶
Immutable namespaces are similar to types.SimpleNamespace, but
prevent any modification of attributes after creation. This makes them ideal for
configuration objects, settings, or any data structure that should remain
completely unchanged after initialization.
>>> from frigid import Namespace
Let’s illustrate this with a configuration namespace for a database connection:
>>> db_config = Namespace(
... host = 'localhost',
... port = 5432,
... name = 'myapp',
... user = 'admin',
... password = 'secret',
... pool_size = 10,
... ssl = True,
... )
Initialization¶
Immutable namespaces can be initialized from zero or more dictionaries or iterables over key-value pairs and zero or more keyword arguments.
>>> # From key-value pairs
>>> cache = Namespace(
... [ ( 'backend', 'redis' ), ( 'timeout', 300 ) ],
... )
>>> # From dictionary
>>> logging = Namespace(
... { 'level': 'INFO', 'format': '%(levelname)s: %(message)s' },
... )
>>> # Mixed initialization
>>> server = Namespace(
... { 'host': 'example.com' },
... [ ( 'port', 443 ) ],
... ssl = True,
... workers = 4,
... )
Immutability¶
Once created, a namespace becomes completely immutable. Attempts to modify existing attributes will raise an error:
>>> db_config.port = 3306
Traceback (most recent call last):
...
frigid.exceptions.AttributeImmutabilityError: Cannot assign or delete attribute 'port'.
Attempts to delete attributes are also prevented:
>>> del db_config.password
Traceback (most recent call last):
...
frigid.exceptions.AttributeImmutabilityError: Cannot assign or delete attribute 'password'.
Unlike types.SimpleNamespace, new attributes cannot be added after
creation:
>>> db_config.timeout = 30
Traceback (most recent call last):
...
frigid.exceptions.AttributeImmutabilityError: Cannot assign or delete attribute 'timeout'.
Attribute Access¶
Attributes can be accessed normally through dot notation:
>>> db_config.host
'localhost'
>>> db_config.port
5432
Attempting to access non-existent attributes raises an AttributeError:
>>> db_config.missing
Traceback (most recent call last):
...
AttributeError: 'Namespace' object has no attribute 'missing'
Representation¶
Namespaces have a clear string representation that shows all their attributes:
>>> cache
frigid.namespaces.Namespace( backend = 'redis', timeout = 300 )
>>> logging
frigid.namespaces.Namespace( level = 'INFO', format = '%(levelname)s: %(message)s' )
Empty namespaces are also represented appropriately:
>>> empty = Namespace()
>>> empty
frigid.namespaces.Namespace( )
Comparison¶
Namespaces can be compared with other namespaces or SimpleNamespaces. Two namespaces are considered equal if they have the same attributes with the same values:
>>> from types import SimpleNamespace
>>> ns1 = Namespace( x = 1, y = 2 )
>>> ns2 = Namespace( x = 1, y = 2 )
>>> ns3 = SimpleNamespace( x = 1, y = 2 )
>>> ns1 == ns2 # Same type, same content
True
>>> ns1 == ns3 # Different type, same content
True
>>> ns1 == Namespace( x = 1, z = 3 ) # Different content
False
Copying¶
To create a copy of a namespace, access its underlying __dict__ and use it
to initialize a new namespace:
>>> original = Namespace( x = 1, y = 2 )
>>> copy = Namespace( **original.__dict__ ) #**
>>> original == copy
True
This pattern is particularly useful when you need to create a modified version of an existing configuration:
>>> # Create new dict with overridden values
>>> test_config = dict( db_config.__dict__ )
>>> test_config.update( name = 'test_myapp', host = 'test.localhost' )
>>> test_db = Namespace( **test_config ) #**
>>> test_db.name
'test_myapp'
>>> test_db.port # Preserved from original
5432