{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tech Meeting 2024 Q1 - Enumerations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The technical meeting that took place on 2024.04.03 related to the Q1 sprints covered the following topics:\n", "\n", "1. Running an analysis whilst modifying the `.ini` configuration files.\n", "2. Usage of enumerations within `ra2ce`.\n", "3. Discussion on long term views for `ra2ce` subprojects.\n", "4. Walk-through, on how to add new analyses to the current solution.\n", "\n", "This jupyter notebook will cover the second point." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Usage of enumerations within `ra2ce`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Enumerations ([enum](https://docs.python.org/3/library/enum.html)) are introduced in `ra2ce` mostly to declare, and therefore distinguish, all the different properties that may influence the creation of a `network` or the run of an `analysis`.\n", "\n", "These enums are, in short, the different possibilities that can be found at the `network.ini` or `analysis.ini` section properties.\n", "\n", "During development of new functionalities, or introduction of new configuration properties, more enumerations could be created or current ones extended. We will see how this works in this section." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.1. Available enums" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "At the current version `v0.8.1` the following enumerations are present:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In `ra2ce.network.network_config_data.enums`:\n", "\n", "- AggregateWlEnum,\n", "- NetworkTypeEnum,\n", "- PartOfDayEnum,\n", "- RoadTypeEnum,\n", "- SourceEnum" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from ra2ce.network.network_config_data.enums.network_type_enum import NetworkTypeEnum\n", "\n", "for _network_type in NetworkTypeEnum:\n", " print(_network_type)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In `ra2ce.analysis.analysis_config_data.enums`:\n", "\n", "- AnalysisDirectEnum,\n", "- AnalysisIndirectEnum,\n", "- DamageCurveEnum,\n", "- EventTypeEnum,\n", "- LossTypeEnum,\n", "- RiskCalculationModeEnum,\n", "- TripPurposesEnum,\n", "- WeighingEnum" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from ra2ce.analysis.analysis_config_data.enums.analysis_losses_enum import AnalysisLossesEnum\n", "\n", "for _losses_type in AnalysisLossesEnum:\n", " print(_losses_type)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.2. Ra2ceEnumBase" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In order to normalize how we handle all our enumerations, a base class `Ra2ceEnumBase` (`ra2ce.configuration.ra2ce_enum_base`) is created (not that this __is not__ an [abstract class](https://docs.python.org/3/library/abc.html)).\n", "\n", "All our enumerations implement said base class and therefore __inherit__ its methods and definitions.\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.1. Creating a new enum" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can check its functionality by first creating our own enumeration here." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from ra2ce.configuration.ra2ce_enum_base import Ra2ceEnumBase\n", "\n", "class DocumentationEnum(Ra2ceEnumBase):\n", " NONE = 0\n", " ALL = 1\n", " EXAMPLE = 2\n", " RESEARCH = 3\n", " TECH_MEETING = 4\n", " ARCHITECTURE = 5\n", " DOMAIN = 6\n", " INVALID = 99" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In our enumeration we see two sides, the name that we will use throughout the code (left side) and its associated value (right side). In short, we are just binding said names to a __unique__ value so that python handles everything internally whilst we can write 'readable' code.\n", "\n", "Some pointers for creation / modification of enums here:\n", "\n", "- Add new properties after the latest logical value. Sometimes you may find the last two values are `BANANA = 3` and `MIX = 100`, choose then to add the next value as `PINEAPPLE = 4` instead of `PINEAPPLE = 101`.\n", "- Always define the names with capital letters.\n", "- Try to use simplify the names whilst still being readable.\n", "- Do not modify existing values unless previously discussed with the development team.\n", "- When inheriting from `Ra2ceEnumBase`: `NONE=0` is an optional entry, whilst `INVALID=99` is a mandatory one." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.2. Using the inherited methods / properties" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now start testing what the `Ra2ceEnumBase` does with our `DocumentationEnum` example" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- `get_enum(str|None)` will help us getting the associated `ra2ce` enum for a given string." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "assert DocumentationEnum.get_enum(\"banana\") == DocumentationEnum.INVALID\n", "assert DocumentationEnum.get_enum(None) == DocumentationEnum.NONE\n", "assert DocumentationEnum.get_enum(\"\") == DocumentationEnum.NONE\n", "assert DocumentationEnum.get_enum(\"reSEarch\") == DocumentationEnum.RESEARCH" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- `is_valid()` verifies whether the selected enum property is something we consider 'valid'.\n", "This method can be later on 'overriden' so that we could determine more options which are not 'valid' ones." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "assert DocumentationEnum.NONE.is_valid()\n", "assert DocumentationEnum.INVALID.is_valid() is False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class DocumentationEnumIsValidOverriden(Ra2ceEnumBase):\n", " NONE = 0\n", " ALL = 1\n", " EXAMPLE = 2\n", " RESEARCH = 3\n", " TECH_MEETING = 4\n", " ARCHITECTURE = 5\n", " DOMAIN = 6\n", " INVALID = 99\n", "\n", " def is_valid(self) -> bool:\n", " # We extend the current definition so that both \n", " # `EXAMPLE` and `TECH_MEETING` are not consider valid documents.\n", " if self in [\n", " DocumentationEnumIsValidOverriden.EXAMPLE,\n", " DocumentationEnumIsValidOverriden.TECH_MEETING]:\n", " return False\n", " return super().is_valid()\n", "\n", "assert DocumentationEnumIsValidOverriden.TECH_MEETING.is_valid() is False\n", "assert DocumentationEnumIsValidOverriden.EXAMPLE.is_valid() is False\n", "assert DocumentationEnumIsValidOverriden.ARCHITECTURE.is_valid()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- `list_valid_options()` returns all the options mapped as 'valid'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"Default valid options:\")\n", "for _valid_option in DocumentationEnum.list_valid_options():\n", " print(_valid_option)\n", "\n", "print(\"\\nValid options when overriding:\")\n", "for _valid_option in DocumentationEnumIsValidOverriden.list_valid_options():\n", " print(_valid_option)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- `config_value` will return how the enum is to be represented in the config file (`.ini`)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for _option in DocumentationEnum:\n", " print(f\"{_option}: {_option.config_value}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But again, this could be easily overriden if desired." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class DocumentationEnumConfigValueOverriden(Ra2ceEnumBase):\n", " NONE = 0\n", " ALL = 1\n", " EXAMPLE = 2\n", " RESEARCH = 3\n", " TECH_MEETING = 4\n", " ARCHITECTURE = 5\n", " DOMAIN = 6\n", " INVALID = 99\n", "\n", " @property\n", " def config_value(self) -> str | None:\n", " if \"_\" in self.name:\n", " _words = [_word.capitalize() for _word in self.name.split(\"_\")]\n", " return \" \".join(_words)\n", " return super().__str__()\n", "\n", "print(DocumentationEnumConfigValueOverriden.TECH_MEETING)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.13" } }, "nbformat": 4, "nbformat_minor": 2 }