Module tinytroupe.factory.tiny_factory
Expand source code
import copy
import random
from tinytroupe.factory import logger
import tinytroupe.utils as utils
class TinyFactory:
"""
A base class for various types of factories. This is important because it makes it easier to extend the system, particularly
regarding transaction caching.
"""
# common randomizer used for samplings, with a default initial seed to allow for reproducibility.
# subclases can use this directly as well.
randomizer = random.Random(42)
# A dict of all factories created so far.
all_factories = {} # name -> factories
def __init__(self, simulation_id:str=None) -> None:
"""
Initialize a TinyFactory instance.
Args:
simulation_id (str, optional): The ID of the simulation. Defaults to None.
"""
self.name = f"Factory {utils.fresh_id(self.__class__.__name__)}" # we need a name, but no point in making it customizable
self.simulation_id = simulation_id
TinyFactory.add_factory(self)
def __repr__(self):
return f"TinyFactory(name='{self.name}')"
@staticmethod
def set_simulation_for_free_factories(simulation):
"""
Sets the simulation if it is None. This allows free environments to be captured by specific simulation scopes
if desired.
"""
for factory in TinyFactory.all_factories.values():
if factory.simulation_id is None:
simulation.add_factory(factory)
@staticmethod
def add_factory(factory):
"""
Adds a factory to the list of all factories. Factory names must be unique,
so if an factory with the same name already exists, an error is raised.
"""
if factory.name in TinyFactory.all_factories:
raise ValueError(f"Factory names must be unique, but '{factory.name}' is already defined.")
else:
TinyFactory.all_factories[factory.name] = factory
@classmethod
def clear_factories(cls):
"""
Clears the global list of all factories.
"""
cls.all_factories = {}
cls._clear_factories()
@classmethod
def _clear_factories(cls):
"""
Additional cleanup actions can be performed here by subclasses if needed.
"""
pass
################################################################################################
# Caching mechanisms
#
# Factories can also be cached in a transactional way. This is necessary because the agents they
# generate can be cached, and we need to ensure that the factory itself is also cached in a
# consistent way.
################################################################################################
def encode_complete_state(self) -> dict:
"""
Encodes the complete state of the factory. If subclasses have elmements that are not serializable, they should override this method.
"""
state = copy.deepcopy(self.__dict__)
return state
def decode_complete_state(self, state:dict):
"""
Decodes the complete state of the factory. If subclasses have elmements that are not serializable, they should override this method.
"""
state = copy.deepcopy(state)
self.__dict__.update(state)
return self
Classes
class TinyFactory (simulation_id: str = None)
-
A base class for various types of factories. This is important because it makes it easier to extend the system, particularly regarding transaction caching.
Initialize a TinyFactory instance.
Args
simulation_id
:str
, optional- The ID of the simulation. Defaults to None.
Expand source code
class TinyFactory: """ A base class for various types of factories. This is important because it makes it easier to extend the system, particularly regarding transaction caching. """ # common randomizer used for samplings, with a default initial seed to allow for reproducibility. # subclases can use this directly as well. randomizer = random.Random(42) # A dict of all factories created so far. all_factories = {} # name -> factories def __init__(self, simulation_id:str=None) -> None: """ Initialize a TinyFactory instance. Args: simulation_id (str, optional): The ID of the simulation. Defaults to None. """ self.name = f"Factory {utils.fresh_id(self.__class__.__name__)}" # we need a name, but no point in making it customizable self.simulation_id = simulation_id TinyFactory.add_factory(self) def __repr__(self): return f"TinyFactory(name='{self.name}')" @staticmethod def set_simulation_for_free_factories(simulation): """ Sets the simulation if it is None. This allows free environments to be captured by specific simulation scopes if desired. """ for factory in TinyFactory.all_factories.values(): if factory.simulation_id is None: simulation.add_factory(factory) @staticmethod def add_factory(factory): """ Adds a factory to the list of all factories. Factory names must be unique, so if an factory with the same name already exists, an error is raised. """ if factory.name in TinyFactory.all_factories: raise ValueError(f"Factory names must be unique, but '{factory.name}' is already defined.") else: TinyFactory.all_factories[factory.name] = factory @classmethod def clear_factories(cls): """ Clears the global list of all factories. """ cls.all_factories = {} cls._clear_factories() @classmethod def _clear_factories(cls): """ Additional cleanup actions can be performed here by subclasses if needed. """ pass ################################################################################################ # Caching mechanisms # # Factories can also be cached in a transactional way. This is necessary because the agents they # generate can be cached, and we need to ensure that the factory itself is also cached in a # consistent way. ################################################################################################ def encode_complete_state(self) -> dict: """ Encodes the complete state of the factory. If subclasses have elmements that are not serializable, they should override this method. """ state = copy.deepcopy(self.__dict__) return state def decode_complete_state(self, state:dict): """ Decodes the complete state of the factory. If subclasses have elmements that are not serializable, they should override this method. """ state = copy.deepcopy(state) self.__dict__.update(state) return self
Subclasses
Class variables
var all_factories
var randomizer
Static methods
def add_factory(factory)
-
Adds a factory to the list of all factories. Factory names must be unique, so if an factory with the same name already exists, an error is raised.
Expand source code
@staticmethod def add_factory(factory): """ Adds a factory to the list of all factories. Factory names must be unique, so if an factory with the same name already exists, an error is raised. """ if factory.name in TinyFactory.all_factories: raise ValueError(f"Factory names must be unique, but '{factory.name}' is already defined.") else: TinyFactory.all_factories[factory.name] = factory
def clear_factories()
-
Clears the global list of all factories.
Expand source code
@classmethod def clear_factories(cls): """ Clears the global list of all factories. """ cls.all_factories = {} cls._clear_factories()
def set_simulation_for_free_factories(simulation)
-
Sets the simulation if it is None. This allows free environments to be captured by specific simulation scopes if desired.
Expand source code
@staticmethod def set_simulation_for_free_factories(simulation): """ Sets the simulation if it is None. This allows free environments to be captured by specific simulation scopes if desired. """ for factory in TinyFactory.all_factories.values(): if factory.simulation_id is None: simulation.add_factory(factory)
Methods
def decode_complete_state(self, state: dict)
-
Decodes the complete state of the factory. If subclasses have elmements that are not serializable, they should override this method.
Expand source code
def decode_complete_state(self, state:dict): """ Decodes the complete state of the factory. If subclasses have elmements that are not serializable, they should override this method. """ state = copy.deepcopy(state) self.__dict__.update(state) return self
def encode_complete_state(self) ‑> dict
-
Encodes the complete state of the factory. If subclasses have elmements that are not serializable, they should override this method.
Expand source code
def encode_complete_state(self) -> dict: """ Encodes the complete state of the factory. If subclasses have elmements that are not serializable, they should override this method. """ state = copy.deepcopy(self.__dict__) return state