Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: set up resources #109

Merged
merged 1 commit into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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