# -*- coding: utf-8 -*-
from setuptools import setup

package_dir = \
{'': 'src'}

packages = \
['bas_metadata_library',
 'bas_metadata_library.schemas',
 'bas_metadata_library.schemas.dist',
 'bas_metadata_library.schemas.src',
 'bas_metadata_library.standards',
 'bas_metadata_library.standards.iec_pas_61174_0_v1',
 'bas_metadata_library.standards.iec_pas_61174_1_v1',
 'bas_metadata_library.standards.iec_pas_61174_common',
 'bas_metadata_library.standards.iso_19115_1',
 'bas_metadata_library.standards.iso_19115_2',
 'bas_metadata_library.standards.iso_19115_common']

package_data = \
{'': ['*'],
 'bas_metadata_library.schemas': ['xsd/gco/*',
                                  'xsd/gmd/*',
                                  'xsd/gmi/*',
                                  'xsd/gml/*',
                                  'xsd/gmx/*',
                                  'xsd/gsr/*',
                                  'xsd/gss/*',
                                  'xsd/gts/*',
                                  'xsd/rtz/*',
                                  'xsd/xlink/*',
                                  'xsd/xml/*']}

install_requires = \
['backports-datetime-fromisoformat>=1.0.0,<2.0.0',
 'importlib-resources>=5.4.0,<6.0.0',
 'jsonschema==3.2.0',
 'lxml>=4.7.1,<5.0.0',
 'rfc3987>=1.3.8,<2.0.0',
 'strict-rfc3339>=0.7,<0.8']

