Skip to content

Commit

Permalink
feat!: set up resources (#109)
Browse files Browse the repository at this point in the history
Fixes #7
  • Loading branch information
afuetterer committed Jun 5, 2024
1 parent f242b10 commit 0d766d2
Show file tree
Hide file tree
Showing 22 changed files with 3,661 additions and 123 deletions.
13 changes: 11 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,15 @@ repos:
hooks:
- id: mdformat
args: [--number, --wrap=120, --ignore-missing-references]
exclude: CHANGELOG.md|.changelog.md|docs/src/cli.md|docs/src/exceptions.md
exclude: |
(?x)^(
CHANGELOG.md|
.changelog.md|
docs/src/api.md|
docs/src/cli.md|
docs/src/exceptions.md|
docs/src/resources.md
)$
additional_dependencies:
- mdformat-mkdocs[recommended]>=v2.0.7

Expand All @@ -81,6 +89,7 @@ repos:
- pytest>=8.2
- respx>=0.21
- typer>=0.12
- xsdata>=24.5

- repo: https://github.com/scientific-python/cookie
rev: 28d1a53da26f9daff6d9a49c50260421ad6d05e0 # frozen: 2024.04.23
Expand All @@ -92,7 +101,7 @@ repos:
hooks:
- id: typos
args: [--force-exclude]
exclude: tests/conftest
exclude: src/re3data/_resources/repository.py|tests/conftest.py

- repo: https://github.com/FHPythonUtils/LicenseCheck/
rev: b2b50f4d40c95b15478279a7a00553a1dc2925ef # frozen: 2024.2
Expand Down
37 changes: 18 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,15 @@ metadata about research data repositories in a convenient and Pythonic way.
```pycon
>>> import re3data
>>> response = re3data.repositories.list()
>>> print(response)
<?xml version="1.0" encoding="UTF-8"?>
<list>
<repository>
<id>r3d100010468</id>
<doi>https://doi.org/10.17616/R3QP53</doi>
<name>Zenodo</name>
<link href="https://www.re3data.org/api/beta/repository/r3d100010468" rel="self" />
</repository>
>>> response
[RepositorySummary(id='r3d100010468', doi='https://doi.org/10.17616/R3QP53', name='Zenodo', link=Link(href='https://www.re3data.org/api/beta/repository/r3d100010468', rel='self'))]
... (remaining repositories truncated)
```

```pycon
>>> response = re3data.repositories.get("r3d100010468")
>>> print(response)
<?xml version="1.0" encoding="utf-8"?>
<!--re3data.org Schema for the Description of Research Data Repositories. Version 2.2, December 2014. doi:10.2312/re3.006-->
<r3d:re3data xmlns:r3d="http://www.re3data.org/schema/2-2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.re3data.org/schema/2-2 http://schema.re3data.org/2-2/re3dataV2-2.xsd">
<r3d:repository>
<r3d:re3data.orgIdentifier>r3d100010468</r3d:re3data.orgIdentifier>
<r3d:repositoryName language="eng">Zenodo</r3d:repositoryName>
<r3d:repositoryURL>https://zenodo.org/</r3d:repositoryURL>
>>> response
Repository(re3data_org_identifier='r3d100010468', repository_name=RepositoryName(value='Zenodo', language=<Languages.ENG: 'eng'>), additional_name=[], repository_url='https://zenodo.org/', repository_identifier=['FAIRsharing_doi:10.25504/FAIRsharing.wy4egf', 'RRID:SCR_004129', 'RRID:nlx_158614'])
... (remaining fields truncated)
```

Expand All @@ -51,15 +38,27 @@ metadata about research data repositories in a convenient and Pythonic way.
`re3data.repositories.list()`.
- Repository details retrieval: Get detailed information about a specific repository using
`re3data.repositories.get(repository_id)`.
- XML response parsers: API XML responses are parsed into Python dataclasses, providing convenient access to the
elements of the [re3data.org Schema 2.2 XML Schema](https://www.re3data.org/schema/2-2). This makes it easy to work
with the rich metadata provided by the API.
- Flexible response options: The response type can be switched between:
- dataclass (default): Returns a Python dataclass object, allowing convenient access to the element of the re3data
schema
- response: Returns a Python object representing the API response
- original XML: Returns the raw XML response from the API

## Requirements

[Python](https://www.python.org/downloads/) >= 3.10

`python-re3data` is built with:

- [httpx](https://github.com/encode/httpx) for issuing HTTP requests
- [typer](https://github.com/tiangolo/typer) for its CLI
- **HTTP Requests**: [httpx](https://github.com/encode/httpx), a modern and efficient HTTP client library, handles all
API interactions.
- **XML Parsing**: [xsdata](https://github.com/tefra/xsdata), a powerful tool for generating Python dataclasses from XML
schemas, simplifies processing of API responses.
- **Optional CLI**: [typer](https://github.com/tiangolo/typer), a popular library for building command-line interfaces,
powers the user-friendly interface.

## Installation

Expand Down
1 change: 1 addition & 0 deletions docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ nav:
- Home: index.md
- Reference:
- API Reference: api.md
- Resources: resources.md
- Exceptions: exceptions.md
- Command Line Interface: cli.md
- Meta:
Expand Down
12 changes: 12 additions & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# API Reference

## `BaseClient`

::: re3data._client.BaseClient

## `Client`

::: re3data.Client

## `RepositoryManager`

::: re3data._client.RepositoryManager

## `Response`

::: re3data.Response
1 change: 1 addition & 0 deletions docs/src/resources.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
::: re3data._resources
14 changes: 14 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ dynamic = [
]
dependencies = [
"httpx>=0.27",
"xsdata>=24.5",
]
optional-dependencies.cli = [
"typer>=0.12",
Expand Down Expand Up @@ -78,8 +79,13 @@ scripts.re3data = "re3data.__main__:app"
only-include = [
"src/re3data",
]
exclude = [
"src/re3data/_resources/*.md",
"src/re3data/_resources/*.xml",
]

[tool.hatch.build.targets.wheel]
only-packages = true
packages = [
"src/re3data",
]
Expand Down Expand Up @@ -172,6 +178,13 @@ lint.ignore = [
lint.per-file-ignores."src/re3data/__about__.py" = [
"D100", # undocumented-public-module
]
lint.per-file-ignores."src/re3data/_resources/*" = [
"D101", # undocumented-public-class
"D106", # undocumented-public-nested-class
"D205", # blank-line-after-summary
"D415", # ends-in-punctuation
"TCH002", # typing-only-third-party-import
]
lint.per-file-ignores."tests/*" = [
"D100", # undocumented-public-module
"D103", # undocumented-public-function
Expand Down Expand Up @@ -225,6 +238,7 @@ omit = [
exclude_also = [
"if TYPE_CHECKING:",
"@abstractmethod",
"@overload",
]
fail_under = 90
show_missing = true
Expand Down
9 changes: 8 additions & 1 deletion requirements/docs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# This file is autogenerated by hatch-pip-compile with Python 3.12
#
# - httpx>=0.27
# - xsdata>=24.5
# - typer>=0.12
# - mike~=2.1
# - mkdocs-include-markdown-plugin~=6.0
Expand Down Expand Up @@ -536,7 +537,9 @@ typer==0.12.3 \
typing-extensions==4.12.0 \
--hash=sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8 \
--hash=sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594
# via typer
# via
# typer
# xsdata
urllib3==2.2.1 \
--hash=sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d \
--hash=sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19
Expand Down Expand Up @@ -583,6 +586,10 @@ wcmatch==8.5.2 \
--hash=sha256:17d3ad3758f9d0b5b4dedc770b65420d4dac62e680229c287bf24c9db856a478 \
--hash=sha256:a70222b86dea82fb382dd87b73278c10756c138bd6f8f714e2183128887b9eb2
# via mkdocs-include-markdown-plugin
xsdata==24.5 \
--hash=sha256:4e8414a01bff603ca38a361d04d819934fcc525f9b4220f0076e040d84a4a963 \
--hash=sha256:6ff12949083d9a0d9934c50401b347ccbf254bb10bf8472aef956b92662f7858
# via hatch.envs.docs
zipp==3.19.0 \
--hash=sha256:952df858fb3164426c976d9338d3961e8e8b3758e2e059e0f754b8c4262625ee \
--hash=sha256:96dc6ad62f1441bcaccef23b274ec471518daf4fbbc580341204936a5a3dddec
Expand Down
12 changes: 10 additions & 2 deletions src/re3data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,22 @@
"""python-re3data."""

from re3data.__about__ import __version__
from re3data._client import Client
from re3data._client import Client, ReturnType
from re3data._exceptions import Re3dataError, RepositoryNotFoundError
from re3data._resources import Re3Data, Repository, RepositoryList, RepositorySummary
from re3data._response import Response

__all__ = [
"__version__",
"Client",
"Re3Data",
"Re3dataError",
"Repository",
"RepositoryList",
"RepositoryNotFoundError",
"RepositorySummary",
"Response",
"ReturnType",
"__version__",
]

_client = Client()
Expand Down
15 changes: 10 additions & 5 deletions src/re3data/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import re3data
from re3data._client import ReturnType
from re3data._exceptions import RepositoryNotFoundError

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -69,14 +70,18 @@ def callback(


@repositories_app.command("list")
def list_repositories(return_type: ReturnType = ReturnType.xml) -> None:
def list_repositories(return_type: ReturnType = ReturnType.DATACLASS) -> None:
"""List the metadata of all repositories in the re3data API."""
response = re3data.repositories.list(return_type=return_type.value)
response = re3data.repositories.list(return_type)
console.print(response)


@repositories_app.command("get")
def get_repository(repository_id: str, return_type: ReturnType = ReturnType.xml) -> None:
def get_repository(repository_id: str, return_type: ReturnType = ReturnType.DATACLASS) -> None:
"""Get the metadata of a specific repository."""
response = re3data.repositories.get(repository_id, return_type=return_type.value)
console.print(response)
try:
response = re3data.repositories.get(repository_id, return_type)
console.print(response)
except RepositoryNotFoundError as error:
print_error(str(error))
raise typer.Exit(code=1) from error
Loading

0 comments on commit 0d766d2

Please sign in to comment.