uclchem.makerates.network ========================= .. py:module:: uclchem.makerates.network .. autoapi-nested-parse:: Unified Network implementation for UCLCHEM. This module provides the Network class and factory functions for creating networks in different contexts: - load_network_from_csv(): Load compiled networks for analysis - build_network(): Build new networks with full validation - create_network(): Direct instantiation from objects The Network class implements a complete interface for accessing and modifying chemical reaction networks, suitable for build-time and analysis-time use. For runtime parameter modification during model execution, use RuntimeNetwork from uclchem.advanced.runtime_network instead. Module Contents --------------- Classes ~~~~~~~ .. autoapisummary:: uclchem.makerates.network.BaseNetwork uclchem.makerates.network.MutableNetworkABC uclchem.makerates.network.Network uclchem.makerates.network.NetworkABC Functions ~~~~~~~~~ .. autoapisummary:: uclchem.makerates.network.build_network uclchem.makerates.network.create_network uclchem.makerates.network.load_network_from_csv Attributes ~~~~~~~~~~ .. autoapisummary:: uclchem.makerates.network.logger .. py:class:: BaseNetwork Bases: :py:obj:`NetworkABC` Base implementation providing common network operations. Implements all read and query operations that are common between Network and RuntimeNetwork. Both classes store data in _species_dict and _reactions_dict, so this base class can implement all the shared logic. Subclasses only need to: 1. Initialize _species_dict and _reactions_dict 2. Implement modification methods (change_binding_energy, change_reaction_barrier) 3. Optionally implement add/remove operations (MutableNetworkABC) .. py:method:: find_similar_reactions(reaction: uclchem.makerates.reaction.Reaction) -> dict[int, uclchem.makerates.reaction.Reaction] Find reactions with same reactants and products. :param reaction: Reaction to find similar reactions for :type reaction: Reaction :returns: Dictionary of {index: Reaction} for matching reactions :rtype: dict[int, Reaction] .. py:method:: get_reaction(reaction_idx: int) -> uclchem.makerates.reaction.Reaction Get a reaction by index (copy). :param reaction_idx: Index of the reaction :type reaction_idx: int :returns: copy of reaction with index reaction_idx. :rtype: Reaction .. py:method:: get_reaction_dict() -> dict[int, uclchem.makerates.reaction.Reaction] Get reactions dictionary (copy). :returns: copy of reaction dictionary, with keys of the indices and values of the reactions. :rtype: dict[int, Reaction] .. py:method:: get_reaction_index(reaction: uclchem.makerates.reaction.Reaction) -> int Get the index of a reaction in the network. :param reaction: Reaction to find :type reaction: Reaction :returns: Index of the reaction :rtype: int :raises ValueError: If reaction not found or multiple matches exist .. py:method:: get_reaction_list() -> list[uclchem.makerates.reaction.Reaction] Get all reactions as a list. :returns: list of all reactions in the Network. :rtype: list[Reaction] .. py:method:: get_reactions_by_types(reaction_type: str | list[str]) -> list[uclchem.makerates.reaction.Reaction] Get all reactions of specific type(s). :param reaction_type: Single type or list of types to filter by :type reaction_type: str | list[str] :returns: List of reactions matching the type(s) :rtype: list[Reaction] .. py:method:: get_specie(specie_name: str) -> uclchem.makerates.species.Species Get a species by name (copy). :param specie_name: species name :type specie_name: str :returns: copy of Species instance. :rtype: Species .. py:method:: get_species_dict() -> dict[str, uclchem.makerates.species.Species] Get species dictionary (copy). :returns: copy of species dictionary, with keys of the names of the species, and values their Species instances. :rtype: dict[str, Species] .. py:method:: get_species_list() -> list[uclchem.makerates.species.Species] Get all species as a list. :returns: list of all species in the Network. :rtype: list[Species] .. py:property:: reactions :type: dict[int, uclchem.makerates.reaction.Reaction] Get reactions dictionary. :returns: Ordered dict of reactions in the network, keyed by index. :rtype: dict[int, Reaction] .. py:property:: species :type: dict[str, uclchem.makerates.species.Species] Get species dictionary. :returns: Ordered dict of species in the network, keyed by name. :rtype: dict[str, Species] .. py:class:: MutableNetworkABC Bases: :py:obj:`NetworkABC` Extended interface for networks that support full CRUD operations. Adds add/remove/set operations for species and reactions on top of the base NetworkABC interface. Used by the Network class for build-time and analysis-time operations. NOT implemented by RuntimeNetwork since the Fortran-backed network is read directly from the fortran files, only allowing for the editing of existing reaction and species parameters. .. py:method:: add_reactions(reactions: uclchem.makerates.reaction.Reaction | list) -> None :abstractmethod: Add one or more reactions to the network. :param reactions: Reactions to add to the network. :type reactions: Reaction | list .. py:method:: add_species(species: uclchem.makerates.species.Species | list) -> None :abstractmethod: Add one or more species to the network. :param species: Species instance or list of species to add. :type species: Species | list .. py:method:: remove_reaction(reaction: uclchem.makerates.reaction.Reaction) -> None :abstractmethod: Remove a reaction from the network. :param reaction: Reaction instance to look up or modify. :type reaction: Reaction .. py:method:: remove_reaction_by_index(reaction_idx: int) -> None :abstractmethod: Remove a reaction by its index. :param reaction_idx: Index of the reaction in the network. :type reaction_idx: int .. py:method:: remove_species(specie_name: str) -> None :abstractmethod: Remove a species from the network. :param specie_name: Name of the species. :type specie_name: str .. py:method:: set_reaction(reaction_idx: int, reaction: uclchem.makerates.reaction.Reaction) -> None :abstractmethod: Set/update a reaction at a specific index. :param reaction_idx: Index of the reaction in the network. :type reaction_idx: int :param reaction: Reaction instance to look up or modify. :type reaction: Reaction .. py:method:: set_reaction_dict(new_dict: dict[int, uclchem.makerates.reaction.Reaction]) -> None :abstractmethod: Replace the entire reaction dictionary. :param new_dict: Replacement reactions dictionary. :type new_dict: dict[int, Reaction] .. py:method:: set_specie(species_name: str, species: uclchem.makerates.species.Species) -> None :abstractmethod: Set/update a species in the network. :param species_name: Name of the species. :type species_name: str :param species: Species instance or list of species to add. :type species: Species .. py:method:: set_species_dict(new_species_dict: dict[str, uclchem.makerates.species.Species]) -> None :abstractmethod: Replace the entire species dictionary. :param new_species_dict: Replacement species dictionary. :type new_species_dict: dict[str, Species] .. py:method:: sort_reactions() -> None :abstractmethod: Sort reactions by type and reactants. .. py:method:: sort_species() -> None :abstractmethod: Sort species by type and mass. .. py:class:: Network(species_dict: dict[str, uclchem.makerates.species.Species], reaction_dict: dict[int, uclchem.makerates.reaction.Reaction]) Bases: :py:obj:`BaseNetwork`, :py:obj:`MutableNetworkABC` Universal network representation for build and analysis contexts. A single Network class that serves all use cases: - Build time: Full validation and automatic reaction generation - Analysis time: Fast loading of compiled networks from CSV The Network class can be created via: - Direct instantiation: Network(species_dict, reaction_dict) - Factory methods: from_csv(), from_lists(), build() - Factory functions: load_network_from_csv(), build_network(), etc. All creation methods produce a Network instance that implements the full NetworkABC interface, ensuring consistent access patterns. For runtime parameter modification during model execution, use RuntimeNetwork from uclchem.advanced.runtime_network instead. .. attribute:: _species_dict Internal species storage {name: Species} :type: dict[str, Species] .. attribute:: _reactions_dict Internal reaction storage {index: Reaction} :type: dict[int, Reaction] .. rubric:: Examples >>> # Load for analysis >>> network = Network.from_csv() >>> # Build with validation >>> from uclchem.makerates.io_functions import read_species_file, read_reaction_file >>> from uclchem.utils import UCLCHEM_ROOT_DIR >>> >>> species_list, user_defined_bulk = read_species_file( # doctest: +SKIP ... UCLCHEM_ROOT_DIR / "../../Makerates/data/default/default_species.csv" ... ) >>> reactions_list, dropped_reactions = read_reaction_file( # doctest: +SKIP ... UCLCHEM_ROOT_DIR / "../../Makerates/data/default/default_grain_network.csv", ... species_list, ... "UCL", ... ) >>> network = Network.build( # doctest: +SKIP ... species_list, reactions_list, gas_phase_extrapolation=True ... ) Initialize network with species and reactions. This is the low-level constructor. Most users should prefer factory methods: - Network.from_csv() for analysis - Network.from_lists() for direct instantiation - Network.build() for full build with validation Or use the module-level factory functions for clearer documentation. For runtime parameter modification, use RuntimeNetwork from uclchem.advanced.runtime_network instead. :param species_dict: Species dictionary {name: Species} :type species_dict: dict[str, Species] :param reaction_dict: Reaction dictionary {index: Reaction} :type reaction_dict: dict[int, Reaction] .. py:method:: add_reactions(reactions: uclchem.makerates.reaction.Reaction | list) -> None Add reactions to network. :param reactions: Reaction object, list of Reactions, or CSV-style entries :type reactions: Reaction | list :raises ValueError: If there is an error when converting the CSV-style entries to Reaction instances :raises TypeError: If input was not a Reaction, list of Reaction instances, or CSV-style entries. .. py:method:: add_species(species: uclchem.makerates.species.Species | list) -> None Add species to network. :param species: Species object, list of Species, or CSV-style entries :type species: Species | list :raises ValueError: If there is an error when converting the CSV-style entries to Species instances :raises TypeError: If input was not a Species, list of Species instances, or CSV-style entries. .. py:method:: build(species: list[uclchem.makerates.species.Species], reactions: list[uclchem.makerates.reaction.Reaction], **build_options) -> Network :classmethod: Build network with full validation and automatic generation. This is the primary method for building new networks with full validation, automatic reaction generation (freeze-out, desorption, bulk), branching ratio checks, and all build-time operations. Delegates to NetworkBuilder. :param species: List of Species objects :type species: list[Species] :param reactions: List of Reaction objects :type reactions: list[Reaction] :param \*\*build_options: Options passed to NetworkBuilder: - user_defined_bulk: List of user-defined bulk species - gas_phase_extrapolation: bool (default False) - add_crp_photo_to_grain: bool (default False) - derive_reaction_exothermicity: list[str] or None - database_reaction_exothermicity: list[Union[str, Path]] or None :type \*\*build_options: dict :returns: Fully built and validated network :rtype: Network .. rubric:: Examples >>> from uclchem.makerates.io_functions import read_species_file, read_reaction_file >>> from uclchem.utils import UCLCHEM_ROOT_DIR >>> >>> species_list, user_defined_bulk = read_species_file( # doctest: +SKIP ... UCLCHEM_ROOT_DIR / "../../Makerates/data/default/default_species.csv" ... ) >>> reactions_list, dropped_reactions = read_reaction_file( # doctest: +SKIP ... UCLCHEM_ROOT_DIR / "../../Makerates/data/default/default_grain_network.csv", ... species_list, ... "UCL", ... ) >>> network = Network.build( # doctest: +SKIP ... species=species_list, ... reactions=reactions_list, ... gas_phase_extrapolation=True, ... add_crp_photo_to_grain=True ... ) .. py:method:: change_binding_energy(specie: str, new_binding_energy: float) -> None Change binding energy of a species. Handles special case of @H2O which affects other bulk species. :param specie: string representation of species :type specie: str :param new_binding_energy: new binding energy in K :type new_binding_energy: float :raises ValueError: If `specie` is not in the network. .. py:method:: change_reaction_barrier(reaction: uclchem.makerates.reaction.Reaction, barrier: float) -> None Change activation barrier of a reaction. Looks up reaction in Network by its reactants and products. If Fortran interface is available, also updates Fortran. :param reaction: Reaction to change. :type reaction: Reaction :param barrier: New reaction barrier in K :type barrier: float :raises RuntimeError: If multiple matching reactions are found in the network. .. py:method:: from_csv(species_path: str | bytes | pathlib.Path | None = None, reactions_path: str | bytes | pathlib.Path | None = None) -> Network :classmethod: Load network from CSV files. Loads a pre-compiled network from CSV files without any validation or automatic generation. This is the primary method for loading networks for analysis purposes. :param species_path: Path to species CSV (None = use default installation) :type species_path: str | bytes | Path | None :param reactions_path: Path to reactions CSV (None = use default installation) :type reactions_path: str | bytes | Path | None :returns: Loaded network instance :rtype: Network .. rubric:: Examples >>> # Load default compiled network >>> network = Network.from_csv() >>> # Load old/custom network for analysis >>> network = Network.from_csv('old/species.csv', 'old/reactions.csv') # doctest: +SKIP .. py:method:: from_lists(species: list[uclchem.makerates.species.Species], reactions: list[uclchem.makerates.reaction.Reaction]) -> Network :classmethod: Create network directly from lists. Direct instantiation from species and reaction lists without any validation or automatic generation. Useful for programmatic network construction or as a base for NetworkBuilder. :param species: List of Species objects :type species: list[Species] :param reactions: List of Reaction objects :type reactions: list[Reaction] :returns: Network instance :rtype: Network .. rubric:: Examples >>> from uclchem.makerates.io_functions import read_species_file, read_reaction_file >>> from uclchem.utils import UCLCHEM_ROOT_DIR >>> >>> species_list, user_defined_bulk = read_species_file( # doctest: +SKIP ... UCLCHEM_ROOT_DIR / "../../Makerates/data/default/default_species.csv" ... ) >>> reactions_list, dropped_reactions = read_reaction_file( # doctest: +SKIP ... UCLCHEM_ROOT_DIR / "../../Makerates/data/default/default_grain_network.csv", ... species_list, ... "UCL", ... ) >>> network = Network.from_lists(species_list, reactions_list) # doctest: +SKIP .. py:method:: get_all_partners(reaction: uclchem.makerates.reaction.Reaction) -> list[uclchem.makerates.reaction.Reaction] Get a list of all reactions that have ``reaction`` as their partner. :param reaction: Reaction :type reaction: Reaction :returns: **reactions_coupled_to_reaction** -- List of reactions that have ``reaction`` as their partner. :rtype: list[Reaction] :raises RuntimeError: If the partner of a :class:`CoupledReaction` instance in the network is None. .. py:method:: get_reactions_by_types(reaction_type: str | list[str]) -> list[uclchem.makerates.reaction.Reaction] Get the union of all reactions of a certain type. :param reaction_type: The reaction type to filter on :type reaction_type: str | list[str] :returns: A list of reactions of the specified type :rtype: list[Reaction] .. py:method:: remove_reaction(reaction: uclchem.makerates.reaction.Reaction) -> None Remove a reaction from network. :param reaction: Reaction to remove from the network. :type reaction: Reaction :raises RuntimeError: If multiple matching reactions are found in the network. .. py:method:: remove_reaction_by_index(reaction_idx: int) -> None Remove a reaction by its index. :param reaction_idx: Index of the reaction in the network. :type reaction_idx: int .. py:method:: remove_species(specie_name: str) -> None Remove a species from network. :param specie_name: Name of the species. :type specie_name: str .. py:method:: set_reaction(reaction_idx: int, reaction: uclchem.makerates.reaction.Reaction) -> None Set/update a reaction at specific index. :param reaction_idx: Index of the reaction in the network. :type reaction_idx: int :param reaction: Reaction instance to look up or modify. :type reaction: Reaction :raises AssertionError: If setting the reaction changes the total count of reactions. .. py:method:: set_reaction_dict(new_dict: dict[int, uclchem.makerates.reaction.Reaction]) -> None Replace entire reaction dictionary. :param new_dict: Replacement reactions dictionary. :type new_dict: dict[int, Reaction] .. py:method:: set_specie(species_name: str, species: uclchem.makerates.species.Species) -> None Set/update a species. :param species_name: Name of the species. :type species_name: str :param species: Species instance or list of species to add. :type species: Species .. py:method:: set_species_dict(new_species_dict: dict[str, uclchem.makerates.species.Species]) -> None Replace entire species dictionary. :param new_species_dict: Replacement species dictionary. :type new_species_dict: dict[str, Species] .. py:method:: sort_reactions() -> None Sort reactions by type and first reactant. :raises AssertionError: If sorting changes the total count of reactions. .. py:method:: sort_species() -> None Sort species by type and mass, with electron last. .. py:attribute:: add_crp_photo_to_grain :type: bool :value: False .. py:attribute:: database_reaction_exothermicity :type: list[str | pathlib.Path] | None :value: None .. py:attribute:: derive_reaction_exothermicity :type: list[str] | None :value: None .. py:attribute:: enthalpies_present :type: bool :value: False .. py:attribute:: excited_species :type: bool :value: False .. py:attribute:: important_reactions :type: dict[str, int | None] .. py:property:: species :type: dict[str, uclchem.makerates.species.Species] Get species dictionary. :returns: Ordered dict of species in the network, keyed by name. :rtype: dict[str, Species] .. py:attribute:: species_indices :type: dict[str, int] .. py:attribute:: user_defined_bulk :type: list :value: [] .. py:class:: NetworkABC Bases: :py:obj:`abc.ABC` Base abstract class defining the read-only network interface. Defines operations common to ALL network types: reading data, querying, and modifying existing parameters. Does NOT include add/remove operations since some implementations (like RuntimeNetwork) have fixed structure. This interface is implemented by: - Network: Full interactive network (via MutableNetworkABC) - RuntimeNetwork: Fortran-backed runtime network (read + parameter modification only) .. py:method:: change_binding_energy(specie: str, new_binding_energy: float) -> None :abstractmethod: Change binding energy of an existing species. :param specie: Name of the species. :type specie: str :param new_binding_energy: New binding energy in Kelvin. :type new_binding_energy: float .. py:method:: change_reaction_barrier(reaction: uclchem.makerates.reaction.Reaction, barrier: float) -> None :abstractmethod: Change activation barrier of an existing reaction. :param reaction: Reaction instance to look up or modify. :type reaction: Reaction :param barrier: New reaction barrier in Kelvin. :type barrier: float .. py:method:: find_similar_reactions(reaction: uclchem.makerates.reaction.Reaction) -> dict[int, uclchem.makerates.reaction.Reaction] :abstractmethod: Find reactions with same reactants/products. :param reaction: Reaction instance to look up or modify. :type reaction: Reaction .. py:method:: get_reaction(reaction_idx: int) -> uclchem.makerates.reaction.Reaction :abstractmethod: Get a specific reaction by index. :param reaction_idx: Index of the reaction in the network. :type reaction_idx: int .. py:method:: get_reaction_dict() -> dict[int, uclchem.makerates.reaction.Reaction] :abstractmethod: Get the reactions dictionary. .. py:method:: get_reaction_index(reaction: uclchem.makerates.reaction.Reaction) -> int :abstractmethod: Get the unique index of a reaction. :param reaction: Reaction instance to look up or modify. :type reaction: Reaction .. py:method:: get_reaction_list() -> list[uclchem.makerates.reaction.Reaction] :abstractmethod: Get all reactions in the network. .. py:method:: get_reactions_by_types(reaction_type: str | list[str]) -> list[uclchem.makerates.reaction.Reaction] :abstractmethod: Get all reactions of specific type(s). :param reaction_type: Reaction type label to filter on (e.g. ``'MA'``, ``'DR'``). :type reaction_type: str | list[str] .. py:method:: get_specie(specie_name: str) -> uclchem.makerates.species.Species :abstractmethod: Get a specific species by name. :param specie_name: Name of the species. :type specie_name: str .. py:method:: get_species_dict() -> dict[str, uclchem.makerates.species.Species] :abstractmethod: Get the species dictionary. .. py:method:: get_species_list() -> list[uclchem.makerates.species.Species] :abstractmethod: Get all species in the network. .. py:property:: reactions :type: dict[int, uclchem.makerates.reaction.Reaction] :abstractmethod: Get the reactions collection. .. py:property:: species :type: dict[str, uclchem.makerates.species.Species] :abstractmethod: Get the species collection. .. py:function:: build_network(species: list[uclchem.makerates.species.Species], reactions: list[uclchem.makerates.reaction.Reaction], user_defined_bulk: list | None = None, gas_phase_extrapolation: bool = False, add_crp_photo_to_grain: bool = False, derive_reaction_exothermicity: list[str] | None = None, database_reaction_exothermicity: list[str | pathlib.Path] | None = None) -> Network Build a new network with full validation and automatic generation. This is a module-level factory function that provides clear documentation and intent. It calls Network.build() internally. Use this when creating new networks at build time. This performs: - Input validation and duplicate checking - Automatic freeze-out reaction generation - Automatic bulk species and reaction generation - Automatic desorption reaction generation - Branching ratio validation and correction - Temperature range collision detection - Optional gas-phase extrapolation - Optional reaction exothermicity calculation :param species: List of Species objects :type species: list[Species] :param reactions: List of Reaction objects :type reactions: list[Reaction] :param user_defined_bulk: User-specified bulk species (optional). Defaults to ``None``. :type user_defined_bulk: list | None :param gas_phase_extrapolation: Extrapolate gas-phase reactions temperatures. Defaults to ``False``. :type gas_phase_extrapolation: bool :param add_crp_photo_to_grain: Add CRP/PHOTON reactions to grain surface. Defaults to ``False``. :type add_crp_photo_to_grain: bool :param derive_reaction_exothermicity: Reaction types to calculate exothermicity for. Defaults to ``None``. :type derive_reaction_exothermicity: list[str] | None :param database_reaction_exothermicity: Custom exothermicity database files. Defaults to ``None``. :type database_reaction_exothermicity: list[str | Path] | None :returns: Fully built and validated network :rtype: Network .. rubric:: Examples >>> from uclchem.makerates.io_functions import read_species_file, read_reaction_file >>> from uclchem.utils import UCLCHEM_ROOT_DIR >>> >>> species_list, user_defined_bulk = read_species_file( # doctest: +SKIP ... UCLCHEM_ROOT_DIR / "../../Makerates/data/default/default_species.csv" ... ) >>> reactions_list, dropped_reactions = read_reaction_file( # doctest: +SKIP ... UCLCHEM_ROOT_DIR / "../../Makerates/data/default/default_grain_network.csv", ... species_list, ... "UCL", ... ) >>> # Build network with standard options >>> network = build_network( # doctest: +SKIP ... species=species_list, ... reactions=reactions_list, ... gas_phase_extrapolation=True ... ) >>> # Build with custom exothermicity >>> network = build_network( ... species=species_list, ... reactions=reactions_list, ... derive_reaction_exothermicity=['PHOTON', 'CRP'], ... database_reaction_exothermicity=['custom_heating.csv'] ... ) # doctest: +SKIP .. py:function:: create_network(species: list[uclchem.makerates.species.Species], reactions: list[uclchem.makerates.reaction.Reaction]) -> Network Create a network directly from species and reaction lists. This is a module-level factory function that provides clear documentation and intent. It calls Network.from_lists() internally. Use this when you want direct instantiation without validation or automatic generation. Suitable for programmatic network construction or when you already have a fully prepared network. :param species: List of Species objects :type species: list[Species] :param reactions: List of Reaction objects :type reactions: list[Reaction] :returns: Network instance :rtype: Network .. rubric:: Examples >>> from uclchem.makerates.io_functions import read_species_file, read_reaction_file >>> from uclchem.utils import UCLCHEM_ROOT_DIR >>> >>> species_list, user_defined_bulk = read_species_file( # doctest: +SKIP ... UCLCHEM_ROOT_DIR / "../../Makerates/data/default/default_species.csv" ... ) >>> reactions_list, dropped_reactions = read_reaction_file( # doctest: +SKIP ... UCLCHEM_ROOT_DIR / "../../Makerates/data/default/default_grain_network.csv", ... species_list, ... "UCL", ... ) >>> >>> network = create_network(species_list, reactions_list) # doctest: +SKIP >>> >>> # Add some additional reactions >>> network.add_reactions(additional_reactions) # doctest: +SKIP .. py:function:: load_network_from_csv(species_path: str | pathlib.Path | None = None, reactions_path: str | pathlib.Path | None = None) -> Network Load a network from CSV files for analysis. This is a module-level factory function that provides clear documentation and intent. It calls Network.from_csv() internally. Use this when analyzing pre-compiled networks, comparing network versions, or loading old networks for analysis. :param species_path: Path to species CSV (None = use default installation) :type species_path: str | Path | None :param reactions_path: Path to reactions CSV (None = use default installation) :type reactions_path: str | Path | None :returns: Loaded network instance :rtype: Network .. rubric:: Examples >>> # Load default cmpiled network >>> network = load_network_from_csv() >>> # Load old version for comparison >>> old_network = load_network_from_csv( ... 'archive/v3.0/species.csv', ... 'archive/v3.0/reactions.csv' ... ) # doctest: +SKIP >>> print(f"Species added: {len(network.get_species_list()) - len(old_network.get_species_list())}") # doctest: +SKIP .. py:data:: logger