doipy


Namedoipy JSON
Version 0.4.0 PyPI version JSON
download
home_pageNone
SummaryA Python wrapper for DOIP.
upload_time2024-08-03 12:03:23
maintainerNone
docs_urlNone
authorTriet Doan
requires_python<4.0,>=3.11
licenseNone
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # DOIPY

DOIPY is a Python wrapper for communication using the Digital Object Interface Protocol (DOIP) in its current
[specification v2.0](https://www.dona.net/sites/default/files/2018-11/DOIPv2Spec_1.pdf).

It supports three main functionalities:

1. Receive the IP and port of a DOIP service by supplying the service ID (see `get_connection`).
2. All basic DOIP operations to handle digital objects (DOs): `hello`, `list_operations`, `create`, `update`, `delete`, 
   `retrieve`, and `search`. Extended operations implemented by specific repository software are and will be included in 
    the future.
3. Some FDO-Manager functionality to handle FAIR digital objects (FDOs): Create an FDO (see `create_fdo`) that complies
   with configuration type 14, which is expressed by a combination of DOIP basic operations, validation steps and
   communication with the data type registry (DTR).

## Install

Simply run

```shell
$ pip install doipy
```

## Usage (Python Code)

To use the `doipy` package in the Python code simply import it and call the exposed methods. The package has several
methods. Please use `doipy --help` to list all available methods.

### 1. Get the IP and Port of a DOIP Service

The service ID is a handle which identifies a DOIP service. For example, `21.T11967/service` is the service ID
identifying the Cordra instance in the FDO One Testbed. Starting with the service ID, one receives the IP and port of
the DOIP service by applying the `get_connection` function.

```python
from doipy import get_connection

# get the IP and port of a DOIP service
service_id, ip, port = get_connection('21.T11967/service')
```

### 2. Basic DOIP Operations

To communicate with a DOIP service, one has to supply a target ID as well as the IP and port of the desired service. For
the operations `hello`, `create`, and `search`, the target ID is equal to the service ID. For `retrieve`, `delete`,
and `update`, the target ID corresponds to the PID of a DO. For `list_operations`, the target ID might be either a
service ID or a DO PID. Below is demonstrated how to apply operations where the service ID is required.

```python
from doipy import get_connection, hello, list_operations, create, search
from pathlib import Path

# get the IP and port of a DOIP service
service_id, ip, port = get_connection(service='21.T11967/service')

# say hello to the data service
response_hello = hello(target_id=service_id, ip=ip, port=port)

# list all available operations at the data service
response_list_operations = list_operations(target_id=service_id, ip=ip, port=port)

# create a DO at the data service
metadata = {'key1': 'value1', 'key2': 'value2'}
username = ''
password = ''
# possibilities for authentication: provide either (username, password) or (client_id, password) or (token). The 
# authentication credentials are the credentials to authenticate the user at the DOIP service.
response_create = create(target_id=service_id, ip=ip, port=port, bitsq=Path('file.txt'), metadata=metadata, 
                         username=username, password=password)

# call the search operation
response_search = search(target_id=service_id, ip=ip, port=port, query='type:Document', username=username, password=password)
```

For the operations `list_operations`, `retrieve`, `delete`, and `update`, the target ID corresponds to a PID identifying
a DO. As an example, we take the PID `21.T11967/35463c4d5e1cf0449a31` which identifies a DO at the Cordra instance of
the FDO One Testbed. To run those operations in the Python code, one can follow the lines below.

```python
from doipy import get_connection, list_operations, retrieve, delete

# get the IP and port of a DOIP service
_, ip, port = get_connection('21.T11967/service')

do = '21.T11967/35463c4d5e1cf0449a31'
username = ''
password = ''

# list all available operations on the given DO
response_list_operations = list_operations(target_id=do, ip=ip, port=port, username=username, password=password)

# retrieve a DO
response_retrieve = retrieve(target_id=do, ip=ip, port=port, username=username, password=password)

# download a bit-sequence of a DO. The file must be the id of the bit-sequence to be downloaded.
response_download = retrieve(target_id=do, ip=ip, file='031c09fd-d45d-48b0-acab-57ec049bb6c8', port=port, username=username, password=password)

# delete a DO
response_delete = delete(target_id=do, ip=ip, port=port, username=username, password=password)

# call the update operation (todo)
```

### 3. FDO Manager

To create an FDO in the Python code, one needs to supply a Python dictionary which follows the structure of the schema 
defined at https://typeapi.lab.pidconsortium.net/v1/types/schema/21.T11969/6e36f6c0de5fcab4a425 as input to 
`create_fdo`.

The `create_fdo` function supports FDOs following configuration type 14, i.e., which consist of multiple data DOs and 
multiple metadata DOs.

Each item in `FDO_Data_and_Metadata` is a data bit-sequence `data_bitsq` and its corresponding metadata bit-sequence
`metadata_bitsq`. One DO is generated for the data bit-sequence and one DO is generated for the metadata bit-sequence.
The content of `data_values` is written into the PID record of the data DO. The content of `metadata_values` is written
into the PID record of the metadata DO.

Use `create_fdo` to register an FDO with specified (meta)data bit-sequences:

```python
from doipy import create_fdo

user_input = {
  "FDO_Service_Ref": "21.T11969/01370800d56a0d897dc1",
  "FDO_Profile_Ref": "21.T11969/141bf451b18a79d0fe66",
  "FDO_Authentication": {
    "username": "",
    "password": ""
  },
  "FDO_Type_Ref": "21.1/thisIsAnFdoType",
  "FDO_Rights_Ref": "21.1/thisIsAnFdoRightsSpecification",
  "FDO_Genre_Ref": "21.1/thisIsAnFdoGenre",
  "FDO_Data_and_Metadata": [
    {
      "data_bitsq": "data_bitsq_1.txt",
      "data_values": "data_values_1.json",
      "metadata_bitsq": "metadata_bitsq_1.json",
      "metadata_values": "metadata_values_1.json"
    },
    {
      "data_bitsq": "data_bitsq_2.txt",
      "data_values": "data_values_2.json",
      "metadata_bitsq": "metadata_bitsq_2.json",
      "metadata_values": "metadata_values_2.json"
    }
  ]
}

# create an FDO
response_create_fdo = create_fdo(user_input)
```

### Authentication

If authentication credentials need to be provided, then the user has several options to authenticate:

1. `username` and `password`
2. `client_id` and `password`
3. `token`

Authentication credentials must be provided for the DOIP functions: `create`, `delete`, and `update`. Depending on 
the rights for read access, authentication credentials might be necessary for `list_operations` of a DO, `retrieve`, and
`search` as well. Authentication credentials must be provided for the FDO-Manager functions: `create_fdo`. Note that not 
all data services accept all three options of authentication credentials.

## Usage (Command Line Interface)

### 1. Get the IP and port of a DOIP service

Starting with the service ID, receive the IP and port of the DOIP service by applying the `get_connection` function.

```shell
# get the IP and port of a DOIP service
$ doipy get_connection '21.T11967/service'
```

### 2. Basic DOIP Operations

We demonstrate how to apply operations `hello`, `list_operations`, `create`, and `search` on the DOIP service which is
identified by the service ID.
Additional to the service ID, IP and port, the `create` operation has more parameters: The `do_type` refers to the type
of the DO at the data service, which is `Document` in Cordra. `bitsq` is a path to a file which contains the data of the
DO. `metadata` is a path to a JSON file containing the metadata. The key-value pairs from the JSON file are written into
the handle record of the DO at generation. `username` and `password`are the authentication credentials of a user at
the data service.

```shell
# get information from the DOIP service
$ doipy hello '21.T11967/service' '141.5.106.77' 9000

# list all available operations at the DOIP service
$ doipy list_operations '21.T11967/service' '141.5.106.77' 9000

# create a DO at the DOIP service
$ doipy create '21.T11967/service' '141.5.106.77' 9000 --do-type 'Document' --do-name 'my_DO' --bitsq 'data.txt' --metadata 'metadata.json' --username '' --password ''

# search in the DOIP service for a DO (todo)
$ doipy search '21.T11967/service' '141.5.106.77' 9000 'type:Document' --username '' --password ''
```

Apply the functions `list_operations` , `retrieve`, `delete`, and `update` on the DO which is identified by the PID
`"21.T11967/35463c4d5e1cf0449a31`.

```shell
# List all available operations of a DO
$ doipy list_operations '21.T11967/35463c4d5e1cf0449a31' '141.5.106.77' 9000 --username '' --password ''

# retrieve a DO 
$ doipy retrieve '21.T11967/35463c4d5e1cf0449a31' '141.5.106.77' 9000 --username '' --password ''

# download a bit-sequence of a DO. The file must be the id of the bit-sequence to be downloaded.
$ doipy retrieve '21.T11967/35463c4d5e1cf0449a31' '141.5.106.77' 9000 --file '031c09fd-d45d-48b0-acab-57ec049bb6c8' --username '' --password ''

# delete a DO
$ doipy delete '21.T11967/35463c4d5e1cf0449a31' '141.5.106.77' 9000 --username '' --password ''

# update a DO (todo)
```

### 3. FDO Manager

To create an FDO on the CLI, first create a JSON file (called input.json), whose content follows
the schema defined at https://typeapi.lab.pidconsortium.net/v1/types/schema/21.T11969/6e36f6c0de5fcab4a425

An example JSON file could look like this:

```json
{
  "FDO_Service_Ref": "21.T11969/01370800d56a0d897dc1",
  "FDO_Profile_Ref": "21.T11969/141bf451b18a79d0fe66",
  "FDO_Authentication": {
    "username": "",
    "password": ""
  },
  "FDO_Type_Ref": "21.1/thisIsAnFdoType",
  "FDO_Rights_Ref": "21.1/thisIsAnFdoRightsSpecification",
  "FDO_Genre_Ref": "21.1/thisIsAnFdoGenre",
  "FDO_Data_and_Metadata": [
    {
      "data_bitsq": "data_bitsq_1.txt",
      "data_values": "data_values_1.json",
      "metadata_bitsq": "metadata_bitsq_1.json",
      "metadata_values": "metadata_values_1.json"
    },
    {
      "data_bitsq": "data_bitsq_2.txt",
      "data_values": "data_values_2.json",
      "metadata_bitsq": "metadata_bitsq_2.json",
      "metadata_values": "metadata_values_2.json"
    }
  ]
}
```

Use `create_fdo` to register an FDO with specified (meta)data bit-sequences:

```shell
$ doipy create_fdo input.json
```

## For developer

The project is managed by [Poetry](https://python-poetry.org/). Therefore, make sure that Poetry is installed in your
system. Then run

```shell
$ poetry install
```

to install all dependencies. With this command, Poetry also installs the package in editable mode.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "doipy",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.11",
    "maintainer_email": null,
    "keywords": null,
    "author": "Triet Doan",
    "author_email": "triet.doan@gwdg.de",
    "download_url": "https://files.pythonhosted.org/packages/71/3d/dcdd49d5abf0600e334af3d6a512f581f74c9e47a3d95cbcb8da15e36f94/doipy-0.4.0.tar.gz",
    "platform": null,
    "description": "# DOIPY\n\nDOIPY is a Python wrapper for communication using the Digital Object Interface Protocol (DOIP) in its current\n[specification v2.0](https://www.dona.net/sites/default/files/2018-11/DOIPv2Spec_1.pdf).\n\nIt supports three main functionalities:\n\n1. Receive the IP and port of a DOIP service by supplying the service ID (see `get_connection`).\n2. All basic DOIP operations to handle digital objects (DOs): `hello`, `list_operations`, `create`, `update`, `delete`, \n   `retrieve`, and `search`. Extended operations implemented by specific repository software are and will be included in \n    the future.\n3. Some FDO-Manager functionality to handle FAIR digital objects (FDOs): Create an FDO (see `create_fdo`) that complies\n   with configuration type 14, which is expressed by a combination of DOIP basic operations, validation steps and\n   communication with the data type registry (DTR).\n\n## Install\n\nSimply run\n\n```shell\n$ pip install doipy\n```\n\n## Usage (Python Code)\n\nTo use the `doipy` package in the Python code simply import it and call the exposed methods. The package has several\nmethods. Please use `doipy --help` to list all available methods.\n\n### 1. Get the IP and Port of a DOIP Service\n\nThe service ID is a handle which identifies a DOIP service. For example, `21.T11967/service` is the service ID\nidentifying the Cordra instance in the FDO One Testbed. Starting with the service ID, one receives the IP and port of\nthe DOIP service by applying the `get_connection` function.\n\n```python\nfrom doipy import get_connection\n\n# get the IP and port of a DOIP service\nservice_id, ip, port = get_connection('21.T11967/service')\n```\n\n### 2. Basic DOIP Operations\n\nTo communicate with a DOIP service, one has to supply a target ID as well as the IP and port of the desired service. For\nthe operations `hello`, `create`, and `search`, the target ID is equal to the service ID. For `retrieve`, `delete`,\nand `update`, the target ID corresponds to the PID of a DO. For `list_operations`, the target ID might be either a\nservice ID or a DO PID. Below is demonstrated how to apply operations where the service ID is required.\n\n```python\nfrom doipy import get_connection, hello, list_operations, create, search\nfrom pathlib import Path\n\n# get the IP and port of a DOIP service\nservice_id, ip, port = get_connection(service='21.T11967/service')\n\n# say hello to the data service\nresponse_hello = hello(target_id=service_id, ip=ip, port=port)\n\n# list all available operations at the data service\nresponse_list_operations = list_operations(target_id=service_id, ip=ip, port=port)\n\n# create a DO at the data service\nmetadata = {'key1': 'value1', 'key2': 'value2'}\nusername = ''\npassword = ''\n# possibilities for authentication: provide either (username, password) or (client_id, password) or (token). The \n# authentication credentials are the credentials to authenticate the user at the DOIP service.\nresponse_create = create(target_id=service_id, ip=ip, port=port, bitsq=Path('file.txt'), metadata=metadata, \n                         username=username, password=password)\n\n# call the search operation\nresponse_search = search(target_id=service_id, ip=ip, port=port, query='type:Document', username=username, password=password)\n```\n\nFor the operations `list_operations`, `retrieve`, `delete`, and `update`, the target ID corresponds to a PID identifying\na DO. As an example, we take the PID `21.T11967/35463c4d5e1cf0449a31` which identifies a DO at the Cordra instance of\nthe FDO One Testbed. To run those operations in the Python code, one can follow the lines below.\n\n```python\nfrom doipy import get_connection, list_operations, retrieve, delete\n\n# get the IP and port of a DOIP service\n_, ip, port = get_connection('21.T11967/service')\n\ndo = '21.T11967/35463c4d5e1cf0449a31'\nusername = ''\npassword = ''\n\n# list all available operations on the given DO\nresponse_list_operations = list_operations(target_id=do, ip=ip, port=port, username=username, password=password)\n\n# retrieve a DO\nresponse_retrieve = retrieve(target_id=do, ip=ip, port=port, username=username, password=password)\n\n# download a bit-sequence of a DO. The file must be the id of the bit-sequence to be downloaded.\nresponse_download = retrieve(target_id=do, ip=ip, file='031c09fd-d45d-48b0-acab-57ec049bb6c8', port=port, username=username, password=password)\n\n# delete a DO\nresponse_delete = delete(target_id=do, ip=ip, port=port, username=username, password=password)\n\n# call the update operation (todo)\n```\n\n### 3. FDO Manager\n\nTo create an FDO in the Python code, one needs to supply a Python dictionary which follows the structure of the schema \ndefined at https://typeapi.lab.pidconsortium.net/v1/types/schema/21.T11969/6e36f6c0de5fcab4a425 as input to \n`create_fdo`.\n\nThe `create_fdo` function supports FDOs following configuration type 14, i.e., which consist of multiple data DOs and \nmultiple metadata DOs.\n\nEach item in `FDO_Data_and_Metadata` is a data bit-sequence `data_bitsq` and its corresponding metadata bit-sequence\n`metadata_bitsq`. One DO is generated for the data bit-sequence and one DO is generated for the metadata bit-sequence.\nThe content of `data_values` is written into the PID record of the data DO. The content of `metadata_values` is written\ninto the PID record of the metadata DO.\n\nUse `create_fdo` to register an FDO with specified (meta)data bit-sequences:\n\n```python\nfrom doipy import create_fdo\n\nuser_input = {\n  \"FDO_Service_Ref\": \"21.T11969/01370800d56a0d897dc1\",\n  \"FDO_Profile_Ref\": \"21.T11969/141bf451b18a79d0fe66\",\n  \"FDO_Authentication\": {\n    \"username\": \"\",\n    \"password\": \"\"\n  },\n  \"FDO_Type_Ref\": \"21.1/thisIsAnFdoType\",\n  \"FDO_Rights_Ref\": \"21.1/thisIsAnFdoRightsSpecification\",\n  \"FDO_Genre_Ref\": \"21.1/thisIsAnFdoGenre\",\n  \"FDO_Data_and_Metadata\": [\n    {\n      \"data_bitsq\": \"data_bitsq_1.txt\",\n      \"data_values\": \"data_values_1.json\",\n      \"metadata_bitsq\": \"metadata_bitsq_1.json\",\n      \"metadata_values\": \"metadata_values_1.json\"\n    },\n    {\n      \"data_bitsq\": \"data_bitsq_2.txt\",\n      \"data_values\": \"data_values_2.json\",\n      \"metadata_bitsq\": \"metadata_bitsq_2.json\",\n      \"metadata_values\": \"metadata_values_2.json\"\n    }\n  ]\n}\n\n# create an FDO\nresponse_create_fdo = create_fdo(user_input)\n```\n\n### Authentication\n\nIf authentication credentials need to be provided, then the user has several options to authenticate:\n\n1. `username` and `password`\n2. `client_id` and `password`\n3. `token`\n\nAuthentication credentials must be provided for the DOIP functions: `create`, `delete`, and `update`. Depending on \nthe rights for read access, authentication credentials might be necessary for `list_operations` of a DO, `retrieve`, and\n`search` as well. Authentication credentials must be provided for the FDO-Manager functions: `create_fdo`. Note that not \nall data services accept all three options of authentication credentials.\n\n## Usage (Command Line Interface)\n\n### 1. Get the IP and port of a DOIP service\n\nStarting with the service ID, receive the IP and port of the DOIP service by applying the `get_connection` function.\n\n```shell\n# get the IP and port of a DOIP service\n$ doipy get_connection '21.T11967/service'\n```\n\n### 2. Basic DOIP Operations\n\nWe demonstrate how to apply operations `hello`, `list_operations`, `create`, and `search` on the DOIP service which is\nidentified by the service ID.\nAdditional to the service ID, IP and port, the `create` operation has more parameters: The `do_type` refers to the type\nof the DO at the data service, which is `Document` in Cordra. `bitsq` is a path to a file which contains the data of the\nDO. `metadata` is a path to a JSON file containing the metadata. The key-value pairs from the JSON file are written into\nthe handle record of the DO at generation. `username` and `password`are the authentication credentials of a user at\nthe data service.\n\n```shell\n# get information from the DOIP service\n$ doipy hello '21.T11967/service' '141.5.106.77' 9000\n\n# list all available operations at the DOIP service\n$ doipy list_operations '21.T11967/service' '141.5.106.77' 9000\n\n# create a DO at the DOIP service\n$ doipy create '21.T11967/service' '141.5.106.77' 9000 --do-type 'Document' --do-name 'my_DO' --bitsq 'data.txt' --metadata 'metadata.json' --username '' --password ''\n\n# search in the DOIP service for a DO (todo)\n$ doipy search '21.T11967/service' '141.5.106.77' 9000 'type:Document' --username '' --password ''\n```\n\nApply the functions `list_operations` , `retrieve`, `delete`, and `update` on the DO which is identified by the PID\n`\"21.T11967/35463c4d5e1cf0449a31`.\n\n```shell\n# List all available operations of a DO\n$ doipy list_operations '21.T11967/35463c4d5e1cf0449a31' '141.5.106.77' 9000 --username '' --password ''\n\n# retrieve a DO \n$ doipy retrieve '21.T11967/35463c4d5e1cf0449a31' '141.5.106.77' 9000 --username '' --password ''\n\n# download a bit-sequence of a DO. The file must be the id of the bit-sequence to be downloaded.\n$ doipy retrieve '21.T11967/35463c4d5e1cf0449a31' '141.5.106.77' 9000 --file '031c09fd-d45d-48b0-acab-57ec049bb6c8' --username '' --password ''\n\n# delete a DO\n$ doipy delete '21.T11967/35463c4d5e1cf0449a31' '141.5.106.77' 9000 --username '' --password ''\n\n# update a DO (todo)\n```\n\n### 3. FDO Manager\n\nTo create an FDO on the CLI, first create a JSON file (called input.json), whose content follows\nthe schema defined at https://typeapi.lab.pidconsortium.net/v1/types/schema/21.T11969/6e36f6c0de5fcab4a425\n\nAn example JSON file could look like this:\n\n```json\n{\n  \"FDO_Service_Ref\": \"21.T11969/01370800d56a0d897dc1\",\n  \"FDO_Profile_Ref\": \"21.T11969/141bf451b18a79d0fe66\",\n  \"FDO_Authentication\": {\n    \"username\": \"\",\n    \"password\": \"\"\n  },\n  \"FDO_Type_Ref\": \"21.1/thisIsAnFdoType\",\n  \"FDO_Rights_Ref\": \"21.1/thisIsAnFdoRightsSpecification\",\n  \"FDO_Genre_Ref\": \"21.1/thisIsAnFdoGenre\",\n  \"FDO_Data_and_Metadata\": [\n    {\n      \"data_bitsq\": \"data_bitsq_1.txt\",\n      \"data_values\": \"data_values_1.json\",\n      \"metadata_bitsq\": \"metadata_bitsq_1.json\",\n      \"metadata_values\": \"metadata_values_1.json\"\n    },\n    {\n      \"data_bitsq\": \"data_bitsq_2.txt\",\n      \"data_values\": \"data_values_2.json\",\n      \"metadata_bitsq\": \"metadata_bitsq_2.json\",\n      \"metadata_values\": \"metadata_values_2.json\"\n    }\n  ]\n}\n```\n\nUse `create_fdo` to register an FDO with specified (meta)data bit-sequences:\n\n```shell\n$ doipy create_fdo input.json\n```\n\n## For developer\n\nThe project is managed by [Poetry](https://python-poetry.org/). Therefore, make sure that Poetry is installed in your\nsystem. Then run\n\n```shell\n$ poetry install\n```\n\nto install all dependencies. With this command, Poetry also installs the package in editable mode.\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "A Python wrapper for DOIP.",
    "version": "0.4.0",
    "project_urls": null,
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "21c1001d571cba16b5563feacaf743e695d648e077234430f5ecd6ca02561938",
                "md5": "cb2470e6b5b828326805521bf3976406",
                "sha256": "282b0e222b918705f559ca23f2fb5f24d166c89ebce27ebe0414fe9d0ae4ba45"
            },
            "downloads": -1,
            "filename": "doipy-0.4.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "cb2470e6b5b828326805521bf3976406",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.11",
            "size": 15985,
            "upload_time": "2024-08-03T12:03:21",
            "upload_time_iso_8601": "2024-08-03T12:03:21.232755Z",
            "url": "https://files.pythonhosted.org/packages/21/c1/001d571cba16b5563feacaf743e695d648e077234430f5ecd6ca02561938/doipy-0.4.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "713ddcdd49d5abf0600e334af3d6a512f581f74c9e47a3d95cbcb8da15e36f94",
                "md5": "86e916f30e0ee57b815be234fbdfd51f",
                "sha256": "6ecfeb2f3c6777bb2541c67a6ba433f0051a18eb2ea6cde8c6819c19095340a5"
            },
            "downloads": -1,
            "filename": "doipy-0.4.0.tar.gz",
            "has_sig": false,
            "md5_digest": "86e916f30e0ee57b815be234fbdfd51f",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.11",
            "size": 25247,
            "upload_time": "2024-08-03T12:03:23",
            "upload_time_iso_8601": "2024-08-03T12:03:23.312380Z",
            "url": "https://files.pythonhosted.org/packages/71/3d/dcdd49d5abf0600e334af3d6a512f581f74c9e47a3d95cbcb8da15e36f94/doipy-0.4.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-08-03 12:03:23",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "doipy"
}
        
Elapsed time: 0.37489s