---
title: "Adding to the package metadata"
order: 2
jupyter: python3
---

In the [previous guide](/docs/guide/package.qmd), we created a Data
Package and saw how to write a minimal set of metadata properties to
`datapackage.json`. Here, we'll take a closer look at the full
`package_properties.py` that's created by `create_properties_script()`.

::: callout-important
Before we get started with this section, it's necessary to delete any
previously created `scripts/package_properties.py` since
`create_properties_script()` does not overwrite this file if it already
exists.
:::

First, change your `main.py` to look like this:

```{python}
#| filename: "main.py"
import seedcase_sprout as sp

def main():
    # Create the properties script in the default location.
    sp.create_properties_script()

if __name__ == "__main__":
    main()
```

Now run the script from terminal:

``` {.bash filename="Terminal"}
uv run main.py
```

If you now view the created `package_properties.py` script, you'll see
that it includes a template containing many of the most commonly used
metadata names together with comments indicating which are required and
which are optional:

<!-- Create the script where quarto can find it for building the docs -->

{{< include _python-minimal-package-setup.qmd >}}

```{python}
#| include: false
sp.create_properties_script(package_path.root())
```

```{python}
#| echo: false
#| output: asis
#| filename: "scripts/package_properties.py"
print(
    '```python',
    package_path.properties_script().read_text(),
    '```',
    sep='\n'
)
```

As you can see, there are a lot of available metadata properties.
However, as we saw in the previous section and as you can see from the
comments in this template script, there aren't that many *required*
metadata. So you can quickly get started creating a Data Package and add
more metadata later as needed.

Sometimes it might feel tedious to fill out metadata properties at all
and you might be tempted to skip creating a Data Package for your data.
But it's important to remember just how vital these metadata actually
are. Without them, your data are simply a collection of files without
any context or meaning. The metadata (properties) are **crucially
important** for understanding and actually using the data in your data
package!

## Creating a more complex `datapackage.json` file

Since metadata is so important, Sprout encourages users to include it by
making it easier to manage it through the use of Python classes as we
saw in the previous section. In the example above, you can see a couple
of additional classes `ContributorProperties` and `SourceProperties`.
Let's create a slightly more complex example using one of these other
classes:

```{python}
#| filename: "scripts/package_properties.py"

import seedcase_sprout as sp

package_properties = sp.PackageProperties(
    name="diabetes-study",
    title="A Study on Diabetes",
    # You can write Markdown below, with the helper `sp.dedent()`.
    description=sp.dedent("""
        # Data from a 2021 study on diabetes prevalence

        This data package contains data from a study conducted in 2021 on the
        *prevalence* of diabetes in various populations. The data includes:

        - demographic information
        - health metrics
        - survey responses about lifestyle
        """),
    contributors=[
        sp.ContributorProperties(
            title="Jamie Jones",
            email="jamie_jones@example.com",
            path="example.com/jamie_jones",
            roles=["creator"],
        ),
        sp.ContributorProperties(
            title="Zdena Ziri",
            email="zdena_ziri@example.com",
            path="example.com/zdena_ziri",
            roles=["creator"],
        )
    ],
    licenses=[
        sp.LicenseProperties(
            name="ODC-BY-1.0",
            path="https://opendatacommons.org/licenses/by",
            title="Open Data Commons Attribution License 1.0",
        )
    ],
    ## Autogenerated:
    id="8f301286-2327-45bf-bbc8-09696d059499",
    version="0.1.0",
    created="2025-11-07T11:12:56+01:00",
)
```

You can see that we included a more involved description of the package
using the helper function `dedent()` and that we used the
`ContributorProperties` class twice as we set the `contributors`
parameter to a list of two contributors who co-created this example Data
Package.

Now you can edit your `main.py` file to again include the
`write_properties()` function:

```{python}
#| eval: false
#| filename: "main.py"
import seedcase_sprout as sp
from scripts.package_properties import package_properties

def main():
    # Create the metadata properties script in default location.
    sp.create_properties_script()
    # Write metadata properties from properties script to `datapackage.json`.
    sp.write_properties(properties=package_properties)

if __name__ == "__main__":
    main()
```

```{python}
#| include: false
# Only to check that it runs.
sp.write_properties(
    properties=package_properties,
    path=package_path.properties()
)
```

Then, use uv to run the script from the Terminal.

``` {.bash filename="Terminal"}
uv run main.py
```

When you inspect the created `datapackage.json` file, you'll see that it
contains all the metadata from the `scripts/package_properties.py`:

```{python}
#| echo: false
#| output: asis
#| filename: datapackage.json
print(
    '```json',
    (package_path.path / 'datapackage.json').read_text(),
    '```',
    sep='\n'
)
```

If you made a mistake and want to update the properties in the current
`datapackage.json`, remember that you never need to edit the JSON file
directly. Instead, you edit the `scripts/package_properties.py` and then
run the `main.py` script to regenerate `datapackage.json`.

## Creating a README of the metadata properties

Having a *human-readable* version of what is contained in the
`datapackage.json` file is useful for others who may be working with or
wanting to learn more about your data package. You can use
`as_readme_text()` to convert the properties into text that can be added
to a README file. Let's create a README file with the properties of the
data package you just created by writing it in the `main.py` file.

```{python}
#| eval: false
#| filename: "main.py"
import seedcase_sprout as sp
from scripts.package_properties import package_properties

def main():
    # Create the properties script in default location.
    sp.create_properties_script()
    # Save the properties to `datapackage.json`.
    sp.write_properties(properties=package_properties)
    # Create text for a README of the data package.
    readme_text = sp.as_readme_text(package_properties)
    # Write the README text to a `README.md` file.
    sp.write_file(readme_text, sp.PackagePath().readme())

if __name__ == "__main__":
    main()
```

Sprout splits the README creation functionality into two steps: One to
make the text and one to write to the file. That way, if you want to add
or manipulate the text, you can do so before writing it to the file.
This is useful if you want to add information to the README that you
don't want included in the `datapackage.json` file. For this guide we
won't cover how or why to do this.

Next, run this command in the Terminal to make the README file. The
`write_file()` will always overwrite the existing README file.

``` {.bash filename="Terminal"}
uv run main.py
```

```{python}
#| include: false
# Only to check that it runs.
readme_text = sp.as_readme_text(package_properties)
sp.write_file(
    string=readme_text,
    path=package_path.readme()
)
```

Now you can see that the `README.md` file has been created in your data
package:

```{python}
#| echo: false
print(file_tree(package_path.root()))
```

Now that you know how to create and manage metadata at the
project-level, it is time to learn how to add data to the project and
manage its metadata.

```{python}
#| include: false
temp_path.cleanup()
```