setup_kwargs = {
    'name': 'bas-metadata-library',
    'version': '0.8.0',
    'description': 'Python library for generating metadata records',
    'long_description': '# BAS Metadata Library\n\nPython library for generating metadata and data records.\n\n## Overview\n\n### Purpose\n\nThis library is designed to assist in generating metadata and data records, primarily for the discovery of datasets,\nservices, features and related resources. This project is intended to be used as a dependency, to avoid the need to\nduplicate the implementation of complex and verbose metadata and data standards.\n\nAt a high level, this library allows a configuration object, representing the fields/structure of a standard, to be\nencoded into its formal representation set out by that standard (typically using XML). It also allows such a formal\nrepresentation to be decoded back into a configuration object, which can be more easily used or manipulated.\n\n### Supported standards\n\n| Standard                                                        | Implementation                                                  | Library Namespace                                   | Introduced In                                                                                      |\n| --------------------------------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------- | -------------------------------------------------------------------------------------------------- |\n| [ISO 19115:2003](https://www.iso.org/standard/26020.html)       | [ISO 19139:2007](https://www.iso.org/standard/32557.html)       | `bas_metadata_library.standards.iso_19115_1_v1`     | [#46](https://gitlab.data.bas.ac.uk/uk-pdc/metadata-infrastructure/metadata-library/issues/46)   |\n| [ISO 19115-2:2009](https://www.iso.org/standard/39229.html)     | [ISO 19139-2:2012](https://www.iso.org/standard/57104.html)     | `bas_metadata_library.standards.iso_19115_2_v1`     | [#50](https://gitlab.data.bas.ac.uk/uk-pdc/metadata-infrastructure/metadata-library/issues/50)   |\n| [IEC 61174:2015](https://webstore.iec.ch/publication/23128)     | [IEC 61174:2015](https://webstore.iec.ch/publication/23128)     | `bas_metadata_library.standards.iec_pas_61174_0_v1` | [#139](https://gitlab.data.bas.ac.uk/uk-pdc/metadata-infrastructure/metadata-library/issues/139) |\n| [IEC PAS 61174:2021](https://webstore.iec.ch/publication/67774) | [IEC PAS 61174:2021](https://webstore.iec.ch/publication/67774) | `bas_metadata_library.standards.iec_pas_61174_1_v1` | [#139](https://gitlab.data.bas.ac.uk/uk-pdc/metadata-infrastructure/metadata-library/issues/144) |\n\n**Note:** In this library, the *ISO 19115:2003* standard is referred to as *ISO-19115-1* (`iso_19115_1`) for\nconsistency with *ISO 19115-2:2009* (referred to as *ISO-19115-2*, `iso_19115_2`). In the future, the\n[ISO 19115-1:2014](https://www.iso.org/standard/53798.html) standard will be referred to as *ISO-19115-3*.\n\n### Supported profiles\n\n| Standard | Profile  | Implementation  | Library Namespace | Introduced In |\n| -------- | -------- | --------------- | ----------------- | ------------- |\n| -        | -        | -               | -                 | -             |\n\n**Note:** Support for profiles has been removed to allow underlying standards to be implemented more easily, and to\nwait until a stable profile for UK PDC Discovery metadata has been developed and approved.\n\n### Supported configuration versions\n\n| Standard           | Profile | Configuration Version                                                                                                     | Status  | Notes            |\n| ------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------- |---------|------------------|\n| ISO 19115:2003     | -       | [`v1`](https://metadata-standards.data.bas.ac.uk/bas-metadata-generator-configuration-schemas/v2/iso-19115-1-v1.json)     | Retired | Replaced by `v2` |\n| ISO 19115:2003     | -       | [`v2`](https://metadata-standards.data.bas.ac.uk/bas-metadata-generator-configuration-schemas/v2/iso-19115-1-v2.json)     | Live    | Stable version   |\n| ISO 19115-2:2009   | -       | [`v1`](https://metadata-standards.data.bas.ac.uk/bas-metadata-generator-configuration-schemas/v2/iso-19115-2-v1.json)     | Retired | Replaced by `v2` |\n| ISO 19115-2:2009   | -       | [`v2`](https://metadata-standards.data.bas.ac.uk/bas-metadata-generator-configuration-schemas/v2/iso-19115-2-v2.json)     | Live    | Stable version   |\n| IEC 61174:2015     | -       | [`v1`](https://metadata-standards.data.bas.ac.uk/bas-metadata-generator-configuration-schemas/v2/iec-pas-61174-0-v1.json) | Alpha   | Experimental     |\n| IEC PAS 61174:2021 | -       | [`v1`](https://metadata-standards.data.bas.ac.uk/bas-metadata-generator-configuration-schemas/v2/iec-pas-61174-1-v1.json) | Alpha   | Experimental     |\n\n### Supported standards coverage\n\nThis library is built around the needs of the British Antarctic Survey and the NERC (UK) Polar Data Centre. This means\nonly standards, and elements of these standards, used by BAS or the UK PDC are supported. However, additions that would\nenable this library to be useful to other organisations and use-case are welcome as contributions providing they do not\nadd significant complexity or maintenance.\n\n| Standard           | Coverage | Coverage Summary                                                                                     |\n| ------------------ | -------- |------------------------------------------------------------------------------------------------------|\n| ISO 19115:2003     | Good     | All mandatory elements are supported with a good number of commonly used additional elements         |\n| ISO 19115-2:2009   | Minimal  | No elements from this extension are supported, with the exception of the root element                |\n| IEC 61174:2015     | Minimal  | All mandatory elements are supported, plus a limited number of optional route information attributes |\n| IEC PAS 61174:2021 | Minimal  | All mandatory elements are supported, plus a limited number of optional route information attributes |\n\n**Note:** ISO 19115 extensions (i.e. `gmd:metadataExtensionInfo` elements) are not supported.\n\n#### Coverage for IEC 61174\n\nAs required by the IEC 61174 standard, this library supports the following properties within this standard:\n\n| Element                                        | Reference | Obligation |\n| ---------------------------------------------- | --------- | ---------- |\n| `route`                                        | *4.5.2*   | Mandatory  |\n| `route.routeInfo.routeAuthor`                  | *4.5.3*   | Optional   |\n| `route.routeInfo.routeName`                    | *4.5.3*   | Mandatory  |\n| `route.routeInfo.routeStatus`                  | *4.5.3*   | Optional   |\n| `route.waypoints`                              | *4.5.4*   | Mandatory  |\n| `route.waypoints.*.waypoint.id`                | *4.5.6*   | Mandatory  |\n| `route.waypoints.*.waypoint.revision`          | *4.5.6*   | Mandatory  |\n| `route.waypoints.*.waypoint.position.lat`      | *4.5.6*   | Mandatory  |\n| `route.waypoints.*.waypoint.position.lon`      | *4.5.6*   | Mandatory  |\n| `route.waypoints.*.waypoint.position.geometry` | *4.5.6*   | Optional   |\n\nThis list is exhaustive. No extensions are supported.\n\nReferences in the above table relate to the IEC PAS 61174:2021 standards document:\nhttps://webstore.iec.ch/publication/67774.\n\nFull citation:\n\n> IEC 61174:2015, Maritime navigation and radiocommunication equipment and systems – Electronic chart display and\n> information system (ECDIS) – Operational and performance requirements, methods of testing and required test results\n\n## Installation\n\nThis package can be installed using Pip from [PyPi](https://pypi.org/project/bas-metadata-library):\n\n```\n$ pip install bas-metadata-library\n```\n\nThis package depends on native libraries for XML encoding and decoding:\n\n* `libxml2`\n* `libxslt`\n\nThis package depends on native binaries for XML validation:\n\n* `xmllint`\n\nMost Operating Systems include these libraries and packages by default. However, others, particularly minimal OSes\nrequire these packages to be installed separately. Required packages for supported Operating Systems are:\n\n| Operating System      | Required Packages              | Notes                |\n|-----------------------|--------------------------------|----------------------|\n| Alpine Linux (Docker) | `libxslt-dev`, `libxml2-utils` | -                    |\n| CentOS 7              | -                              | Installed by default |\n| CentOS 7 (Docker)     | -                              | Installed by default |\n\n## Usage\n\n### Encode an ISO 19115 metadata record\n\nTo generate an ISO 19115 metadata record from a Python record configuration and return it as an XML document:\n\n```python\nfrom datetime import date\n\nfrom bas_metadata_library.standards.iso_19115_2 import MetadataRecordConfigV2, MetadataRecord\n\nminimal_record_config = {\n    "hierarchy_level": "dataset",\n    "metadata": {\n        "language": "eng",\n        "character_set": "utf-8",\n        "contacts": [{"organisation": {"name": "UK Polar Data Centre"}, "role": ["pointOfContact"]}],\n        "date_stamp": date(2018, 10, 18),\n    },\n    "identification": {\n        "title": {"value": "Test Record"},\n        "dates": {"creation": {"date": date(2018, 1, 1), "date_precision": "year"}},\n        "abstract": "Test Record for ISO 19115 metadata standard (no profile) with required properties only.",\n        "character_set": "utf-8",\n        "language": "eng",\n        "topics": ["environment", "climatologyMeteorologyAtmosphere"],\n        "extent": {\n            "geographic": {\n                "bounding_box": {\n                    "west_longitude": -45.61521,\n                    "east_longitude": -27.04976,\n                    "south_latitude": -68.1511,\n                    "north_latitude": -54.30761,\n                }\n            }\n        },\n    },\n}\nconfiguration = MetadataRecordConfigV2(**minimal_record_config)\nrecord = MetadataRecord(configuration=configuration)\ndocument = record.generate_xml_document()\n\n# output document\nprint(document.decode())\n```\n\nSee the [HTML Entities](#html-entities) section for guidance on using accents and symbols in descriptions.\n\nYou will need to use a `date_precision` property for partial dates. See the [Date Precision](#date-precision) section \nfor more information.\n\n### Encode an IEC 61174 route information record\n\nTo encode to a RTZ file:\n\n```python\nfrom bas_metadata_library.standards.iec_pas_61174_0_v1 import MetadataRecordConfigV1, MetadataRecord\n\nminimal_record_config = {"route_name": "minimal-test-route",\n    "waypoints": [\n        {"id": 1001, "revision": 0, "position": {"lat": 5, "lon": 50}},\n        {"id": 1002, "revision": 0, "position": {"lat": 5, "lon": 50}},\n        {"id": 1003, "revision": 0, "position": {"lat": 5, "lon": 50}},\n    ],\n}\nconfiguration = MetadataRecordConfigV1(**minimal_record_config)\nrecord = MetadataRecord(configuration=configuration)\ndocument = record.generate_xml_document()\n\n# output document\nprint(document.decode())\n```\n\nTo encode to a RTZP package:\n\n```python\nfrom pathlib import Path\n\nfrom bas_metadata_library.standards.iec_pas_61174_0_v1 import MetadataRecordConfigV1, MetadataRecord\n\noutput_path = str(\'/path/to/file.rtzp\')\n\nminimal_record_config = {"route_name": "minimal-test-route",\n    "waypoints": [\n        {"id": 1001, "revision": 0, "position": {"lat": 5, "lon": 50}},\n        {"id": 1002, "revision": 0, "position": {"lat": 5, "lon": 50}},\n        {"id": 1003, "revision": 0, "position": {"lat": 5, "lon": 50}},\n    ],\n}\nconfiguration = MetadataRecordConfigV1(**minimal_record_config)\nrecord = MetadataRecord(configuration=configuration)\nrecord.generate_rtzp_archive(file=Path(output_path))\n```\n\n### Decode an ISO 19115 metadata record\n\n```python\nfrom bas_metadata_library.standards.iso_19115_2 import MetadataRecord\n\nwith open(f"minimal-record.xml") as record_file:\n    record_data = record_file.read()\n\nrecord = MetadataRecord(record=record_data)\nconfiguration = record.make_config()\nminimal_record_config = configuration.config\n\n# output configuration\nprint(minimal_record_config)\n```\n\n### Decode an IEC 61174 route information record\n\nTo decode from a RTZ file:\n\n```python\nfrom bas_metadata_library.standards.iec_pas_61174_0_v1 import MetadataRecord\n\nwith open(f"minimal-record.rtz") as record_file:\n    record_data = record_file.read()\n\nrecord = MetadataRecord(record=record_data)\nconfiguration = record.make_config()\nminimal_record_config = configuration.config\n\n# output configuration\nprint(minimal_record_config)\n```\n\nTo decode from a RTZP package:\n\n```python\nfrom pathlib import Path\n\nfrom bas_metadata_library.standards.iec_pas_61174_0_v1 import MetadataRecord\n\ninput_path = str(\'/path/to/file.rtzp\')\n\nrecord = MetadataRecord()\nrecord.load_from_rtzp_archive(file=Path(input_path))\nconfiguration = record.make_config()\nminimal_record_config = configuration.config\n\n# output configuration\nprint(minimal_record_config)\n```\n\n### Loading a record configuration from JSON\n\n**The example below is for the ISO 19115 standard but this applies to all standards.**\n\nThe `load()` and `loads()` methods on the configuration class can be used to load a record configuration encoded as a\nJSON file or JSON string respectively:\n\n```python\nfrom pathlib import Path\n\nfrom bas_metadata_library.standards.iso_19115_2 import MetadataRecordConfigV2\n\ninput_path = str(\'/path/to/file.json\')\n\nconfiguration = MetadataRecordConfigV2()\nconfiguration.load(file=Path(input_path))\n```\n\n### Dumping a record configuration to JSON\n\n**The example below is for the ISO 19115 standard but this applies to all standards.**\n\nThe `dump()` and `dumps()` methods on the configuration class can be used to dump a record configuration to a JSON\nencoded file or string respectively:\n\n```python\nfrom datetime import date\nfrom pathlib import Path\n\nfrom bas_metadata_library.standards.iso_19115_2 import MetadataRecordConfigV2\n\noutput_path = str(\'/path/to/file.json\')\n\nminimal_record_config = {\n    "hierarchy_level": "dataset",\n    "metadata": {\n        "language": "eng",\n        "character_set": "utf-8",\n        "contacts": [{"organisation": {"name": "UK Polar Data Centre"}, "role": ["pointOfContact"]}],\n        "date_stamp": date(2018, 10, 18),\n    },\n    "identification": {\n        "title": {"value": "Test Record"},\n        "dates": {"creation": {"date": date(2018, 1, 1), "date_precision": "year"}},\n        "abstract": "Test Record for ISO 19115 metadata standard (no profile) with required properties only.",\n        "character_set": "utf-8",\n        "language": "eng",\n        "topics": ["environment", "climatologyMeteorologyAtmosphere"],\n        "extent": {\n            "geographic": {\n                "bounding_box": {\n                    "west_longitude": -45.61521,\n                    "east_longitude": -27.04976,\n                    "south_latitude": -68.1511,\n                    "north_latitude": -54.30761,\n                }\n            }\n        },\n    },\n}\nconfiguration = MetadataRecordConfigV2(**minimal_record_config)\nconfiguration.dump(file=Path(output_path))\n```\n\n### Validating a record\n\n**The example below is for the ISO 19115 standard but this applies to all standards.**\n\nThe formal encoding of a record can be validated against one or more XML schemas relevant to each metadata or data\nstandard. Records are not validated automatically, and so must be validated explicitly:\n\n```python\nfrom datetime import date\n\nfrom bas_metadata_library import RecordValidationError\nfrom bas_metadata_library.standards.iso_19115_2 import MetadataRecordConfigV2, MetadataRecord\n\nminimal_record_config = {\n    "hierarchy_level": "dataset",\n    "metadata": {\n        "language": "eng",\n        "character_set": "utf-8",\n        "contacts": [{"organisation": {"name": "UK Polar Data Centre"}, "role": ["pointOfContact"]}],\n        "date_stamp": date(2018, 10, 18),\n    },\n    "identification": {\n        "title": {"value": "Test Record"},\n        "dates": {"creation": {"date": date(2018, 1, 1), "date_precision": "year"}},\n        "abstract": "Test Record for ISO 19115 metadata standard (no profile) with required properties only.",\n        "character_set": "utf-8",\n        "language": "eng",\n        "topics": ["environment", "climatologyMeteorologyAtmosphere"],\n        "extent": {\n            "geographic": {\n                "bounding_box": {\n                    "west_longitude": -45.61521,\n                    "east_longitude": -27.04976,\n                    "south_latitude": -68.1511,\n                    "north_latitude": -54.30761,\n                }\n            }\n        },\n    },\n}\nconfiguration = MetadataRecordConfigV2(**minimal_record_config)\nrecord = MetadataRecord(configuration=configuration)\n\ntry:\n    record.validate()\nexcept RecordValidationError as e:\n    print(\'Record invalid\')\n    print(e)\n```\n\nWhere the contents of the record is invalid, a `RecordValidationError` exception will be raised. Printing this\nexception will return validation errors.\n\nThese errors should not happen, and if they do are considered internal bugs. Please report any in the\n[Project Issue Tracker](#issue-tracking) if you are internal to BAS, or as [Feedback](#feedback) if you are not.\n\nSee the [Record Schemas](#record-schemas) section for more information on how validation works.\n\n### Validating a record configuration\n\n**The example below is for the ISO 19115 standard but this applies to all standards.**\n\nRecord configurations will be validated automatically using a JSON Schema relevant to each metadata or data standard.\n\nTo explicitly validate a record configuration:\n\n```python\nfrom datetime import date\n\nfrom jsonschema import ValidationError\nfrom bas_metadata_library.standards.iso_19115_2 import MetadataRecordConfigV2\n\nminimal_record_config = {\n    "hierarchy_level": "dataset",\n    "metadata": {\n        "language": "eng",\n        "character_set": "utf-8",\n        "contacts": [{"organisation": {"name": "UK Polar Data Centre"}, "role": ["pointOfContact"]}],\n        "date_stamp": date(2018, 10, 18),\n    },\n    "identification": {\n        "title": {"value": "Test Record"},\n        "dates": {"creation": {"date": date(2018, 1, 1), "date_precision": "year"}},\n        "abstract": "Test Record for ISO 19115 metadata standard (no profile) with required properties only.",\n        "character_set": "utf-8",\n        "language": "eng",\n        "topics": ["environment", "climatologyMeteorologyAtmosphere"],\n        "extent": {\n            "geographic": {\n                "bounding_box": {\n                    "west_longitude": -45.61521,\n                    "east_longitude": -27.04976,\n                    "south_latitude": -68.1511,\n                    "north_latitude": -54.30761,\n                }\n            }\n        },\n    },\n}\nconfiguration = MetadataRecordConfigV2(**minimal_record_config)\n\ntry:\n    configuration.validate()\nexcept ValidationError as e:\n    print(\'Record configuration invalid\')\n    print(e)\n```\n\nWhere the contents of the record is invalid, a\n[`ValidationError`](https://python-jsonschema.readthedocs.io/en/stable/errors/#jsonschema.exceptions.ValidationError)\nexception will be raised by the underlying JSON Schema library. Printing this exception will return validation errors.\n\nSee the [Record Configuration Schemas](#configuration-schemas) section for more information.\n\n### HTML entities\n\nDo not include HTML entities in input to this library, as they will be double escaped by [Lxml](https://lxml.de), the\nunderlying XML processing library used by this project. Instead, literal characters should be used (e.g. `>`), which\nwill be escaped as needed automatically. This applies to any unicode character, such as accents (e.g. `å`) and\nsymbols (e.g. `µ`).\n\nE.g. If `&gt;`, the HTML entity for `>` (greater than), were used as input, it would be escaped again to `&amp;gt;`\nwhich will not be valid output.\n\n### Date Precision\n\nWhen using Python for record configurations, date or date times must be structured as dictionaries with a `date` \nvalue (which can be a Python date or date time object), and optional `date_precision` property for indicating elements \nin the date or date time object should be ignored when encoding records. This property can be set to either:\n\n* `year` (month and day are unknown)\n* `month` (day is unknown)\n\nWhen decoding a record, partial dates or date times will be detected and a `date_precision` property added \nautomatically. Unknown elements of a date or date time should, or will, use \'1\' as a conventional value, which can \neffectively be ignored. This is necessary as Python does not allow unknown date elements to be omitted.\n\nWhen using JSON for record configurations, date or date times must be written as strings. Partial dates or date \ntimes can be expressed naturally (e.g. `2012-04`), without the need for a `date_precision` property. This library will \nautomatically convert strings to or from dictionaries, with a `date_precision` property if needed, when loading from, \nor saving to, JSON.\n\nSummary table:\n\n| Date Precision | Python Encoding                                                                | JSON Encoding           | XML Encoding            |\n|----------------|--------------------------------------------------------------------------------|-------------------------|-------------------------|\n| Year           | `{\'date\': date(year=2012, month=1, day=1), \'date_precision\': \'year\'}`          | `"2012"`                | `"2012"`                |\n| Month          | `{\'date\': date(year=2012, month=4, day=1), \'date_precision\': \'month\'}`         | `"2012-04"`             | `"2012-04"`             |\n| Day            | `{\'date\': date(year=2012, month=4, day=14)}`                                   | `"2012-04-14"`          | `"2012-04-14"`          |\n| Hour           | `{\'date\': datetime(year=2012, month=4, day=14, hour=6)}`                       | `"2012-04-14T06"`       | `"2012-04-14T06"`       |\n| Minute         | `{\'date\': datetime(year=2012, month=4, day=14, hour=6, minute=30)}`            | `"2012-04-14T06:30"`    | `"2012-04-14T06:30"`    |\n| Second         | `{\'date\': datetime(year=2012, month=4, day=14, hour=6, minute=30, second=42)}` | `"2012-04-14T06:30:42"` | `"2012-04-14T06:30:42"` |\n\n**Note:** For date times, the UTC timezone is assumed unless set.\n\n### ISO 19115 - linkages between transfer options and formats\n\nIn ISO 19115, there is no formal mechanism to associate file distribution formats and transfer options. As this library\nseeks to be fully reversible between a configuration object and formal XML encoding, associations between these elements\nwould be lost when records are encoded as XML. These associations are used to produce download tables such as [1].\n\nIn [Record Configurations](#configuration-classes), these associations are encoded using a \'distribution option\'\nconcept. In formal XML records, these associations are encoded using `xsd:ID` attributes in `gmd:MD_Format` and\n`gmd:DigitalTransferOptions` elements, with values that allow these associations to be reconstructed when decoding XML.\n\n**Note:** Do not modify automatically assigned IDs, as this will break this functionality.\n\nSee the [Automatic transfer option / format IDs](#iso-19115-automatic-transfer-option-format-ids) section for more\ninformation.\n\n[1]\n\n| Format     | Size   | Download Link                |\n| ---------- | ------ | ---------------------------- |\n| CSV        | 68 kB  | [Link](https://example.com/) |\n| GeoPackage | 1.2 MB | [Link](https://example.com/) |\n\n## Implementation\n\nThis library is implemented in Python and consists of a set of classes used to generate XML metadata and data records\nfrom a configuration object, or to generate a configuration object from an XML record.\n\nEach [supported Standard](#supported-standards) is implemented as a module under `bas_metadata_library.standards`. Each\n[Supported Profile](#supported-profiles) is implemented as modules under their respective standard.\n\n### Base classes\n\nFor each standard and profile, instances of these base classes are defined:\n\n* `Namespaces`\n* `MetadataRecord`\n* `MetadataRecordConfig`\n\nThe `namespaces` class is a set of mappings between XML namespaces, their shorthand aliases and their definitions XSDs.\n\nThe `MetadataRecord` class represents a metadata record and defines the Root [Element](#record-element-classes). This \nclass provides methods to generate an XML document for example.\n\nThe `MetadataRecordConfig` class represents the [Configuration](#configuration-classes) used to define values within a\n`MetadataRecord`, either for new records, or derived from existing records. This class provides methods to validate the\nconfiguration used in a record for example.\n\n### Record element classes\n\nEach supported element, in each [supported standard](#supported-standards), inherit and use the `MetadataRecordElement`\nclass to:\n\n* encode configuration values into an XML fragment of at least one element\n* decode an XML fragment into one or more configuration values\n\nSpecifically, at least two methods are implemented:\n\n* `make_element()` which builds an XML element using values from a configuration object\n* `make_config()` which uses typically XPath expressions to build a configuration object from XML\n\nThese methods may be simple (if encoding or decoding a simple free text value for example), or quite complex, using\nsub-elements (which themselves may contain sub-elements as needed).\n\n### Record schemas\n\nAllowed elements, attributes and values for each [supported Standard](#supported-standards) and\n[Supported Profile](#supported-profiles) are defined using one or more [XML Schemas](https://www.w3.org/XML/Schema).\nThese schemas define any required entities, and any entities with enumerated values. Schemas are usually published by\nstandards organisations to facilitate record validation.\n\nFor performance reasons, and to ensure required schemas are not unavailable (due to remote locations being reorganised,\nor during server maintenance etc.), these schema files are stored within this package. Schemas are stored as XML Schema\nDefinition (XSD) files in the `bas_metadata_library.schemas.xsd` module, and loaded as resource files for use in record\nvalidation.\n\n**Note:** To support local validation, imported or included schema locations in local versions of XML schemas, have\nbeen modified. These changes do not materially change the contents of any schema.\n\n**Note:** In some cases, material changes *have* been made to local versions of schemas, in order to workaround\nspecific issues. These changes will be documented and explained, to allow users to understand the effect they will\nhave, and why they have been made.\n\n#### Altered Metadata Schema - Geographic Metadata (GMD)\n\nThe ISO *Geographic Metadata (GMD)* schema (used directly for the ISO 19115-0 standard, and indirectly in the ISO\n19115-2 standard) has been modified to:\n\n1. include the ISO *Geographic Metadata XML (GMX)* schema:\n    * in order to allow Anchor elements to substitute primitive/simple values (such as character strings and integers),\n    * as defined in the ISO 19139:2007 and ISO 19139:2012 standards\n\n### Configuration classes\n\nThe configuration of each metadata record is held in a Python dictionary, within a `MetadataRecordConfig` class. This\nclass includes methods to validate its configuration against a relevant [Configuration Schema](#configuration-schemas).\n\nConfiguration classes are defined at the root of each standard or profile, alongside its root\n[Metadata Element](#record-element-classes) and XML namespaces.\n\nA configuration class will exist for each supported configuration schema with methods to convert from one version to\nanother.\n\n### Configuration schemas\n\nAllowed properties and values for record configurations for each [supported Standard](#supported-standards) and\n[Supported Profile](#supported-profiles) are defined using a [JSON Schema](https://json-schema.org). These schemas\ndefine any required properties, and any properties with enumerated values.\n\nConfiguration schemas are stored as JSON files in the `bas_metadata_library.schemas` module, and loaded as\nresource files from within this package to validate record configurations. Schemas are also made available externally\nthrough the BAS Metadata Standards website,\n[metadata-standards.data.bas.ac.uk](https://metadata-standards.data.bas.ac.uk), to allow:\n\n1. other applications to ensure their output will be compatible with this library - where they can\'t, or don\'t want to,\n   use this library directly\n2. schema inheritance/extension - for standards that inherit from other standards (such as extensions or profiles)\n\nConfiguration schemas are versioned (e.g. `v1`, `v2`) to allow for backwards incompatible changes to be made.\nUpgrade/Downgrade methods will be provided for a limited time to assist migrating record configurations between schema\nversions.\n\n#### Source and distribution schemas\n\nStandards and profiles usually inherit from other standards and profiles. In order to prevent this creating huge\nduplication within configuration schemas, inheritance is used to incorporate a base schema and extend it as needed. For\nexample, the ISO 19115-2 standard extends, and therefore incorporates the configuration schema for, ISO 19115-1.\n\nJSON Schema references and identifier properties are used to implement this, using URIs within the BAS Metadata\nStandards website. Unfortunately, this creates a problem when developing these schemas, as if Schema B relies on Schema\nA, using its published identifier as a reference, the published instance of the schema will be used (i.e. the remote\nschema will be downloaded when Schema B is validated). If Schema A is being developed, and is not ready to be\nrepublished, there is a difference between the local and remote schemas used, creating unreliable tests for example.\n\nTo avoid this problem, a set of *source* schemas are used which use references to avoid duplication, from which a set\nof *distribution* schemas are generated. These distribution schemas inline any references contained in their source\ncounterpart. These distribution schemas are therefore self-contained and can be updated locally without any\ndependencies on remote sources. Distribution schemas are used by [Configuration Classes](#configuration-classes) and\npublished to the BAS Metadata Standards website, they are located in the `bas_metadata_library.schemas.dist` module.\n\nWhen editing configuration schemas, you should edit the source schemas, located in the\n`bas_metadata_library.schemas.src` module, then [generate distribution schemas](#generating-configuration-schemas).\n\nJSON Schema\'s can be developed using [jsonschemavalidator.net](https://www.jsonschemavalidator.net).\n\n### Adding a new standard\n\nTo add a new standard:\n\n1. create a new module under `bas_metadata_library.standards`, e.g. `bas_metadata_library.standards.foo_v1/__init__.py`\n2. in this module, overload the `Namespaces`, `MetadataRecordConfig` and `MetadataRecord` classes as needed\n3. create a suitable metadata configuration JSON schema in `bas_metadata_library.schemas.src`\n   e.g. `bas_metadata_library.schemas.src.foo_v1.json`\n4. update the `generate_schemas` method in `app.py` to generate distribution schemas\n5. add a script line to the `publish-schemas-stage` and `publish-schemas-prod` jobs in `.gitlab-ci.yml`, to publish\n   the distribution schema within the BAS Metadata Standards website\n6. define a series of test configurations (e.g. minimal, typical and complete) for generating test records in\n   `tests/resources/configs/` e.g. `tests/resources/configs/foo_v1_standard.py`\n7. add a route `app.py` for generating test records for the new standard\n8. update the `capture_test_records` method in `app.py` to generate and save test records\n9. add relevant [tests](#testing) with methods to test each metadata element class and test records\n\n### Adding a new element to an existing standard\n\n**Note:** These instructions are specific to the ISO 19115 metadata standards family.\n\n1. [amend configuration schema](#configuration-schemas):\n   * new or changed properties should be added to the configuration for the relevant standard (e.g. ISO 19115-1)\n   * typically, this involves adding new elements to the `definitions` property and referencing these in the relevant\n     parent element (e.g. to the `identification` property)\n2. [generate distribution schemas](#generating-configuration-schemas)\n3. amend test configs:\n   * new or changed properties should be made to the relevant test record configurations in `tests/resources/configs/`\n   * there are different levels of configuration, from minimal to complete, which should, where possible, build on\n     each other (e.g. the complete record should include all the properties and values of the minimal record)\n   * the `minimum` configuration should not be changed, as all mandatory elements are already implemented\n   * the `base_simple` configuration should contain elements used most of the time, that use free-text values\n   * the `base_complex` configuration should contain elements used most of the time, that use URL or other\n     identifier values\n   * the `complete` configuration should contain examples of all supported elements, providing this still produces a\n     valid record, in order to ensure high test coverage\n   * where possible, configurations should be internally consistent, but this can be ignored if needed\n   * values used for identifiers and other external references should use the correct form/structure but do not need\n     to exist or relate to the resource described by each configuration (i.e. DOIs should be valid URLs but could be\n     a DOI for another resource for example)\n4. add relevant [element class](#record-element-classes):\n   * new or changed elements should be added to the configuration for the relevant package for each standard\n   * for the ISO 19115 family of standards, element classes should be added to the `iso_19115_common` package\n   * the exact module to use within this package will depend on the nature of the element being added, but in general,\n     elements should be added to the module of their parent element (e.g. `data_identification.py` for elements\n     under the `identification` record configuration property), elements used across a range of elements should be\n     added to the `common_elements.py` module\n   * remember to include references to new element class in the parent element class (in both the `make_element` and\n     `make_config` methods)\n5. [capture test records](#capturing-test-records)\n    * initially this acts as a good way to check new or changed element classes encode configuration properties\n      correctly\n    * check the git status of these test records to check existing records have changed how you expect (and haven\'t\n      changed things you didn\'t intend to for example)\n6. [capture test JSON configurations](#capturing-test-configurations-as-json)\n    * check the git status of these test configs to check they are encoded correctly from Python (i.e. dates)\n7. add tests:\n    * new test cases should be added, or existing test cases updated, in the relevant module within\n      `tests/bas_metadata_library/`\n    * for the ISO 19115 family of standards, this should be `test_standard_iso_19115_1.py`, unless the element is only\n      part of the ISO 19115-2 standard\n    * providing there are enough test configurations to test all the ways a new element can be used (e.g. with a simple\n      text string or anchor element for example), adding a test case for each element is typically enough to ensure\n      sufficient test coverage\n    * where this isn\'t the case, it\'s suggested to add one or more \'edge case\' test cases to test remaining code paths\n      explicitly\n8. check [test coverage](#test-coverage):\n    * for missing coverage, consider adding edge case test cases where applicable\n    * coverage exemptions should be avoided wherever feasible and all exemptions must be discussed before they are added\n    * where exceptions are added, they should be documented as an issue with information on how they will be addressed\n      in the longer term\n9. update `README.md` examples if common element:\n    * this is probably best done before releasing a new version\n10. update `CHANGELOG.md`\n11. if needed, add name to `authors` property in `pyproject.toml`\n\n### ISO 19115 - Automatic transfer option / format IDs\n\nID attributes are automatically added to `gmd:MD_Format` and `gmd:MD_DigitalTransferOptions` elements in order to\nreconstruct related formats and transfer options (see the\n[Linking transfer options and formats](#ISO-19115-linkages-between-transfer-options-and-formats) section for more \ninformation).\n\nWhen a record is encoded, ID values are generated by hashing a JSON encoded string of the distribution object. This\nID is used as a shared base between the format and transfer option, with `-fmt` appended for the format and `-tfo`\nfor the transfer option.\n\nWhen a record is decoded, ID values are extracted (stripping the `-fmt`/`-tfo` suffixes) to index and then match up\nformat and transfer options back into distribution options. Any format and transfer options without an ID value, or\nwithout a corresponding match, are added as partial distribution options.\n\nAs a worked example for encoding a (simplified) distribution object such as:\n\n```python\ndo = {\n   \'format\': \'csv\',\n   \'transfer_option\': {\n      \'size\': \'40\',\n      \'url\': \'https://example.com/foo.csv\'\n   }\n}\n```\n\nBecomes:\n\n```\n\'{"format":"csv","transfer_option":{"size":40,"url":"https://example.com/foo.csv"}}\'\n```\n\nWhen encoded as a JSON encoded string, which when hashed becomes:\n\n```\n16b7b5df78a664b15d69feda7ccc7caed501f341\n```\n\nThe ID value added to the `gmd:MD_Format` element would be:\n\n```xml\n<gmd:MD_Format id="bml-16b7b5df78a664b15d69feda7ccc7caed501f341-fmt">\n```\n\nAnd for the `gmd:MD_DigitalTransferOptions` element:\n\n```xml\n<gmd:MD_DigitalTransferOptions id="bml-16b7b5df78a664b15d69feda7ccc7caed501f341-tfo">\n```\n\nThe `bml-` prefix is added to ensure all IDs begin with a letter (as required by XML), and to allow IDs generated by\nthis library to be detected. The `-fmt`/`-tfo` prefixes are used to allow the same ID value to uniquely identify two\nelements uniquely.\n\n## Setup\n\n### Terraform\n\nTerraform is used to provision resources required to operate this application in staging and production environments.\n\nThese resources allow [Configuration schemas](#configuration-schemas) for each standard to be accessed externally.\n\nAccess to the [BAS AWS account](https://gitlab.data.bas.ac.uk/WSF/bas-aws) is needed to provision these resources.\n\n**Note:** This provisioning should have already been performed (and applies globally). If changes are made to this\nprovisioning it only needs to be applied once.\n\n```shell\n# start terraform inside a docker container\n$ cd provisioning/terraform\n$ docker compose run terraform\n# setup terraform\n$ terraform init\n# apply changes\n$ terraform validate\n$ terraform fmt\n$ terraform apply\n# exit container\n$ exit\n$ docker compose down\n```\n\n#### Terraform remote state\n\nState information for this project is stored remotely using a\n[Backend](https://www.terraform.io/docs/backends/index.html).\n\nSpecifically the [AWS S3](https://www.terraform.io/docs/backends/types/s3.html) backend as part of the\n[BAS Terraform Remote State](https://gitlab.data.bas.ac.uk/WSF/terraform-remote-state) project.\n\nRemote state storage will be automatically initialised when running `terraform init`. Any changes to remote state will\nbe automatically saved to the remote backend, there is no need to push or pull changes.\n\n##### Remote state authentication\n\nPermission to read and/or write remote state information for this project is restricted to authorised users. Contact\nthe [BAS Web & Applications Team](mailto:servicedesk@bas.ac.uk) to request access.\n\nSee the [BAS Terraform Remote State](https://gitlab.data.bas.ac.uk/WSF/terraform-remote-state) project for how these\npermissions to remote state are enforced.\n\n## Development\n\nThis API is developed as a Python library. A bundled Flask application is used to simulate its usage, act as\nframework for running tests etc., and provide utility methods for generating schemas etc.\n\n### Development environment\n\nGit and [Poetry](https://python-poetry.org) are required to set up a local development environment of this application.\n\n**Note:** If you use [Pyenv](https://github.com/pyenv/pyenv), this project sets a local Python version for consistency.\n\nIf you have access to the [BAS GitLab instance](https://gitlab.data.bas.ac.uk):\n\n```shell\n# clone from the BAS GitLab instance if possible\n$ git clone https://gitlab.data.bas.ac.uk/uk-pdc/metadata-infrastructure/metadata-library.git\n\n# alternatively, clone from the GitHub mirror\n$ git clone https://github.com/antarctica/metadata-library.git\n\n# setup virtual environment\n$ cd metadata-library\n$ poetry install\n```\n\n### Code Style\n\nPEP-8 style and formatting guidelines must be used for this project, except the 80 character line limit.\n[Black](https://github.com/psf/black) is used for formatting, configured in `pyproject.toml` and enforced as part of\n[Python code linting](#code-linting-python).\n\nBlack can be integrated with a range of editors, such as \n[PyCharm](https://black.readthedocs.io/en/stable/integrations/editors.html#pycharm-intellij-idea), to apply formatting \nautomatically when saving files.\n\nTo apply formatting manually:\n\n```shell\n$ poetry run black src/ tests/\n```\n\n### Code Linting (Python)\n\n[Flake8](https://flake8.pycqa.org) and various extensions are used to lint Python files in the `bas_metadata_library` \nmodule. Specific checks, and any configuration options, are documented in the `./.flake8` config file.\n\nTo check files manually:\n\n```shell\n$ poetry run flake8 src/\n```\n\nChecks are run automatically in [Continuous Integration](#continuous-integration).\n\n### Code Linting (JSON)\n\nJSON files (specifically JSON Schemas used for [Record Configurations](#configuration-schemas)) must be valid JSON \ndocuments. Minimal linting is used to enforce this as part of [Continuous Integration](#continuous-integration).\n\nTo check files manually:\n\n```shell\n$ for file in $(find ./src/bas_metadata_library/schemas/src -name "*.json"); do echo ${file}; poetry run python -m json.tool < ${file} 1>/dev/null; done\n```\n\n### Dependencies\n\nPython dependencies for this project are managed with [Poetry](https://python-poetry.org) in `pyproject.toml`.\n\nNon-code files, such as static files, can also be included in the [Python package](#python-package) using the\n`include` key in `pyproject.toml`.\n\n#### Adding new dependencies\n\nTo add a new (development) dependency:\n\n```shell\n$ poetry add [dependency] (--dev)\n```\n\nThen update the Docker image used for CI/CD builds and push to the BAS Docker Registry (which is provided by GitLab):\n\n```shell\n$ docker build -f gitlab-ci.Dockerfile -t docker-registry.data.bas.ac.uk/uk-pdc/metadata-infrastructure/metadata-library:latest .\n$ docker push docker-registry.data.bas.ac.uk/uk-pdc/metadata-infrastructure/metadata-library:latest\n```\n\n#### Updating dependencies\n\n```shell\n$ poetry update\n```\n\nSee the instructions above to update the Docker image used in CI/CD.\n\n#### Dependency vulnerability checks\n\nThe [Safety](https://pypi.org/project/safety/) package is used to check dependencies against known vulnerabilities.\n\n**IMPORTANT!** As with all security tools, Safety is an aid for spotting common mistakes, not a guarantee of secure \ncode. In particular this is using the free vulnerability database, which is updated less frequently than paid options.\n\nThis is a good tool for spotting low-hanging fruit in terms of vulnerabilities. It isn\'t a substitute for proper \nvetting of dependencies, or a proper audit of potential issues by security professionals. If in any doubt you MUST seek\nproper advice.\n\nChecks are run automatically in [Continuous Integration](#continuous-integration).\n\nTo check locally:\n\n```shell\n$ poetry export --without-hashes -f requirements.txt | poetry run safety check --full-report --stdin\n```\n\n#### `jsonschema` package\n\nThe `jsonschema` dependency is locked to version 3.2.0 because version 4.0 > dropped Python 3.6 support. This\nlibrary cannot require newer Python versions to ensure it can be used in projects that run on BAS IT infrastructure.\n\n#### `lxml` package\n\nThe `lxml` dependency takes a long time to install/update inside Alpine container images because it needs to be built \nfrom source. This is because Alpine Linux, used by the official Python Docker base images, is not supported by the \nPython [manylinux](https://github.com/pypa/manylinux) system, and therefore cannot use pre-built, binary, wheels.\n\n### Static security scanning\n\nTo ensure the security of this API, source code is checked against [Bandit](https://github.com/PyCQA/bandit)\nand enforced as part of [Python code linting](#code-linting-python).\n\n**Warning:** Bandit is a static analysis tool and can\'t check for issues that are only be detectable when running the\napplication. As with all security tools, Bandit is an aid for spotting common mistakes, not a guarantee of secure code.\n\nChecks are run automatically in [Continuous Integration](#continuous-integration).\n\n#### `lxml` package (bandit)\n\nBandit identifies the use of `lxml` classes and methods as a security issue, specifically:\n\n> Element to parse untrusted XML data is known to be vulnerable to XML attacks\n\nThe recommendation is to use a *safe* implementation of an XML processor (`defusedxml`) that can avoid entity bombs and \nother XML processing attacks. However, `defusedxml` does not offer all of the methods we need and there does not appear\nto be such another processor that does provide them.\n\nThe main vulnerability this security issue relates to is processing user input that can\'t be trusted. This isn\'t really\napplicable to this library directly, but rather to where it\'s used in implementing projects. I.e. if this library is \nused in a service that accepts user input, an assessment must be made whether the input needs to be sanitised.\n\nWithin this library itself, the only input that is processed is test records, all of which are assumed to be safe to \nprocess.\n\n### Generating configuration schemas\n\nTo generate [distribution schemas from source schemas](#source-and-distribution-schemas), a custom Flask CLI command,\n`generate-schemas` is available. The [`jsonref`](https://jsonref.readthedocs.io/en/latest/) library is used to resolve\nany references in source schemas and write the output as distribution schemas, replacing any existing output.\n\n```shell\n$ poetry run flask generate-schemas\n```\n\nTo configure this command, (e.g. to add a new schema for a new standard/profile), adjust the `schemas` list in the\n`generate_schemas` method in `app.py`. This list should contain dictionaries with keys for the common name of the\nschema (based on the common file name of the schema JSON file), and whether the source schema should be resolved or\nsimply copied. This should be true by default, and is only relevant to schemas that do not contain any references, as\nthis will cause an error if resolved.\n\n## Testing\n\nAll code in the `bas_metadata_library` module must be covered by tests, defined in `tests/`. This project uses\n[PyTest](https://docs.pytest.org/en/latest/) which should be run in a random order using\n[pytest-random-order](https://pypi.org/project/pytest-random-order/).\n\nTests are written to create metadata records based on a series of configurations defined in `tests/resources/configs/`.\nThese define \'minimal\' to \'complete\' test records, intended to test different ways a standard can be used, both for\nindividual elements and whole records. These tests are designed to ensure that records are generally well-formed and\nthat where config options are used the corresponding elements in the metadata record are generated.\n\nAs this library does not seek to support all possible elements and variations within each standard, these tests are\nsimilarly not exhaustive, nor are they a substitute for formal metadata validation.\n\nTest methods are used to test individual elements are formed correctly. Comparisons against static records are used to\ntest the structure of whole records.\n\nTo run tests manually from the command line:\n\n```shell\n$ poetry run pytest --random-order\n```\n\nTo run tests manually using PyCharm, use the included *App (Tests)* run/debug configuration.\n\nTests are run automatically in [Continuous Integration](#continuous-integration).\n\n### Capturing test records\n\nTo capture test records, which verify complete records are assembled correctly, a custom Flask CLI command,\n`capture-test-records` is available. This requires the Flask application to be running and uses the *Requests* \nlibrary to make requests against the Flask app, saving responses to a relevant directory in `tests/resources/records`.\n\n```shell\n# start Flask application:\n$ poetry run flask run\n\n# then in a separate terminal:\n$ poetry run flask capture-test-records\n```\n\nIt is intended that this command will update pre-existing records, with differences captured in version control to aid \nmanual review to ensure they are correct.\n\n### Capturing test configurations as JSON\n\nTo capture test configurations as JSON, which verify the dump/load methods of configuration classes work encode and \ndecode information correctly, a custom Flask CLI command, `capture-json-test-configs` is available. This will dump all \ntest configurations for each standard to set of JSON files in `tests/resources/configs/`. \n\n```shell\n$ poetry run flask capture-json-test-configs\n```\n\nThese files MUST then be manually verified to ensure they have encoded each configuration correctly. Once they have, \nthey can be used in tests to automatically verify this remains the case.\n\nIt is intended that this command will update pre-existing configurations, with differences captured in version control\nto aid in manual review to ensure they are correct.\n\n### Test coverage\n\n[pytest-cov](https://pypi.org/project/pytest-cov/) is used to measure test coverage.\n\nTo measure coverage manually:\n\n```shell\n$ poetry run pytest --random-order --cov=bas_metadata_library --cov-fail-under=100 --cov-report=html .\n```\n\n[Continuous Integration](#continuous-integration) will check coverage automatically and fail if less than 100%.\n\n### Continuous Integration\n\nAll commits will trigger a Continuous Integration process using GitLab\'s CI/CD platform, configured in `.gitlab-ci.yml`.\n\n## Deployment\n\n### Python package\n\nThis project is distributed as a Python package, hosted in [PyPi](https://pypi.org/project/bas-metadata-library).\n\nSource and binary packages are built and published automatically using\n[Poetry](https://python-poetry.org) in [Continuous Deployment](#continuous-deployment).\n\n**Note:** Except for tagged releases, Python packages built in CD will use `0.0.0` as a version to indicate they are \nnot formal releases.\n\n### Continuous Deployment\n\nA Continuous Deployment process using GitLab\'s CI/CD platform is configured in `.gitlab-ci.yml`.\n\n## Release procedure\n\nFor all releases, create a release issue by creating a new [issue](#issue-tracking), with the \'release\' issue template,\nand follow its instructions.\n\n## Feedback\n\nThe maintainer of this project is the BAS Web & Applications Team, they can be contacted at:\n[servicedesk@bas.ac.uk](mailto:servicedesk@bas.ac.uk).\n\n## Issue tracking\n\nThis project uses issue tracking, see the\n[Issue tracker](https://gitlab.data.bas.ac.uk/uk-pdc/metadata-infrastructure/metadata-library/issues) for more\ninformation.\n\n**Note:** Read & write access to this issue tracker is restricted. Contact the project maintainer to request access.\n\n## License\n\nCopyright (c) 2019-2022 UK Research and Innovation (UKRI), British Antarctic Survey.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the "Software"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n',
    'author': 'Felix Fennell',
    'author_email': 'felnne@bas.ac.uk',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/antarctica/metadata-library',
    'package_dir': package_dir,
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.6.2,<4.0.0',
}


setup(**setup_kwargs)
