cffconvert

Command line program to validate and convert CITATION.cff files.

https://github.com/citation-file-format/cffconvert

Science Score: 44.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
    Found CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
  • Academic email domains
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (14.2%) to scientific vocabulary

Keywords

attribution bibtex cff citation citation-files codemeta endnote ris schemaorg software-sustainability zenodo
Last synced: 6 months ago · JSON representation ·

Repository

Command line program to validate and convert CITATION.cff files.

Basic Info
  • Host: GitHub
  • Owner: citation-file-format
  • License: apache-2.0
  • Language: Python
  • Default Branch: main
  • Homepage:
  • Size: 2.28 MB
Statistics
  • Stars: 127
  • Watchers: 6
  • Forks: 33
  • Open Issues: 45
  • Releases: 18
Topics
attribution bibtex cff citation citation-files codemeta endnote ris schemaorg software-sustainability zenodo
Created about 8 years ago · Last pushed over 1 year ago
Metadata Files
Readme Changelog Contributing License Citation Zenodo

README.dev.md

Documentation for developers

Installing

```shell

get a copy of the cffconvert software

git clone https://github.com/citation-file-format/cffconvert.git

change directory into cffconvert

cd cffconvert

make a virtual environment named venv

python3 -m venv venv

activate the virtual environment

source venv/bin/activate

upgrade pip, wheel, setuptools

pip install --upgrade pip wheel setuptools

install cffconvert in editable mode

pip install --editable . ```

There are various sets of dependencies that you should install depending on the work you're planning to do.

shell pip install --editable .[dev]

shell pip install --editable .[gcloud]

shell pip install --editable .[publishing]

shell pip install --editable .[testing]

You can combine these into one command like so, e.g.:

shell pip install --editable .[dev,testing]

Testing

```shell

(from the project root)

pip install --editable .[testing]

run all tests

pytest tests/

run tests for consistent versioning

pytest tests/testconsistentversioning.py

run pytest on a subset of the files, e.g.

cd tests/lib/cff12_0/ && pytest . ```

Tests pertaining to a specific exporter have been marked accordingly with one of the following markers (see also pytest configuration section in pyproject.toml):

  1. apalike
  2. bibtex
  3. codemeta
  4. endnote
  5. ris
  6. schemaorg
  7. zenodo

Additionally, there are markers for CLI tests and for library tests:

  1. cli
  2. lib

You can instruct pytest to run only the tests for one or some of these marked sets. As an example, if you want to run only the tests related to exporting as Endnote, you should call pytest with the -m flag as follows:

shell pytest -m endnote

Markers can also be combined with or and and and not, e.g.

```shell pytest -m 'endnote and lib' pytest -m 'cli and not zenodo' pytest -m 'schemaorg or codemeta'

etc

```

Linting

Running the linters requires that the development tools have been installed:

shell pip install --editable .[dev]

