3.1. Structure#

The control center is a directory in your repository containing declarative configurations in data files, along with optional Python file to dynamically generate custom configurations and files during runtime.

3.1.1. Location#

By default, the control center can be found in the .control directory located at the root of your repository. You can customize its location by setting the $.control.path key in your configuration files to the desired path relative to the root of your repository.

Dynamic Directory

Like other dynamic directories in your repository, you should not manually move or rename the control center directory. Instead, after setting the new path in the configuration files, simply push the changes to your GitHub repository, or run pypackit sync locally. PyPackIT will automatically move the directory to the new location.

For example, to change the control center location to a directory at dev/control-center, you should have the following configuration in one of your YAML files (more details below):

Code 3.1.1.1 Setting the control center path to dev/control-center#
control:
  path: dev/control-center

3.1.2. Data Files#

Declarative project configurations are stored in YAML files within the control center directory.

The entire project configuration is essentially a large mapping (aka dict), where some keys have simple scalar values, while others have complex nested structures. By default, this mapping is broken down to multiple YAML files, each containing a thematically related subset of the project configurations:

You are completely free to restructure your configurations in any way you like. For example, you can have a single large YAML file with all configurations, or you can further break down the configurations into more files and subdirectories. You can even break down a single complex value (i.e., a mapping or a sequence) into multiple files, each containing a subset of the value’s data. When processing the control center, PyPackIT will automatically merge all configurations into a single mapping using the following logic:

  1. The control center directory is recursively scanned (excluding the hooks subdirectory), and all files with a .yaml or .yml extension (case-insensitive) are gathered as configuration files. Each file must represent a mapping.

  2. All key-value pairs from the collected files are recursively merged into a single mapping, where the values for the same path from different files are combined according to the following rules:

    • Mapping key-value pairs are combined. If two mappings share some keys, the values are recursively merged according to the same rules.

    • Sequences are concatenated. Note that files are always read in a shallow-first alphabetical order, so the order of concatenated sequences in the final mapping is determined by the order of the files.

    • Scalar values cannot be merged; if a scalar value is defined in multiple files, an error is raised and the conflicting paths are reported.

    • Mixed types (e.g., a sequence and a mapping) are not allowed at the same path; if such a conflict is detected, an error is raised and the conflicting paths are reported.

3.1.2.1. Configuration Paths#

We use JSONPath path expressions to refer to a specific configuration value’s location in the control center.

For example, you can set the name of your project at $.name, i.e., as the value of the name key in the top-level mapping of the control center. In which control center YAML file this key is defined (if at all) is completely up to you, as explained above.

3.1.3. Python Files#

In addition to declarative configurations in YAML files, you can also include Python files in the control center directory. These act as hooks to dynamically generate custom configurations and files during control center synchronization events. They must be added to a subdirectory named hooks at the root of the control center directory. For each type of hook, PyPackIT looks for a specific file in this directory. Before running your hooks, PyPackIT will also look for a requirements.txt file in the hooks directory, and install the specified packages using pip if found. Note that in contrast to the YAML files, the hooks directory and its constituent files must be exactly named and located as described here. However, beside the requirements and hook files, you are free to add any other additional files or subdirectories to the hooks directory. For example, if you want to implement multiple complex hooks, you can modularize your code by creating a Python package in the hooks directory, adding it to your hooks/requirements.txt file, and importing it in your hook files.