larray.CheckedSession

class larray.CheckedSession(*args, meta=None, **kwargs)[source]

Class intended to be inherited by user defined classes in which the variables of a model are declared. Each declared variable is constrained by a type defined explicitly or deduced from the given default value (see examples below). All classes inheriting from CheckedSession will have access to all methods of the Session class.

The special CheckedArray type represents an Array object with fixed axes and/or dtype. This prevents users from modifying the dimensions (and labels) and/or the dtype of an array by mistake and make sure that the definition of an array remains always valid in the model.

By declaring variables, users will speed up the development of their models using the auto-completion (the feature in which development tools like PyCharm try to predict the variable or function a user intends to enter after only a few characters have been typed).

As for normal Session objects, it is still possible to add undeclared variables to instances of classes inheriting from CheckedSession but this must be done with caution.

Parameters
*argsstr or dict of {str: object} or iterable of tuples (str, object)

Path to the file containing the session to load or list/tuple/dictionary containing couples (name, object).

**kwargsdict of {str: object}
  • Objects to add written as name=object

  • metalist of pairs or dict or Metadata, optional

    Metadata (title, description, author, creation_date, …) associated with the array. Keys must be strings. Values must be of type string, int, float, date, time or datetime.

Warning

The CheckedSession.filter(), CheckedSession.compact() and CheckedSession.apply() methods return a simple Session object. The type of the declared variables (and the value for the declared constants) will no longer be checked.

Examples

Content of file ‘parameters.py’

>>> from larray import *
>>> FIRST_YEAR = 2020
>>> LAST_YEAR = 2030
>>> AGE = Axis('age=0..10')
>>> GENDER = Axis('gender=male,female')
>>> TIME = Axis(f'time={FIRST_YEAR}..{LAST_YEAR}')

Content of file ‘model.py’

>>> class ModelVariables(CheckedSession):
...     # --- declare variables with defined types ---
...     # Their values will be defined at runtime but must match the specified type.
...     birth_rate: Array
...     births: Array
...     # --- declare variables with a default value ---
...     # The default value will be used to set the variable if no value is passed at instantiation (see below).
...     # Their type is deduced from their default value and cannot be changed at runtime.
...     target_age = AGE[:2] >> '0-2'
...     population = zeros((AGE, GENDER, TIME), dtype=int)
...     # --- declare checked arrays ---
...     # The checked arrays have axes assumed to be "frozen", meaning they are
...     # constant all along the execution of the program.
...     mortality_rate: CheckedArray((AGE, GENDER))
...     # For checked arrays, the default value can be given as a scalar.
...     # Optionally, a dtype can be also specified (defaults to float).
...     deaths: CheckedArray((AGE, GENDER, TIME), dtype=int) = 0
>>> variant_name = "baseline"
>>> # Instantiation --> create an instance of the ModelVariables class.
>>> # Warning: All variables declared without a default value must be set.
>>> m = ModelVariables(birth_rate = zeros((AGE, GENDER)),
...                    births = zeros((AGE, GENDER, TIME), dtype=int),
...                    mortality_rate = 0)
>>> # ==== model ====
>>> # In the definition of ModelVariables, the 'birth_rate' variable, has been declared as an Array object.
>>> # This means that the 'birth_rate' variable will always remain of type Array.
>>> # Any attempt to assign a non-Array value to 'birth_rate' will make the program to crash.
>>> m.birth_rate = Array([0.045, 0.055], GENDER)    # OK
>>> m.birth_rate = [0.045, 0.055]                   # Fails
Traceback (most recent call last):
    ...
pydantic.errors.ArbitraryTypeError: instance of Array expected
>>> # However, the arrays 'birth_rate', 'births' and 'population' have not been declared as 'CheckedArray'.
>>> # Thus, axes and dtype of these arrays are not protected, leading to potentially unexpected behavior
>>> # of the model.
>>> # example 1: Let's say we want to calculate the new births for the year 2025 and we assume that
>>> # the birth rate only differ by gender.
>>> # In the line below, we add an additional TIME axis to 'birth_rate' while it was initialized
>>> # with the AGE and GENDER axes only
>>> m.birth_rate = full((AGE, GENDER, TIME), fill_value=Array([0.045, 0.055], GENDER))
>>> # here 'new_births' have the AGE, GENDER and TIME axes instead of the AGE and GENDER axes only
>>> new_births = m.population['female', 2025] * m.birth_rate
>>> print(new_births.info)
11 x 2 x 11
 age [11]: 0 1 2 ... 8 9 10
 gender [2]: 'male' 'female'
 time [11]: 2020 2021 2022 ... 2028 2029 2030