Sorting Python import lines with 'isort' (https://pycqa.github.io/isort/):

```shell

recursively check import style for the cffconvert module only

isort --check-only src/cffconvert

recursively check import style for the cffconvert module only and show

any proposed changes as a diff

isort --check-only --diff src/cffconvert

recursively fix import style for the cffconvert module only

isort src/cffconvert ```

Linting the code base by running a variety of other tools via 'prospector' (https://github.com/landscapeio/prospector):

```shell

linter

prospector ```

Assessing the package metadata using 'pyroma' (https://github.com/regebro/pyroma):

```shell

from the project root

pyroma . ```

Linting the code base using 'ruff' (https://github.com/astral-sh/ruff):

shell ruff check path/to/code/

The linting tools are also usable via pre-commit:

```shell

Run all tools

pre-commit run --all-files

Run a specific tool, see .pre-commit-config.yaml for their IDs

pre-commit run --all-files ```

Alternatively, the linting tools can be set up to run automatically whenever you issue a git commit command, as follows:

shell pre-commit install

Construction of author keys

There are various source keys in CFF that can be used to convert to a target format. The code uses a pattern of first identifiying what information is present, then summarizing this as a key, then using that key to retrieve a method which is tailored only to that specific combination of source keys. As an example of this mapping, see the setup in https://github.com/citation-file-format/cffconvert/blob/3.0.0a0/cffconvert/behaviorshared/schemaorgauthor_shared.py

Source keys:

  1. authors[i].given-names
  2. authors[i].family-names (including name particle and suffix)
  3. authors[i].alias
  4. authors[i].name
  5. authors[i].affiliation
  6. authors[i].orcid
  7. authors[i].email

The table below lists how the key name is constructed based what information was provided in the CITATION.cff file:

| key | has given name | has family name | has alias | has name | has affiliation | has orcid | has email | |--------------|----------------|-----------------|-----------|----------|-----------------|-----------|-----------| | GFANAOE | True | True | True | True | True | True | True | | GFANA_E | True | True | True | True | True | False | True | | GFAN_OE | True | True | True | True | False | True | True | | GFAN__E | True | True | True | True | False | False | True | | GFA_AOE | True | True | True | False | True | True | True | | GFA_A_E | True | True | True | False | True | False | True | | GFA__OE | True | True | True | False | False | True | True | | GFA___E | True | True | True | False | False | False | True | | GF_NAOE | True | True | False | True | True | True | True | | GF_NA_E | True | True | False | True | True | False | True | | GF_N_OE | True | True | False | True | False | True | True | | GF_N__E | True | True | False | True | False | False | True | | GF__AOE | True | True | False | False | True | True | True | | GF__A_E | True | True | False | False | True | False | True | | GF___OE | True | True | False | False | False | True | True | | GF____E | True | True | False | False | False | False | True | | G_ANAOE | True | False | True | True | True | True | True | | G_ANA_E | True | False | True | True | True | False | True | | G_AN_OE | True | False | True | True | False | True | True | | G_AN__E | True | False | True | True | False | False | True | | G_A_AOE | True | False | True | False | True | True | True | | G_A_A_E | True | False | True | False | True | False | True | | G_A__OE | True | False | True | False | False | True | True | | G_A___E | True | False | True | False | False | False | True | | G__NAOE | True | False | False | True | True | True | True | | G__NA_E | True | False | False | True | True | False | True | | G__N_OE | True | False | False | True | False | True | True | | G__N__E | True | False | False | True | False | False | True | | G___AOE | True | False | False | False | True | True | True | | G___A_E | True | False | False | False | True | False | True | | G____OE | True | False | False | False | False | True | True | | G_____E | True | False | False | False | False | False | True | | _FANAOE | False | True | True | True | True | True | True | | _FANA_E | False | True | True | True | True | False | True | | _FAN_OE | False | True | True | True | False | True | True | | _FAN__E | False | True | True | True | False | False | True | | _FA_AOE | False | True | True | False | True | True | True | | _FA_A_E | False | True | True | False | True | False | True | | _FA__OE | False | True | True | False | False | True | True | | _FA___E | False | True | True | False | False | False | True | | _F_NAOE | False | True | False | True | True | True | True | | _F_NA_E | False | True | False | True | True | False | True | | _F_N_OE | False | True | False | True | False | True | True | | _F_N__E | False | True | False | True | False | False | True | | _F__AOE | False | True | False | False | True | True | True | | _F__A_E | False | True | False | False | True | False | True | | _F___OE | False | True | False | False | False | True | True | | _F____E | False | True | False | False | False | False | True | | __ANAOE | False | False | True | True | True | True | True | | __ANA_E | False | False | True | True | True | False | True | | __AN_OE | False | False | True | True | False | True | True | | __AN__E | False | False | True | True | False | False | True | | __A_AOE | False | False | True | False | True | True | True | | __A_A_E | False | False | True | False | True | False | True | | __A__OE | False | False | True | False | False | True | True | | __A___E | False | False | True | False | False | False | True | | ___NAOE | False | False | False | True | True | True | True | | ___NA_E | False | False | False | True | True | False | True | | ___N_OE | False | False | False | True | False | True | True | | ___N__E | False | False | False | True | False | False | True | | ____AOE | False | False | False | False | True | True | True | | ____A_E | False | False | False | False | True | False | True | | _____OE | False | False | False | False | False | True | True | | ______E | False | False | False | False | False | False | True | | GFANAO_ | True | True | True | True | True | True | False | | GFANA__ | True | True | True | True | True | False | False | | GFAN_O_ | True | True | True | True | False | True | False | | GFAN___ | True | True | True | True | False | False | False | | GFA_AO_ | True | True | True | False | True | True | False | | GFA_A__ | True | True | True | False | True | False | False | | GFA__O_ | True | True | True | False | False | True | False | | GFA____ | True | True | True | False | False | False | False | | GF_NAO_ | True | True | False | True | True | True | False | | GF_NA__ | True | True | False | True | True | False | False | | GF_N_O_ | True | True | False | True | False | True | False | | GF_N___ | True | True | False | True | False | False | False | | GF__AO_ | True | True | False | False | True | True | False | | GF__A__ | True | True | False | False | True | False | False | | GF___O_ | True | True | False | False | False | True | False | | GF_____ | True | True | False | False | False | False | False | | G_ANAO_ | True | False | True | True | True | True | False | | G_ANA__ | True | False | True | True | True | False | False | | G_AN_O_ | True | False | True | True | False | True | False | | G_AN___ | True | False | True | True | False | False | False | | G_A_AO_ | True | False | True | False | True | True | False | | G_A_A__ | True | False | True | False | True | False | False | | G_A__O_ | True | False | True | False | False | True | False | | G_A____ | True | False | True | False | False | False | False | | G__NAO_ | True | False | False | True | True | True | False | | G__NA__ | True | False | False | True | True | False | False | | G__N_O_ | True | False | False | True | False | True | False | | G__N___ | True | False | False | True | False | False | False | | G___AO_ | True | False | False | False | True | True | False | | G___A__ | True | False | False | False | True | False | False | | G____O_ | True | False | False | False | False | True | False | | G______ | True | False | False | False | False | False | False | | _FANAO_ | False | True | True | True | True | True | False | | _FANA__ | False | True | True | True | True | False | False | | _FAN_O_ | False | True | True | True | False | True | False | | _FAN___ | False | True | True | True | False | False | False | | _FA_AO_ | False | True | True | False | True | True | False | | _FA_A__ | False | True | True | False | True | False | False | | _FA__O_ | False | True | True | False | False | True | False | | _FA____ | False | True | True | False | False | False | False | | _F_NAO_ | False | True | False | True | True | True | False | | _F_NA__ | False | True | False | True | True | False | False | | _F_N_O_ | False | True | False | True | False | True | False | | _F_N___ | False | True | False | True | False | False | False | | _F__AO_ | False | True | False | False | True | True | False | | _F__A__ | False | True | False | False | True | False | False | | _F___O_ | False | True | False | False | False | True | False | | _F_____ | False | True | False | False | False | False | False | | __ANAO_ | False | False | True | True | True | True | False | | __ANA__ | False | False | True | True | True | False | False | | __AN_O_ | False | False | True | True | False | True | False | | __AN___ | False | False | True | True | False | False | False | | __A_AO_ | False | False | True | False | True | True | False | | __A_A__ | False | False | True | False | True | False | False | | __A__O_ | False | False | True | False | False | True | False | | __A____ | False | False | True | False | False | False | False | | ___NAO_ | False | False | False | True | True | True | False | | ___NA__ | False | False | False | True | True | False | False | | ___N_O_ | False | False | False | True | False | True | False | | ___N___ | False | False | False | True | False | False | False | | ____AO_ | False | False | False | False | True | True | False | | ____A__ | False | False | False | False | True | False | False | | _____O_ | False | False | False | False | False | True | False | | _______ | False | False | False | False | False | False | False |

Construction of identifier keys

There are various source keys in CFF that can be used to convert to a target format. The code uses a pattern of first identifiying what information is present, then summarizing this as a key, then using that key to retrieve a method which is tailored only to that specific combination of source keys.

Source keys:

  • doi
  • identifiers[i].type==doi

The table below lists how the key name is constructed based what information was provided in the CITATION.cff file:

| key | has doi | has identifiers doi | |------|---------|---------------------| | __ | False | False | | _I | False | True | | D_ | True | False | | DI | True | True |

Construction of URL keys

There are various source keys in CFF that can be used to convert to a target format. The code uses a pattern of first identifiying what information is present, then summarizing this as a key, then using that key to retrieve a method which is tailored only to that specific combination of source keys.

Source keys:

  • identifiers[i].type==url
  • repository
  • repository-artifact
  • repository-code
  • url

The table below lists how the key name is constructed based what information was provided in the CITATION.cff file:

| key | has indentifiers url | has repository | has repository-artifact | has repository-code | has url | |---------|----------------------|----------------|-------------------------|---------------------|---------| | IRACU | True | True | True | True | True | | IRAC_ | True | True | True | True | False | | IRA_U | True | True | True | False | True | | IRA__ | True | True | True | False | False | | IR_CU | True | True | False | True | True | | IR_C_ | True | True | False | True | False | | IR__U | True | True | False | False | True | | IR___ | True | True | False | False | False | | I_ACU | True | False | True | True | True | | I_AC_ | True | False | True | True | False | | I_A_U | True | False | True | False | True | | I_A__ | True | False | True | False | False | | I__CU | True | False | False | True | True | | I__C_ | True | False | False | True | False | | I___U | True | False | False | False | True | | I____ | True | False | False | False | False | | _RACU | False | True | True | True | True | | _RAC_ | False | True | True | True | False | | _RA_U | False | True | True | False | True | | _RA__ | False | True | True | False | False | | _R_CU | False | True | False | True | True | | _R_C_ | False | True | False | True | False | | _R__U | False | True | False | False | True | | _R___ | False | True | False | False | False | | __ACU | False | False | True | True | True | | __AC_ | False | False | True | True | False | | __A_U | False | False | True | False | True | | __A__ | False | False | True | False | False | | ___CU | False | False | False | True | True | | ___C_ | False | False | False | True | False | | ____U | False | False | False | False | True | | _____ | False | False | False | False | False |

For maintainers

Making a release

  1. make sure the release notes are up to date
  2. preparation

    ```shell

    remove old cffconvert from your system if you have it

    python3 -m pip uninstall cffconvert

    this next command should now return empty

    which cffconvert

    install the package to user space, using no caching (can bring to light dependency problems)

    python3 -m pip install --user --no-cache-dir .

    check if cffconvert works, e.g.

    cffconvert --version

    run the tests, make sure they pass

    python3 -m pip pytest tests

    git push everything, merge into main as appropriate

    ```

  3. publishing on test instance of PyPI

    ```shell

    verify that everything has been pushed and merged by testing as follows

    cd $(mktemp -d --tmpdir cffconvert-release.XXXXXX) git clone https://github.com/citation-file-format/cffconvert.git . python3 -m venv venv source venv/bin/activate python3 -m pip install --upgrade pip wheel setuptools python3 -m pip install --no-cache-dir .

    register with PyPI test instance https://test.pypi.org

    remove these directories if you have them

    rm -rf dist rm -rf cffconvert-egg.info

    make a source distribution:

    python setup.py sdist

    make a wheel

    python setup.py bdist_wheel

    install the 'upload to pypi/testpypi tool' aka twine

    pip install .[publishing]

    upload the contents of the source distribution we just made (requires credentials for test.pypi.org)

    twine upload --repository-url https://test.pypi.org/legacy/ dist/* ```

  4. Checking the package

    Open another shell but keep the other one. We'll return to the first shell momentarily.

    Verify that there is a new version of the package on Test PyPI https://test.pypi.org/project/cffconvert/

    ```shell python3 -m pip -v install --user --no-cache-dir \ --index-url https://test.pypi.org/simple/ \ --extra-index-url https://pypi.org/simple cffconvert

    check that the package works as it should when installed from pypitest

    ```

  5. FINAL STEP: upload to PyPI

    Go back to the first shell, then (requires credentials for pypi.org)

    shell twine upload dist/*

  6. Make the release on GitHub

  7. Go to Zenodo, log in to inspect the draft. Then click Publish to finalize it.

Building the docker image

```shell

(requires 3.0.0a0 to be downloadable from PyPI)

docker build --tag cffconvert:3.0.0a0 . docker build --tag cffconvert:latest . ```

See if the Docker image works as expected: ```shell docker run --rm -v $PWD:/app cffconvert --validate docker run --rm -v $PWD:/app cffconvert --version docker run --rm -v $PWD:/app cffconvert

etc

```

Publishing on DockerHub

See https://docs.docker.com/docker-hub/repos/#pushing-a-docker-container-image-to-docker-hub for more information on publishing.

```shell

log out of any dockerhub credentials

docker logout

log back in with username 'citationcff' credentials

docker login

re-tag existing images

docker tag cffconvert:3.0.0a0 citationcff/cffconvert:3.0.0a0 docker tag cffconvert:latest citationcff/cffconvert:latest

publish

docker push citationcff/cffconvert:3.0.0a0 docker push citationcff/cffconvert:latest ```

Owner

  • Name: citation-file-format
  • Login: citation-file-format
  • Kind: organization

Citation (CITATION.cff)

abstract: Command line program to validate and convert CITATION.cff files.
authors:
  - affiliation: Netherlands eScience Center
    alias: jspaaks
    family-names: Spaaks
    given-names: Jurriaan H.
    orcid: https://orcid.org/0000-0002-7064-4069
contributors:
  - affiliation: University of Oslo
    alias: wleoncio
    family-names: Leoncio
    given-names: Waldir
    name-suffix: Netto
  - affiliation: Humboldt-Universität zu Berlin
    alias: sdruskat
    family-names: Druskat
    given-names: Stephan
    orcid: https://orcid.org/0000-0003-4925-7248
  - affiliation: Netherlands eScience Center
    alias: Tommos0
    family-names: Klaver
    given-names: Tom
  - alias: zmoon
    family-names: Moon
    given-names: Zachary
  - alias: nialov
    family-names: Ovaskainen
    given-names: Nikolas
  - alias: musicinmybrain
    family-names: Beasley
    given-names: Ben
  - alias: abelsiqueira
    family-names: Soares Siqueira
    given-names: Abel
    orcid: https://orcid.org/0000-0003-4451-281X
  - alias: monperrus
    family-names: Monperrus
    given-names: Martin
  - alias: ots22
  - affiliation: Netherlands eScience Center
    alias: sverhoeven
    family-names: Verhoeven
    given-names: Stefan
    orcid: https://orcid.org/0000-0002-5821-2060
cff-version: 1.3.0
date-released: 2021-09-22
identifiers:
  - type: doi
    value: 10.5281/zenodo.1162057
    description: Persistent identifier for all versions of cffconvert
    relation: isPartOf
  - type: doi
    value: 10.5281/zenodo.5521767
    description: Persistent identifier for this version of cffconvert
    relation: isIdenticalTo
  - type: url
    value: https://github.com/citation-file-format/cffconvert
    description: URL to the GitHub repository for cffconvert
  - type: url
    value: https://pypi.org/project/cffconvert
    description: cffconvert on PyPI
keywords:
  - bibliography
  - BibTeX
  - cff
  - citation
  - CITATION.cff
  - CodeMeta
  - EndNote
  - RIS
  - Citation File Format
license: Apache-2.0
message: If you use this software, please cite it using these metadata.
repository-artifact: https://pypi.org/project/cffconvert
repository-code: https://github.com/citation-file-format/cffconvert
title: cffconvert
type: software
version: 3.0.0a0
references:
  - authors:
      - affiliation: Netherlands eScience Center
        family-names: Zwaan
        given-names: Janneke
        name-particle: van der
        orcid: https://orcid.org/0000-0002-8329-7000
      - affiliation: Netherlands eScience Center
        family-names: Werkhoven
        given-names: Ben
        name-particle: van
        orcid: https://orcid.org/0000-0002-7508-3272
      - affiliation: Netherlands eScience Center
        family-names: Andela
        given-names: Bouwe
        orcid: https://orcid.org/0000-0001-9005-8940
      - affiliation: Netherlands eScience Center
        family-names: Bos
        given-names: Patrick
        orcid: https://orcid.org/0000-0002-6033-960X
      - affiliation: Netherlands eScience Center
        family-names: Attema
        given-names: Jisk
        orcid: https://orcid.org/0000-0002-0948-1176
      - affiliation: Netherlands eScience Center
        family-names: Bakker
        given-names: Tom
      - affiliation: Netherlands eScience Center
        family-names: Spaaks
        given-names: Jurriaan H.
        orcid: https://orcid.org/0000-0002-7064-4069
      - affiliation: Netherlands eScience Center
        family-names: Kuppevelt
        given-names: Dafne
        name-particle: van
        orcid: https://orcid.org/0000-0002-2662-1994
      - affiliation: Netherlands eScience Center
        family-names: Veen
        given-names: Lourens
        orcid: https://orcid.org/0000-0002-6311-1168
      - affiliation: Netherlands eScience Center
        family-names: Rol
        given-names: Evert
        orcid: https://orcid.org/0000-0001-8357-4453
      - affiliation: Netherlands eScience Center
        family-names: Verhoeven
        given-names: Stefan
        orcid: https://orcid.org/0000-0002-5821-2060
      - affiliation: Netherlands eScience Center
        family-names: Diblen
        given-names: Faruk
        orcid: https://orcid.org/0000-0002-0989-929X
      - affiliation: Netherlands eScience Center
        family-names: Tjong Kim Sang
        given-names: Erik
        orcid: https://orcid.org/0000-0002-8431-081X
    date-released: 2018-07-17
    identifiers:
      - description: Concept DOI for Netherlands eScience Center Python Template
        type: doi
        value: 10.5281/zenodo.1310751
    keywords:
      - cookiecutter
      - template
      - Python
    license: Apache-2.0
    repository-code: https://github.com/NLeSC/python-template
    title: Netherlands eScience Center Python Template
    type: software
    version: 0.4.0
  - authors:
      - family-names: McAdoo
        given-names: Timothy
    title: How to Cite Software in APA Style
    type: blog
    url: >-
      https://blog.apastyle.org/apastyle/2015/01/how-to-cite-software-in-apa-style.html

GitHub Events

Total
  • Issues event: 10
  • Watch event: 25
  • Issue comment event: 20
  • Pull request event: 8
  • Fork event: 6
Last Year
  • Issues event: 10
  • Watch event: 25
  • Issue comment event: 20
  • Pull request event: 8
  • Fork event: 6

Issues and Pull Requests

Last synced: 6 months ago

All Time
  • Total issues: 51
  • Total pull requests: 71
  • Average time to close issues: 3 months
  • Average time to close pull requests: 4 days
  • Total issue authors: 20
  • Total pull request authors: 10
  • Average comments per issue: 1.37
  • Average comments per pull request: 0.24
  • Merged pull requests: 55
  • Bot issues: 0
  • Bot pull requests: 4
Past Year
  • Issues: 9
  • Pull requests: 11
  • Average time to close issues: 10 days
  • Average time to close pull requests: about 1 month
  • Issue authors: 8
  • Pull request authors: 4
  • Average comments per issue: 1.44
  • Average comments per pull request: 0.27
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • jspaaks (26)
  • rettinghaus (2)
  • alexlancaster (1)
  • malikwirin (1)
  • slugb0t (1)
  • remram44 (1)
  • mateuszpawlik (1)
  • rouault (1)
  • jcolomb (1)
  • tvercaut (1)
  • MattF-NSIDC (1)
  • musicinmybrain (1)
  • orichters (1)
  • NiklasMelton (1)
  • irm-codebase (1)
Pull Request Authors
  • jspaaks (46)
  • dependabot[bot] (6)
  • alexlancaster (5)
  • kurtmckee (4)
  • rettinghaus (4)
  • hunterhogan (3)
  • joenio (2)
  • afuetterer (2)
  • firefly-cpp (2)
  • andreaschrader (2)
  • sdruskat (1)
Top Labels
Issue Labels
question (2)
Pull Request Labels
dependencies (6)

Dependencies

.github/workflows/cffconvert.yml actions
  • actions/checkout v2 composite
  • citation-file-format/cffconvert-github-action 2.0.0 composite
.github/workflows/linting.yml actions
  • actions/checkout v2 composite
  • actions/setup-python v2 composite
.github/workflows/testing.yml actions
  • actions/checkout v2 composite
  • actions/setup-python v2 composite
.github/workflows/zenodraft.yml actions
  • actions/checkout v2 composite
  • zenodraft/action 0.10.0 composite
Dockerfile docker
  • python 3.9-alpine build
pyproject.toml pypi
  • click >= 7.0, <9
  • jsonschema >=3.0, <5
  • pykwalify >=1.6
  • requests >=2.20, <3
  • ruamel.yaml >=0.16.0