---
title: "Data Package"
author: "Peter Desmet"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Data Package}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

[Data Package](https://datapackage.org/standard/data-package/) is a simple container format to describe a coherent collection of data (a dataset), including its contributors, licenses, etc.

::: {.callout-note}
In this document we use the terms "package" for Data Package, "resource" for Data Resource, "dialect" for Table Dialect, and "schema" for Table Schema.
:::

## General implementation

frictionless supports reading, manipulating and writing packages. Much of its functionality is focused on manipulating resources (see `vignette("data-resource")`).

### Read

`read_package()` reads a package from `datapackage.json` file (path or URL):

```{r}
library(frictionless)
file <- system.file("extdata", "v2", "datapackage.json", package = "frictionless")
package <- read_package(file)
```

`print.datapackage()` prints a human-readable summary of a package:

```{r}
package
```

### Manipulate

A package is a list, with all the properties that were present in the `datapackage.json` file (e.g. `name`, `id`, etc.). frictionless adds the custom attribute `"directory"` to support reading data (which is removed when writing to disk) and extends the class with `"datapackage"` to support printing and checking:

```{r}
attributes(package)
```

`create_package()` creates a package from scratch or from an existing package. **It always creates a package following the [v2 specification](https://datapackage.org/standard/data-package/).** It adds the required properties, attribute and class if those are missing:

```{r}
# From scratch
create_package()

# From an existing package
create_package(package)
```

`check_package()` checks if a package contains the required properties and class:

```{r, error = TRUE, purl = FALSE}
invalid_package <- example_package()
invalid_package$resources <- NULL
check_package(invalid_package)
```

::: {.callout-warning}
Some base functions (e.g. `unclass()` or `append()`) remove the custom class, creating an invalid package. You can fix this by calling `create_package()` on your package.
:::

`add_properties()` can be used to add (custom) metadata properties to a package:

```{r}
my_package <- create_package()
my_package <- add_properties(
  my_package,
  title = "My package",
  keywords = c("minimal", "frictionlessdata"),
  after = 1 # Add after the first property
)
str(my_package)
```

Most functions have `package` as their first argument and as output. This allows you to **pipe the functions**:

```{r, message = FALSE}
my_package <-
  create_package() |>
  add_properties(
    title = "My package",
    keywords = c("minimal", "frictionlessdata"),
    after = 0
  ) |>
  add_resource(resource_name = "iris", data = iris)
my_package
```

### Write

`write_package()` writes a package and its resources to disk as a `datapackage.json` and CSV files. See the function documentation for details.

## Properties implementation

### $schema

[`$schema`](https://datapackage.org/standard/data-package/#dollar-schema) indicates what `version()` of the Data Package standard is used (v1 if undefined).

- `read_package()` ignores it and does not upgrade a package, since it does not rely on v1 properties deprecated in v2.
- `create_package()` sets `$schema` to the recommended v2 value (`"https://datapackage.org/profiles/2.0/datapackage.json"`) and thus creates a v2 package.
- `upgrade_package()` sets `$schema` to the recommended v2 value, except for certain `profile` values.

### profile

[`profile`](https://specs.frictionlessdata.io/data-package/#profile) (a deprecated v1 property) is ignored by `read_package()` and not set by `create_package()`. `upgrade_package()` removes `profile` (unless `$schema` is already set), but retains its value in `$schema` if it is a URL to a custom profile (see [backwards compatibility](https://datapackage.org/standard/data-package/#dollar-schema)).

### resources

[`resources`](https://datapackage.org/standard/data-package/#resources) is required. It is used by `resource_names()` and many other functions. `check_package()` returns an error if it is missing.

### name

[`name`](https://datapackage.org/standard/data-package/#name) is ignored by `read_package()` and not set by `create_package()`.

### id

[`id`](https://datapackage.org/standard/data-package/#id) is ignored by `read_package()` and not set by `create_package()`. `print.datapackage()` adds an extra sentence when `id` is a URL (like a DOI):

```{r}
package <- example_package()
package$id <- "https://doi.org/10.5281/zenodo.10053702/"
package
```

### licenses

[`licenses`](https://datapackage.org/standard/data-package/#licenses) is ignored by `read_package()` and not set by `create_package()`.

### title

[`title`](https://datapackage.org/standard/data-package/#title) is ignored by `read_package()` and not set by `create_package()`.

### description

[`description`](https://datapackage.org/standard/data-package/#description) is ignored by `read_package()` and not set by `create_package()`.

### homepage

[`homepage`](https://datapackage.org/standard/data-package/#homepage) is ignored by `read_package()` and not set by `create_package()`.

### image

[`image`](https://datapackage.org/standard/data-package/#image) is ignored by `read_package()` and not set by `create_package()`.

### version

[`version`](https://datapackage.org/standard/data-package/#version) is ignored by `read_package()` and not set by `create_package()`.

### created

[`created`](https://datapackage.org/standard/data-package/#created) is ignored by `read_package()` and not set by `create_package()`.

### keywords

[`keywords`](https://datapackage.org/standard/data-package/#keywords) is ignored by `read_package()` and not set by `create_package()`.

### contributors

[`contributors`](https://datapackage.org/standard/data-package/#contributors) is ignored by `read_package()` and not set by `create_package()`. `upgrade_package()` converts `"role": "value"` to `"roles": ["value"]` for all contributors (see [changelog](https://datapackage.org/overview/changelog/#packagecontributors-updated)).

### sources

[`sources`](https://datapackage.org/standard/data-package/#sources) is ignored by `read_package()` and not set by `create_package()`.