dtype: float64
memory used: 1.89 Kb
>>> # and the line below will crash
>>> m.births[2025] = new_births         
Traceback (most recent call last):
    ...
ValueError: Value {time} axis is not present in target subset {age, gender}.
A value can only have the same axes or fewer axes than the subset being targeted
>>> # now let's try to do the same for deaths and making the same mistake as for 'birth_rate'.
>>> # The program will crash now at the first step instead of letting you go further
>>> m.mortality_rate = full((AGE, GENDER, TIME), fill_value=sequence(AGE, inc=0.02))            
Traceback (most recent call last):
    ...
ValueError: Array 'mortality_rate' was declared with axes {age, gender} but got array with axes
{age, gender, time} (unexpected {time} axis)
>>> # example 2: let's say we want to calculate the new births for all years.
>>> m.birth_rate = full((AGE, GENDER, TIME), fill_value=Array([0.045, 0.055], GENDER))
>>> new_births = m.population['female'] * m.birth_rate
>>> # here 'new_births' has the same axes as 'births' but is a float array instead of
>>> # an integer array as 'births'.
>>> # The line below will make the 'births' array become a float array while
>>> # it was initialized as an integer array
>>> m.births = new_births
>>> print(m.births.info)
11 x 11 x 2
 age [11]: 0 1 2 ... 8 9 10
 time [11]: 2020 2021 2022 ... 2028 2029 2030
 gender [2]: 'male' 'female'
dtype: float64
memory used: 1.89 Kb
>>> # now let's try to do the same for deaths.
>>> m.mortality_rate = full((AGE, GENDER), fill_value=sequence(AGE, inc=0.02))
>>> # here the result of the multiplication of the 'population' array by the 'mortality_rate' array
>>> # is automatically converted to an integer array
>>> m.deaths = m.population * m.mortality_rate
>>> print(m.deaths.info)                            
11 x 2 x 11
 age [11]: 0 1 2 ... 8 9 10
 gender [2]: 'male' 'female'
 time [11]: 2020 2021 2022 ... 2028 2029 2030
dtype: int32
memory used: 968 bytes

It is possible to add undeclared variables to a checked session but this will print a warning:

>>> m.undeclared_var = 'my_value'                   
UserWarning: 'undeclared_var' is not declared in 'ModelVariables'
>>> # ==== output ====
>>> # save all variables in an HDF5 file
>>> m.save(f'{variant_name}.h5', display=True)      
dumping birth_rate ... done
dumping births ... done
dumping mortality_rate ... done
dumping deaths ... done
dumping target_age ... done
dumping population ... done
dumping undeclared_var ... done
__init__(*args, meta=None, **kwargs)[source]

Methods

__init__(*args[, meta])

add(*args, **kwargs)

Deprecated.

apply(func, *args[, kind])

Apply function func on elements of the session and return a new session.

array_equals(**kwargs)

compact([display])

Detect and remove "useless" axes (ie axes for which values are constant over the whole axis) for all array objects in session.

copy()

Return a copy of the session.

dict([exclude])

dump(**kwargs)

dump_csv(**kwargs)

dump_excel(**kwargs)

dump_hdf(**kwargs)

element_equals(other[, rtol, atol, nans_equal])

Test if each element (group, axis and array) of the current session equals the corresponding element of another session.

equals(other[, rtol, atol, nans_equal])

Test if all elements (groups, axes and arrays) of the current session are equal to those of another session.

filter([pattern, kind])

Return a new session with objects which match some criteria.

get(key[, default])

Return the object corresponding to the key.

items()

Return a view of the session's items ((key, value) pairs).

keys()

Return a view on the session's keys.

load(fname[, names, engine, display])

Load objects from a file, or several .csv files.

save(fname[, names, engine, overwrite, display])

Dump objects from the current session to a file, or several .csv files.

summary([template])

Return a summary of the content of the session.

to_csv(fname[, names, display])

Dump Array objects from the current session to CSV files.

to_excel(fname[, names, overwrite, display])

Dump Array objects from the current session to an Excel file.

to_globals([names, depth, warn, inplace])

Create global variables out of objects in the session.

to_hdf(fname[, names, overwrite, display])

Dump objects from the current session to an HDF file.

to_pickle(fname[, names, overwrite, display])

Dump objects from the current session to a file using pickle.

transpose(*args)

Reorder axes of arrays in session, ignoring missing axes for each array.

update([other])

Update the session with the key/value pairs from other or passed keyword arguments, overwriting existing keys.

values()

Return a view on the session's values.

Attributes

memory_used

Return the memory consumed by the session in human readable form.

meta

Return metadata of the session.

names

Return the list of names of the objects in the session.

nbytes

Return the memory in bytes consumed by the session.