---
title: Python functions
---

This document describes the Python functions that form the CLI and
non-CLI functions. Non-CLI functions are those used by the CLI
functions. We include function signatures, documentation, some
pseudocode, and diagrams that represent the interface along with
explanations for these design decisions. It primarily serves as a
reference for us to develop from and track what has been finished and
what remains to be done.

{{< include /docs/includes/_design-status.qmd >}}

## Overview

The Python interface has two parts: the functions that represent the
interface via the Terminal (CLI) and the functions that implement the
behaviour of the CLI functions. We will call them "CLI" and "non-CLI"
functions. We have this split for a few reasons:

- To create a clear separation between code that is exposed through the
  CLI and code that could be used on its own as a Python package
  library.
- To apply functional programming practices to the non-CLI functions,
  and restrict the use of side effects and other non-functional
  practices to CLI functions.
- To write unit tests for the non-CLI functions and integration tests
  for the CLI functions.
- To keep the CLI functions small by building them from functional units
  of non-CLI code.

## Python CLI functions

These functions are the direct Python equivalents of the CLI commands
described on the [CLI design page](cli.qmd): `build()` and `view()`.
This page focuses on the Python design and decisions made to avoid too
much overlap with the content of the CLI design page.

Both the `build()` and `view()` functions read in the `datapackage.json`
file into a Python dictionary object that gets checked using
[`check-datapackage`](https://check-datapackage.seedcase-project.org).
This is the main input for the non-CLI functions that build the output
files.

<!-- TODO: Unhide after implementing a class based approach. -->

::: content-hidden
This `Properties` class is used instead of a dictionary for a few
reasons:

- Provides a clear and structured way of representing the properties of
  a Data Package with defined attributes and types.
- Allows for better type checking of the properties to ensure the
  properties are in the expected format.
- Provides a clearer and documented interface for accessing the
  properties.
- Includes better integrated documentation of the properties via
  developer tools and IDEs.
- Allows for the use of dataclass features, such as default values and
  immutability.
- Makes it easier to extend the properties to accommodate version
  updates of the Data Package specification, by creating new versions of
  the `PackageProperties` class.

:::

### {{< var done >}} `build()`

As already described in the CLI design page, this function has the
following parameters:

- `source` for the source argument. The default is the
  `datapackage.json` file found in the current working directory. See
  the [CLI design](cli.qmd) for details about `source`.
- `style` for the style of output to use, which specifies the output
  file type and the number of files created. Either `None` or one of the
  built-in styles. Is ignored if `template_dir` is given.
- `template_dir` for directory that contains the custom styling Jinja
  template files as well as the `sections.toml` file. Defaults to `None`
  as the default style is a built-in style that uses built-in templates.
  If given, `style` is ignored.
- `output_dir` to specify where the root directory is for the output
  files. Defaults to the current working directory.
- `verbose` to output more messages, rather than have no output.

The internal flow of this function is shown in the diagram below.

```{mermaid}
%%| label: fig-python-build-flow
%%| fig-cap: "Diagram of the internal flow of functions and objects in the `build()` CLI function."
flowchart TD
    source:::input --> parse_source{{"parse_source()"}} --> path
    style_cfg[style]:::input --> Config
    template_dir_cfg[template_dir]:::input --> Config
    path --> read_properties{{"read_properties()"}} --> properties
    properties & Config --> build_sections{{"build_sections()"}} --> output["list[BuiltSection]"]
    output --> write_sections{{"write_sections()"}}
    output_dir:::input --> Config
    Config --> write_sections
    write_sections --> files["list[Path]"]
    files --> cli_message{{"cli_message()"}} --> stdout
    verbose:::input --> cli_message

    classDef input fill:#FFF
```

### {{< var done >}} `view()`

As mentioned in the CLI design page, this function has two parameters
that are both the same as those in the `build()` function: `source` and
`style`. The only difference with the `style` parameter is that it can
only accept built-in styles that are one-page (as the terminal is only a
single page itself) and does not allow a custom style. It also doesn't
read from the configuration file.

The internal flow of this function is shown in the diagram below.

```{mermaid}
%%| label: fig-python-view-flow
%%| fig-cap: "Diagram of the internal flow of functions and objects in the `view()` CLI function."
flowchart TD
    source:::input --> parse_source{{"parse_source()"}} --> path
    style_cfg[style]:::input --> Config
    path --> read_properties{{"read_properties()"}} --> properties
    properties & Config --> build_sections{{"build_sections()"}} --> output["list[BuiltSection]"]
    output --> pretty_print{{"pretty_print()"}}

    classDef input fill:#FFF
```
