From 0dda098e0cb7a81e6351e8989c84dcfc04935668 Mon Sep 17 00:00:00 2001
From: s-roscher <stephanie.roscher@ilr.tu-berlin.de>
Date: Tue, 12 Nov 2024 16:41:19 +0100
Subject: [PATCH] - Update python-modularization.md

Maybe this works when committed, but currently the preview cannot properly display:
- @note/@warning
- \emoji

And the preview displays written marks for cross-references ({#introduction}).
---
 docs/developer/style/python-modularization.md | 350 +++++++++++++++++-
 1 file changed, 349 insertions(+), 1 deletion(-)

diff --git a/docs/developer/style/python-modularization.md b/docs/developer/style/python-modularization.md
index e5da1bc..ee44082 100644
--- a/docs/developer/style/python-modularization.md
+++ b/docs/developer/style/python-modularization.md
@@ -1 +1,349 @@
-@ todo take from Phabricator
\ No newline at end of file
+# How to Python in UNICADO
+This documentation provides a detailed overview of helpful guidelines and conventions for the use/implementation of Python code in the UNICADO framework.
+
+@note The content below is valid for UNICADO release v2.0.
+
+# Content
+- [Introduction](#introduction)
+- [Code style](#code-style)
+- [UNICADO Python philosophy](#unicado-python-philosophy)
+- [Code modularity (Python-only modules)](#code-modularity-python-only-modules)
+- [Logging and printing](#logging-and-printing)
+- [Package generation](#package-generation)
+- [Testing with Python](#testing-with-python)
+
+---
+
+# First things first ... Easter egg hunt 🪺
+
+1. Please open a Python interpreter or IDE of your choice.
+2. Start an interactive Python console.
+3. Type `import this`.
+4. Congrats! You found the _Zen of Python_.
+5. Take a few deep breaths and let the spiritual outpourings of Tim Peters work their magic on you ... \emoji lotus_position (For the less spiritual souls among us, awesome work! Allow yourself a short break before we dive deeper into the topic.)
+
+# Introduction {#introduction}
+The UNICADO Python Library is designed to streamline and standardize Python-based code development. The library consists of multiple packages within a central repository, each containing individual modules grouped by functionality. These modules house functions that perform related tasks, creating a highly modular, scalable, and manageable structure.
+
+With its structured layers and well-defined documentation and logging practices, the UNICADO Library enables developers to produce modular, reusable, and well-documented code. This guide ensures developers can build and maintain code to the standards expected within the UNICADO framework, promoting compatibility and readiness for team-based development, testing, and deployment. The result is improved code quality, reusability, and maintainability across complex projects.
+
+# Code style {#code-style}
+...
+
+## Python Enhancement Proposals (PEPs)
+Let's start with an obvious question ... [What is a PEP?](https://peps.python.org/pep-0001/#what-is-a-pep)
+
+> PEP stands for Python Enhancement Proposal. A PEP is a design document providing information to the Python community, or describing a new feature for Python or its processes or environment. The PEP should provide a concise technical specification of the feature and a rationale for the feature.
+
+There are numerous PEPs, one of which is PEP 20 (which you have already encountered as _Zen of Python_), but probably the most beautiful is ... \emoji drum
+
+... PEP 8.
+
+Wondering why?
+Great, I will tell you... [PEP 8 - Style Guide for Python Code](https://peps.python.org/pep-0008/) gives us conventions on how to write beautiful Python code. And beautiful is better than ugly, right? \emoji wink
+
+No, seriously... PEP 8 is considered a common and official Python style guide. To improve readability and ensure consistency as well as maintainability when writing new Python code, we decided to follow this recommendation and choose PEP 8 as our **Python coding standard**.
+
+## PEP 8
+- Supported by common Python IDEs.
+- Guidelines are adaptable, with internal project guidelines having a higher priority.
+- Unless otherwise stated, we adhere to the PEP 8 guidelines.
+
+At some points, the standard leaves options. These are explained in more detail below.
+
+### Code Layout
+- Tabs or spaces? Spaces
+- Maximum Line Length? 119 characters
+- Line Break Before or After a Binary Operator? Before
+
+### Naming Conventions
+- Packages: all-lowercase, starting with "py" (e.g., `pymodulepackage` or `pymathpackage`)
+- Modules: all-lowercase (e.g., `datapreprocessingmodule`)
+- Functions: `lowercase_with_underscores`
+- Variables: Descriptive variable names written in `lowercase_with_underscores`
+
+### Implementing PEP 8 into your workflow
+- Familiarize yourself with the guidelines
+- Use a linter!
+- Avoid excessive whitespace
+- Stay consistent in naming conventions
+
+## DocStrings
+- Customized DocString format based on reStructuredText (reST)
+<!-- - reST is used by default in JetBrains PyCharm: Type triple quotes `"""` after defining a function and hit Enter -->
+
+Please try to stick to the following scheme:
+
+```python
+"""Short description of the module.
+
+Long description of the module.
+
+:param type parameter_name: Description
+...
+:raises name: Description of raised error
+:return type parameter_name: Description OR
+:return: None OR
+:returns:
+    - type parameter_name: Description
+    - type parameter_name: Description
+"""
+```
+
+
+Example:
+
+```python
+    """Conduct data preprocessing.
+
+    This function provides data preprocessing functionalities. It sets up the necessary data and imports relevant modules. The importlib module is used to dynamically import necessary modules.
+
+    [...]
+
+    :param str module_configuration_file: Name of module configuration file
+    :param list argv: List with optional input arguments
+    :raises ModuleNotFoundError: Raised if module import failed
+    :returns:
+        - dict paths_and_names: Dictionary containing system paths and ElementTrees
+        - dict preprocessing_dict: Dictionary containing data preprocessing results
+        - logging.Logger runtime_output: Logging object used for capturing log messages in the module
+
+    """
+```
+
+# UNICADO Python philosophy {#unicado-python-philosophy}
+- **UNICADO** has a **library**
+- This **library** is a collection of various **packages**
+- These **packages** are a collection of several **modules**
+- These **modules** combine **functions** that belong together in terms of functionality
+
+This means, for example:
+- There is the `unicado_python_library`, which contains, for example:
+  - the `pymodulepackage`, which includes:
+    - the `datapostprocessingmodule` and
+    - the `datapreprocessingmodule`. This in turn provides the functions
+      - `read_paths_and_names`
+      - `read_xml_information`.
+
+## Excursion: What is a Module?
+- A **module** is a *.py file containing related code, allowing its functionality to be reused across different parts of an application.
+- Modules can include variables, functions, classes, and more.
+- Import modules using `import [module_name]`.
+- **Example:** Import a module named `mypythonmodule` with `import mypythonmodule`.
+- **Function Syntax:** Access functions within a module using `module.function()`.
+  - **Example:** If `mypythonmodule` contains a function `easter_egg_hunt()`, call it with `mypythonmodule.easter_egg_hunt()`.
+-  Since it is common that a module contains several functions, explicit imports can be realized using the following syntax: `from mypythonmodule import easter_egg_hunt`.
+
+# Code modularity (Python-only modules) {#code-modularity-python-only-modules}
+In the following, the modularized structure of a Python module is explained using the `cost_estimation` module. The according folder structure is shown in the following picture. It is also available for download.
+
+![](../img/_01_code-modularity.png)
+
+@warning Insert files here!
+@warning {F216186}
+
+## Layer example
+The following **layers** are selected for cost calculation:
+
+1. Aircraft configuration (e.g., `blended_wing_body` or `tube_and_wing`, golden folder)
+2. Fidelity of the calculation method (e.g., `empirical`, red folder)
+3. Calculation method (e.g., `operating_cost_estimation_tu_berlin`, green folder)
+4. Energy carrier (e.g., `kerosene` or `liquid_hydrogen`, grey folder) - **USER LAYER** (This is where the magic happens! \emoji mage)
+
+@warning Insert files/images here! {F204708, layout=middle, float, size=full}
+
+## File structure
+
+The following section gives a brief overview of the files included in the (condensed) **rAircraftDesign** repository/folder with short descriptions of their contents.
+```plaintext
+rAircraftDesign
+|- cost_estimation: Current example module
+|  |- src: Contains source code (see [1])
+|  |  |- blended_wing_body: Folder and files for blended wing body configurations (see [2])
+|  |  |- tube_and_wing: Folder and files for tube and wing configurations (see [2])
+|  |  |  | - empirical: Folder and files for empirical calculation methods (see [3])
+|  |  |  |  | - operating_cost_estimation_tu_berlin: Files and folders necessary for calculating operating costs based on the TU Berlin method ([J. Thorbeck's Documentation](https://unicado.ilr.rwth-aachen.de/w/micado_descriptions/doc_estimation/)) (see [4])
+|  |  |  |  |  | - general: [user layer] Files with functionalities independent of layer 4 value
+|  |  |  |  |  |  | - methodhtmlreport.py: Functionalities for data export to "cost_estimation.html" file (located in '...')
+|  |  |  |  |  |  | - methodplot.py: Plotting functionalities (plots saved to 'projects/CSR/CSR-02/reporting/plots')
+|  |  |  |  |  |  | - methodtexoutput.py: TeX report functionalities (output in '...')
+|  |  |  |  |  |  | - methodxmlexport.py: Data export functionalities to "cost_estimation_results.xml" file (located in 'projects/CSR/CSR-02/reporting/report_xml')
+|  |  |  |  |  | - kerosene: [user layer] Functionalities specific to kerosene
+|  |  |  |  |  |  | - methodkerosene.py: Module with calculation functions for kerosene-driven aircraft, implemented by the user
+|  |  |  |  |  | - liquid_hydrogen: [user layer] Functionalities specific to liquid hydrogen
+|  |  |  |  |  |  | - methodliquidhydrogen.py: Module with calculation functions for liquid hydrogen-driven aircraft, implemented by the user
+|  |  |  |  |  | - usermethoddatapreparation.py: Module providing functions for user data preparation
+|  |  |  | - datapostprocessing.py: Functions for data postprocessing
+|  |  |  | - datapreprocessing.py: Functions for data preprocessing
+|  |  |  | - readlayertext.py: Functions for reading layer information
+|  |- CMakeLists.txt: ...
+|  |- cost_estimation_conf.xml: General information for the cost estimation module, e.g., console output/log/report on/off settings and the path and name of the module configuration file
+|  |- cost_estimation.log: Logging messages for the current module
+|  |- main.py: Main file of the calculation module
+|- projects: Contains aircraft projects (xml files) and output folders
+|- unicado_python_library: Contains UNICADO-specific Python packages
+```
+<br>
+@note [1] At the top level, the example structure distinguishes between aircraft configurations with two branches: **blended wing body** and **tube and wing**.
+@note [2] These folders are subdivided according to **layer 2** and may contain various calculation method fidelities.
+@note [3] This folder is subdivided according to **layer 3** and may contain various calculation methods.
+@note [4] This folder is subdivided according to **layer 4** and may contain various fuel types.
+
+## Files that require changes by the module manager
+The code is designed to be highly generalized, meaning that only a few files need changes by the module manager. These files are shown in the following image and are discussed below in more detail. In some parts of the code, dynamic import commands and function names are generated, with examples provided at relevant points to illustrate how these commands work.
+
+### The `main()`
+- Update the module name in two places within the docString
+- Customize the module configuration file name
+- Adjust the `runtime_output_string`
+
+@warning Upload files/images here!
+@warning {F204719, layout=left, float, size=full}
+@warning {F204721, layout=left, float, size=full}
+@warning {F204723, layout=left, float, size=full}
+
+### The `data_preprocessing` (`datapreprocessing.py`)
+- Update the layer description in the docString
+- Customize the layer description within `layer_description_dict`. If a layer is unknown (e.g., `user_layer`), set it to 'None' rather than a path and call the relevant function (e.g., `read_energy_carrier`) as indicated (see lines 69 and following).
+
+@warning Upload files/images here!
+@warning {F204725, layout=left, float, size=full}
+@warning {F204727, layout=left, float, size=full}
+
+**Example for `module_import_name`**  
+In this example, `module_import_name` at line 68 would be: `src.tube_and_wing.empirical.operating_cost_estimation_tu_berlin`.
+
+**Example for the import command**  
+To import a module from `usermethoddatapreparation.py` at line 74, the command is as follows:  
+`src.tube_and_wing.empirical.operating_cost_estimation_tu_berlin.usermethoddatapreparation`.
+
+### The `data_postprocessing` (`datapostprocessing.py`)
+- Modify `paths_to_key_parameters_list`
+- Adjust `module_key_parameters_dict`
+
+@warning Upload files/images here!
+@warning {F204729, layout=left, float, size=full}
+@warning {F204731, layout=left, float, size=full}
+
+## Files that require changes by the user
+Similarly, the code is structured so that only a few files require modifications by the user. These files are highlighted in the following image.
+
+Note that this is an executable example code and a proposal for a structure. Generally speaking, the following files are at **user layer**:
+- `methodexport.py`
+- `methodplot.py`
+- `methodreport.py`
+- `methodkerosene.py`
+- `methodliquidhydrogen.py`
+
+Users are free to structure the code within these files but must ensure that all parameters are formatted correctly and contain all necessary values. This is especially critical for `usermethoddatapreparation.py` (not part of the user layer!), as this function handles data preparation for the user method. Here, the user must gather relevant general data from the aircraft exchange file and calculation-specific parameters from the module configuration file, submitting the data in the correct format.
+
+More detailed instructions for required changes are available within the docStrings of each corresponding file.
+
+# Logging and printing {#logging-and-printing}
+The Python framework in this project has a customized logging function, which builds on Python’s [logging facility](https://docs.python.org/3/library/logging.html). The following logging levels are available:
+
+| **Level**                  | **Numeric Value** | **Usage**                                                 | **Text Scheme**                                          |
+|----------------------------|-------------------|-----------------------------------------------------------|----------------------------------------------------------|
+| `runtime_output.debug`     | 10                | For development messages and debug information            | `runtime_output.debug("Debug: Add some text here.")`     |
+| `runtime_output.info`      | 20                | To provide additional information on calculations         | `runtime_output.info("Attention: Add some text here.")`  |
+| `runtime_output.warning`   | 30                | When something goes wrong, but the code still runs        | `runtime_output.warning("Warning: Add some text here.")` |
+| `runtime_output.print`     | 35 (default)      | For standard user output (e.g., values)                   | `runtime_output.print("Add some text here.")`            |
+| `runtime_output.error`     | 40                | For serious issues where the code can still continue      | `runtime_output.error("Error: Add some text here.")`     |
+| `runtime_output.critical`  | 50                | For critical issues that terminate the code (exit code 1) | `runtime_output.critical("Error: Add some text here.")`  |
+
+Instead of using Python's built-in `print` function, use these logging options to ensure all outputs are appropriately documented in the log file according to user settings. 
+
+## Logging configuration in the module configuration file
+User settings for logging behavior can be configured in the module configuration file under `console_output/value` and `log_file_output/value`. The available modes are as follows:
+
+| **Mode** | **Logging Levels Included**                                  |
+|----------|--------------------------------------------------------------|
+| `mode_0` | `critical`                                                   |
+| `mode_1` | `critical`, `error`, `print`, and `warning`                  |
+| `mode_2` | `critical`, `error`, `print`, `warning`, and `info`          |
+| `mode_3` | `critical`, `error`, `print`, `warning`, `info`, and `debug` |
+
+Each mode enables progressively more detailed logging, from critical errors only (`mode_0`) to full debug information (`mode_3`).
+
+# Package generation {#package-generation}
+Sources:
+- [Python packaging](https://packaging.python.org/en/latest/tutorials/packaging-projects/)
+- [Example video](https://www.youtube.com/watch?v=v6tALyc4C10&ab_channel=RealPython)
+
+According to the UNICADO Python philosophy, the UNICADO Python library contains several packages, e.g. the `pymodulepackage`. But how do I generate those packages?
+The necessary steps are listed below. Please ensure to read the respective explanations of the individual steps carefully before proceeding to the next step.
+
+**Prerequisites**
+1. Update `pip` to the latest version:
+   - **Unix/macOS:** `python3 -m pip install --upgrade pip`
+   - **Windows:** `python -m pip install --upgrade pip`
+2. Navigate to the `AircraftDesign/unicado_python_library` folder (illustrated below) to set up the required folder structure.
+
+@warning Upload files/images here!
+@warning {F204733, layout=left, float, size=full}
+
+## Step 1: Create the package subfolder
+In `unicado_python_library`, create a new subfolder for the package. Follow this naming convention:
+- **Format:** `py[name of package]package` (all lowercase, without underscores)
+- **Example:** `pymodulepackage`
+  
+Then, navigate into this subfolder.
+
+## Step 2: Create a `pyproject.toml` file
+The `pyproject.toml` file contains information on the build backend (`[build-system]`). We are using setuptools. Furthermore, this file contains core metadata for packaging-related tools to consume (`[project]`, `[project.urls]`).
+
+Please download the sample `pyproject.toml` file and complete the **highlighted fields** with package-specific information, without modifying build system details.
+
+@warning Upload files/images here!
+@warning {F204735}
+
+**Further resources:**
+- [PEP 621: Project metadata](https://peps.python.org/pep-0621/)
+- [Setuptools documentation](https://setuptools.pypa.io/en/latest/index.html)
+
+## Step 3: Create a `LICENSE` file
+Add a `LICENSE` file to define usage rights. You can download this directly here:
+
+@warning Upload files/images here!
+@warning {F204736}
+@warning Add: This file only needs to be downloaded from the repository.
+
+The [GPL-3.0 license](https://choosealicense.com/licenses/gpl-3.0/#) text is used in this example.
+
+## Step 4: Create a `README.md` file
+Download and fill out the sample `README.md` file with details about your package. This file can also be obtained from the repository.
+
+@warning Upload files/images here!
+@warning {F204737}
+@warning Add: This file only needs to be downloaded from the repository.
+
+## Step 5: Create `src` subfolder
+Inside the package folder, create a `src` subfolder to hold the `.py` files (modules).
+- **Convention:** Each `.py` file should correspond to a single module, named in this format:
+  - **Format:** `[module name]module.py` (all lowercase, no underscores)
+  - **Example:** `datapreprocessingmodule.py`
+  
+Modules can contain several functions. Once files are set up, return to the main package folder before proceeding.
+
+## Step 6: Execute installation command
+In the directory containing `pyproject.toml`, run the following installation command:
+   - **Windows:** `python -m pip install -e .`
+   - **macOS:** `python3 -m pip install -e .`
+
+**Explanation:**
+- **`-m` flag:** Specifies the module to run as a script.
+- **`-e` (editable mode):** Installs the package in editable mode, meaning changes to source code are immediately reflected.
+
+Expected output should resemble:
+```plaintext
+C:\Users\user_name\Documents\example_project\AircraftDesign\unicado_python_library\pymodulepackage>python -m pip install -e . Obtaining file:///C:/Users/user_name/Documents/example_project/AircraftDesign/unicado_python_library/pymodulepackage Installing build dependencies ... done Checking if build backend supports build_editable ... done Getting requirements to build editable ... done Installing backend dependencies ... done Preparing editable metadata (pyproject.toml) ... done Building wheels for collected packages: pymodulepackage Building editable for pymodulepackage (pyproject.toml) ... done Created wheel for pymodulepackage: filename=pymodulepackage-2.0.1-0.editable-py3-none-any.whl size=26933 sha256=11cbdd8301b02ef2e9a7daabcc87c549844e651b951c27aa78611a9f1f13df5e Stored in directory: C:\Users...... Successfully built pymodulepackage Installing collected packages: pymodulepackage Successfully installed pymodulepackage-2.0.1
+```
+
+You can check whether this command was successful by running `pip list`. If the installation was successful, the module should be listed.
+
+## Step 7: Use packages
+The modules  should now be ready to use. You can import the functions from the modules using the `from [module name] import [function name]` command. To stay with the before mentioned example:
+`from datapostprocessingmodule import paths_and_names`
+
+# Testing with Python {#testing-with-python}
+tbd. \emoji construction
\ No newline at end of file
-- 
GitLab