ngsildclient


Namengsildclient JSON
Version 0.5.2 PyPI version JSON
download
home_pagehttps://github.com/Orange-OpenSource/python-ngsild-client
SummaryA Python library that helps building NGSI-LD entities and interacting with a NGSI-LD Context Broker
upload_time2022-12-01 16:02:43
maintainer
docs_urlNone
authorfbattello
requires_python>=3.9,<4.0
licenseApache-2.0
keywords fiware ngsi ngsi-ld ngsi agent
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # The ngsildclient library

[![NGSI-LD badge](https://img.shields.io/badge/NGSI-LD-red.svg)](https://www.etsi.org/deliver/etsi_gs/CIM/001_099/009/01.02.01_60/gs_CIM009v010201p.pdf)
[![SOF support badge](https://nexus.lab.fiware.org/repository/raw/public/badges/stackoverflow/fiware.svg)](http://stackoverflow.com/questions/tagged/fiware)
<br>
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Read the Docs](https://img.shields.io/readthedocs/ngsildclient)](https://ngsildclient.readthedocs.io/en/latest/index.html)
<br>
[![deploy status](https://github.com/Orange-OpenSource/python-ngsild-client/workflows/CI/badge.svg)](https://github.com/Orange-OpenSource/python-ngsild-client/actions)
[![PyPI](https://img.shields.io/pypi/v/ngsildclient.svg)](https://pypi.org/project/ngsildclient/)
[![Python version](https://img.shields.io/pypi/pyversions/ngsildclient)](https://pypi.org/project/ngsildclient/)


## Overview

 **ngsildclient** is a Python library dedicated to NGSI-LD.
 
 It combines :

 - a toolbox to create and modify NGSI-LD entities effortlessly
 - a NGSI-LD API client to interact with a Context Broker

## Features

### Build NGSI-LD entities

ngsildclient aims at :

- programmatically generate NGSI-LD entities
- load entities from JSON-LD payloads

Four primitives are provided `prop()`, `gprop()`, `tprop()`, `rel()` to build respectively a Property, GeoProperty, TemporalProperty and Relationship.

An Entity is backed by a Python dictionary that stores the JSON-LD payload.
The library operates the mapping between the Entity's attributes and their JSON-LD counterpart, allowing to easily manipulate NGSI-LD value and metadata directly in Python.

### Features list

- primitives to build properties and relationships (chainable)
- benefit from uri naming convention, omit scheme and entity's type, e.g. `parking = Entity("OffStreetParking", "Downtown1")`
- support dot-notation facility, e.g. `reliability = parking["availableSpotNumber.reliability"]`
- easily manipulate a property's value, e.g. `reliability.value = 0.8`
- easily manipulate a property's metadata, e.g. `reliability.datasetid = "dataset1"`
- support nesting
- support multi-attribute
- load/save to file
- load from HTTP
- load well-known sample entities, e.g.  `parking = Entity.load(SmartDataModels.SmartCities.Parking.OffStreetParking)`
- provide helpers to ease building some structures, e.g. PostalAddress
- pretty-print entity and properties

### Interact with the Context Broker

Two clients are provided, `Client` and `AsyncClient` respectively for synchronous and asynchronous modes.

Prefer the synchronous one when working in interactive mode, for example to explore and visualize context data in a Jupyter notebook.
Prefer the async one if you're looking for performance, for example to develop a real-time NGSI-LD Agent with a high data-acquisition frequency rate.

### Features list

 - synchronous and asynchronous clients
 - support batch operations
 - support pagination : transparently handle pagination (sending as many requests as needed under the hood)
 - support auto-batch : transparently divide into many batch requests if needed
 - support queries and alternate (POST) queries
 - support temporal queries
 - support pandas dataframe as a temporal query result
 - support subscriptions
 - find subscription conflicts
 - SubscriptionBuilder to help build subscriptions
 - auto-detect broker vendor and version
 - support follow relationships (chainable), e.g. `camera = parking.follow("availableSpotNumber.providedBy")`

## Getting started

### Create our first parking Entity

The following code snippet builds the `OffstreetParking` sample entity from the ETSI documentation.

```python
from datetime import datetime
from ngsildclient import Entity

PARKING_CONTEXT = "https://raw.githubusercontent.com/smart-data-models/dataModel.Parking/master/context.jsonld"

e = Entity("OffStreetParking", "Downtown1")
e.ctx.append(PARKING_CONTEXT)
e.prop("name", "Downtown One")
e.prop("availableSpotNumber", 121, observedat=datetime(2022, 10, 25, 8)).anchor()
e.prop("reliability", 0.7).rel("providedBy", "Camera:C1").unanchor()
e.prop("totalSpotNumber", 200).loc(41.2, -8.5)
```

Let's print the JSON-LD payload.

```python
e.pprint()
```

The result is available [here](https://github.com/Orange-OpenSource/python-ngsild-client/blob/master/parking_sample.jsonld).<br>


### Persist our parking in the Context Broker

The following example assumes that an Orion-LD context broker is running on localhost.<br>
A docker-compose config [file](https://raw.githubusercontent.com/Orange-OpenSource/python-ngsild-client/master/brokers/orionld/docker-compose-troe.yml) file is provided for that purpose.

```python
from ngsildclient import Client

client = Client(port=8026, port_temporal=8027)
client.create(e)
```

### Increase our parking occupancy as the day goes on

Each hour ten more parkings spots are occupied, until 8 p.m.

```python
from datetime import timedelta

prop = e["availableSpotNumber"]
for _ in range(12):
    prop.observedat += timedelta(hours=1)
    prop.value -= 10
    client.update(e)
```

### Retrieve our parking

Get back our parking from the broker and display its `availableSpotNumber` property.<br>

```python
parking = client.get("OffStreetParking:Downtown1", ctx=PARKING_CONTEXT)
parking["availableSpotNumber"].pprint()
```

Only one available parking spot remains at 8 p.m.

```json
{
    "type": "Property",
    "value": 1,
    "observedAt": "2022-10-25T20:00:00Z",
    "reliability": {
        "type": "Property",
        "value": 0.7
    },
    "providedBy": {
        "type": "Relationship",
        "object": "urn:ngsi-ld:Camera:C1"
    }
}
```

### Request the Temporal Representation of our parking

For convenience we retrieve it as a pandas dataframe.

*If you don't have pandas installed, just omit the `as_dataframe` argument and get JSON instead.*

```python
df = client.temporal.get(e, ctx=PARKING_CONTEXT, as_dataframe=True)
```

Let's display the three last rows.

```python
df.tail(3)
```

|    | OffStreetParking   | observed                  |   availableSpotNumber |
|---:|:-------------------|:--------------------------|----------------------:|
| 10 | Downtown1          | 2022-10-25 18:00:00+00:00 |                    21 |
| 11 | Downtown1          | 2022-10-25 19:00:00+00:00 |                    11 |
| 12 | Downtown1          | 2022-10-25 20:00:00+00:00 |                     1 |

### Let's throw in a more realistic parking management system

Let us move from our first example to the more realistic parking example provided by the Smart Data Models Program.

```python
from ngsildclient import SmartDataModels

parking = Entity.load(SmartDataModels.SmartCities.Parking.OffStreetParking)
```

Once loaded we can manipulate our new parking the same way we've done until now.<br>
Let's see how it is occupied.

```python
n_total = parking["totalSpotNumber"].value
n_occupied = parking["occupiedSpotNumber"].value
n_avail= parking["availableSpotNumber"].value
print(n_total, n_occupied, n_avail)
```

This parking has 414 parking slots. 282 are occupied. 132 are available.<br>
In order to complete our parking system we would like to add 414 spots to our datamodel.<br>
Let's create a reference parking spot to be used as a template.

```python
spot = Entity("ParkingSpot", "OffStreetParking:porto-ParkingLot-23889:000")
spot.prop("status", "free")
spot.rel("refParkingSite", parking)
```

Let's clone this spot 414 times, assign a disctinct id to each one and occupy the 282 first spots.<br>
This is a simplistic strategy but enough to keep the parking system consistent.

```python
spots = spot * n_total
for i, spot in enumerate(spots):
    spot.id = f"{spot.id[:-3]}{i+1:03}"
    if i < n_occupied:
        spot["status"].value = "occupied"
```

We now establish the relationship between the parking and its spots by adding a new attribute to the parking.<br>
Having a mutual relationship is not necessarily needed. It depends on how we want to navigate in our datamodel. <br>
Let's do it for the sake of example.

```python
from ngsildclient import MultAttrValue

mrel = MultAttrValue()
for spot in spots:
    mrel.add(spot, datasetid=f"Dataset:{spot.id[-26:]}")
parking.rel("refParkingSpot", mrel)
```

To sum up we have obtained 415 entities : 1 parking and 414 spots.<br>
Make a single list of these parts and save it into a file.

```python
datamodel = sum(([parking], spots), [])  # flatten lists
Entity.save_batch(datamodel, "parking_system.jsonld")
```
The result is available [here](https://github.com/Orange-OpenSource/python-ngsild-client/blob/master/parking_system.jsonld).<br>
Time now to populate our parking system in the broker.

```python
client.upsert(datamodel)
```

Check everything is fine by asking the broker for the number of occupied spots.<br>
Eventually close the client.

```python
client.count("ParkingSpot", q='refParkingSite=="urn:ngsi-ld:OffStreetParking:porto-ParkingLot-23889";status=="occupied"')  # 282
client.close()
```

### Let's go further

1. Develop a NGSI-LD Agent

    - Collect incoming data from parking IoT *(ground sensors, cameras)* and the parking system API
    - Clean data, process data and convert to NGSI-LD entities
    - Create and update entities into the NGSI-LD broker *in real-time*

2. Subscribe to events

    - Create a subscription to be informed when parking occupation exceeds 90%
    - The software that listens to these highly-occupied parking entities can also be a NGSI-LD Agent

    <br>Example : programmatically subscribe to events

    ```python
    from ngsildclient import SubscriptionBuilder

    subscr = SubscriptionBuilder("https://parkingsystem.example.com:8000/subscription/high-occupancy")
        .description("Notify me of high occupancy on parking porto-23889")
        .select_type("OffStreetParking")
        .watch(["occupancy"])
        .query('occupancy>0.9;controlledAsset=="urn:ngsi-ld:OffStreetParking:porto-ParkingLot-23889"')
        .build()
    client.subscriptions.create(subscr)
    ```

## Where to get it

The source code is currently hosted on GitHub at :
https://github.com/Orange-OpenSource/python-ngsild-client

Binary installer for the latest released version is available at the [Python
package index](https://pypi.org/project/ngsildclient).

## Installation

**ngsildclient** requires Python 3.9+.

```sh
pip install ngsildclient
```

## Documentation

User guide is available on [Read the Docs](https://ngsildclient.readthedocs.io/en/latest/index.html).

Refer to the [Cookbook](https://ngsildclient.readthedocs.io/en/latest/cookbook.html) chapter that provides many HOWTOs to :

- develop various NGSI-LD Agents collecting data from heterogeneous datasources
- forge NGSI-LD sample entities from the Smart Data Models initiative

## License

[Apache 2.0](LICENSE)

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/Orange-OpenSource/python-ngsild-client",
    "name": "ngsildclient",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.9,<4.0",
    "maintainer_email": "",
    "keywords": "Fiware,NGSI,NGSI-LD,NGSI Agent",
    "author": "fbattello",
    "author_email": "fabien.battello@orange.com",
    "download_url": "https://files.pythonhosted.org/packages/26/7d/576cacd953fb21709fc850f3ad589c92ffedc342f27cf09292d2659838cc/ngsildclient-0.5.2.tar.gz",
    "platform": null,
    "description": "# The ngsildclient library\n\n[![NGSI-LD badge](https://img.shields.io/badge/NGSI-LD-red.svg)](https://www.etsi.org/deliver/etsi_gs/CIM/001_099/009/01.02.01_60/gs_CIM009v010201p.pdf)\n[![SOF support badge](https://nexus.lab.fiware.org/repository/raw/public/badges/stackoverflow/fiware.svg)](http://stackoverflow.com/questions/tagged/fiware)\n<br>\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Read the Docs](https://img.shields.io/readthedocs/ngsildclient)](https://ngsildclient.readthedocs.io/en/latest/index.html)\n<br>\n[![deploy status](https://github.com/Orange-OpenSource/python-ngsild-client/workflows/CI/badge.svg)](https://github.com/Orange-OpenSource/python-ngsild-client/actions)\n[![PyPI](https://img.shields.io/pypi/v/ngsildclient.svg)](https://pypi.org/project/ngsildclient/)\n[![Python version](https://img.shields.io/pypi/pyversions/ngsildclient)](https://pypi.org/project/ngsildclient/)\n\n\n## Overview\n\n **ngsildclient** is a Python library dedicated to NGSI-LD.\n \n It combines :\n\n - a toolbox to create and modify NGSI-LD entities effortlessly\n - a NGSI-LD API client to interact with a Context Broker\n\n## Features\n\n### Build NGSI-LD entities\n\nngsildclient aims at :\n\n- programmatically generate NGSI-LD entities\n- load entities from JSON-LD payloads\n\nFour primitives are provided `prop()`, `gprop()`, `tprop()`, `rel()` to build respectively a Property, GeoProperty, TemporalProperty and Relationship.\n\nAn Entity is backed by a Python dictionary that stores the JSON-LD payload.\nThe library operates the mapping between the Entity's attributes and their JSON-LD counterpart, allowing to easily manipulate NGSI-LD value and metadata directly in Python.\n\n### Features list\n\n- primitives to build properties and relationships (chainable)\n- benefit from uri naming convention, omit scheme and entity's type, e.g. `parking = Entity(\"OffStreetParking\", \"Downtown1\")`\n- support dot-notation facility, e.g. `reliability = parking[\"availableSpotNumber.reliability\"]`\n- easily manipulate a property's value, e.g. `reliability.value = 0.8`\n- easily manipulate a property's metadata, e.g. `reliability.datasetid = \"dataset1\"`\n- support nesting\n- support multi-attribute\n- load/save to file\n- load from HTTP\n- load well-known sample entities, e.g.  `parking = Entity.load(SmartDataModels.SmartCities.Parking.OffStreetParking)`\n- provide helpers to ease building some structures, e.g. PostalAddress\n- pretty-print entity and properties\n\n### Interact with the Context Broker\n\nTwo clients are provided, `Client` and `AsyncClient` respectively for synchronous and asynchronous modes.\n\nPrefer the synchronous one when working in interactive mode, for example to explore and visualize context data in a Jupyter notebook.\nPrefer the async one if you're looking for performance, for example to develop a real-time NGSI-LD Agent with a high data-acquisition frequency rate.\n\n### Features list\n\n - synchronous and asynchronous clients\n - support batch operations\n - support pagination : transparently handle pagination (sending as many requests as needed under the hood)\n - support auto-batch : transparently divide into many batch requests if needed\n - support queries and alternate (POST) queries\n - support temporal queries\n - support pandas dataframe as a temporal query result\n - support subscriptions\n - find subscription conflicts\n - SubscriptionBuilder to help build subscriptions\n - auto-detect broker vendor and version\n - support follow relationships (chainable), e.g. `camera = parking.follow(\"availableSpotNumber.providedBy\")`\n\n## Getting started\n\n### Create our first parking Entity\n\nThe following code snippet builds the `OffstreetParking` sample entity from the ETSI documentation.\n\n```python\nfrom datetime import datetime\nfrom ngsildclient import Entity\n\nPARKING_CONTEXT = \"https://raw.githubusercontent.com/smart-data-models/dataModel.Parking/master/context.jsonld\"\n\ne = Entity(\"OffStreetParking\", \"Downtown1\")\ne.ctx.append(PARKING_CONTEXT)\ne.prop(\"name\", \"Downtown One\")\ne.prop(\"availableSpotNumber\", 121, observedat=datetime(2022, 10, 25, 8)).anchor()\ne.prop(\"reliability\", 0.7).rel(\"providedBy\", \"Camera:C1\").unanchor()\ne.prop(\"totalSpotNumber\", 200).loc(41.2, -8.5)\n```\n\nLet's print the JSON-LD payload.\n\n```python\ne.pprint()\n```\n\nThe result is available [here](https://github.com/Orange-OpenSource/python-ngsild-client/blob/master/parking_sample.jsonld).<br>\n\n\n### Persist our parking in the Context Broker\n\nThe following example assumes that an Orion-LD context broker is running on localhost.<br>\nA docker-compose config [file](https://raw.githubusercontent.com/Orange-OpenSource/python-ngsild-client/master/brokers/orionld/docker-compose-troe.yml) file is provided for that purpose.\n\n```python\nfrom ngsildclient import Client\n\nclient = Client(port=8026, port_temporal=8027)\nclient.create(e)\n```\n\n### Increase our parking occupancy as the day goes on\n\nEach hour ten more parkings spots are occupied, until 8 p.m.\n\n```python\nfrom datetime import timedelta\n\nprop = e[\"availableSpotNumber\"]\nfor _ in range(12):\n    prop.observedat += timedelta(hours=1)\n    prop.value -= 10\n    client.update(e)\n```\n\n### Retrieve our parking\n\nGet back our parking from the broker and display its `availableSpotNumber` property.<br>\n\n```python\nparking = client.get(\"OffStreetParking:Downtown1\", ctx=PARKING_CONTEXT)\nparking[\"availableSpotNumber\"].pprint()\n```\n\nOnly one available parking spot remains at 8 p.m.\n\n```json\n{\n    \"type\": \"Property\",\n    \"value\": 1,\n    \"observedAt\": \"2022-10-25T20:00:00Z\",\n    \"reliability\": {\n        \"type\": \"Property\",\n        \"value\": 0.7\n    },\n    \"providedBy\": {\n        \"type\": \"Relationship\",\n        \"object\": \"urn:ngsi-ld:Camera:C1\"\n    }\n}\n```\n\n### Request the Temporal Representation of our parking\n\nFor convenience we retrieve it as a pandas dataframe.\n\n*If you don't have pandas installed, just omit the `as_dataframe` argument and get JSON instead.*\n\n```python\ndf = client.temporal.get(e, ctx=PARKING_CONTEXT, as_dataframe=True)\n```\n\nLet's display the three last rows.\n\n```python\ndf.tail(3)\n```\n\n|    | OffStreetParking   | observed                  |   availableSpotNumber |\n|---:|:-------------------|:--------------------------|----------------------:|\n| 10 | Downtown1          | 2022-10-25 18:00:00+00:00 |                    21 |\n| 11 | Downtown1          | 2022-10-25 19:00:00+00:00 |                    11 |\n| 12 | Downtown1          | 2022-10-25 20:00:00+00:00 |                     1 |\n\n### Let's throw in a more realistic parking management system\n\nLet us move from our first example to the more realistic parking example provided by the Smart Data Models Program.\n\n```python\nfrom ngsildclient import SmartDataModels\n\nparking = Entity.load(SmartDataModels.SmartCities.Parking.OffStreetParking)\n```\n\nOnce loaded we can manipulate our new parking the same way we've done until now.<br>\nLet's see how it is occupied.\n\n```python\nn_total = parking[\"totalSpotNumber\"].value\nn_occupied = parking[\"occupiedSpotNumber\"].value\nn_avail= parking[\"availableSpotNumber\"].value\nprint(n_total, n_occupied, n_avail)\n```\n\nThis parking has 414 parking slots. 282 are occupied. 132 are available.<br>\nIn order to complete our parking system we would like to add 414 spots to our datamodel.<br>\nLet's create a reference parking spot to be used as a template.\n\n```python\nspot = Entity(\"ParkingSpot\", \"OffStreetParking:porto-ParkingLot-23889:000\")\nspot.prop(\"status\", \"free\")\nspot.rel(\"refParkingSite\", parking)\n```\n\nLet's clone this spot 414 times, assign a disctinct id to each one and occupy the 282 first spots.<br>\nThis is a simplistic strategy but enough to keep the parking system consistent.\n\n```python\nspots = spot * n_total\nfor i, spot in enumerate(spots):\n    spot.id = f\"{spot.id[:-3]}{i+1:03}\"\n    if i < n_occupied:\n        spot[\"status\"].value = \"occupied\"\n```\n\nWe now establish the relationship between the parking and its spots by adding a new attribute to the parking.<br>\nHaving a mutual relationship is not necessarily needed. It depends on how we want to navigate in our datamodel. <br>\nLet's do it for the sake of example.\n\n```python\nfrom ngsildclient import MultAttrValue\n\nmrel = MultAttrValue()\nfor spot in spots:\n    mrel.add(spot, datasetid=f\"Dataset:{spot.id[-26:]}\")\nparking.rel(\"refParkingSpot\", mrel)\n```\n\nTo sum up we have obtained 415 entities : 1 parking and 414 spots.<br>\nMake a single list of these parts and save it into a file.\n\n```python\ndatamodel = sum(([parking], spots), [])  # flatten lists\nEntity.save_batch(datamodel, \"parking_system.jsonld\")\n```\nThe result is available [here](https://github.com/Orange-OpenSource/python-ngsild-client/blob/master/parking_system.jsonld).<br>\nTime now to populate our parking system in the broker.\n\n```python\nclient.upsert(datamodel)\n```\n\nCheck everything is fine by asking the broker for the number of occupied spots.<br>\nEventually close the client.\n\n```python\nclient.count(\"ParkingSpot\", q='refParkingSite==\"urn:ngsi-ld:OffStreetParking:porto-ParkingLot-23889\";status==\"occupied\"')  # 282\nclient.close()\n```\n\n### Let's go further\n\n1. Develop a NGSI-LD Agent\n\n    - Collect incoming data from parking IoT *(ground sensors, cameras)* and the parking system API\n    - Clean data, process data and convert to NGSI-LD entities\n    - Create and update entities into the NGSI-LD broker *in real-time*\n\n2. Subscribe to events\n\n    - Create a subscription to be informed when parking occupation exceeds 90%\n    - The software that listens to these highly-occupied parking entities can also be a NGSI-LD Agent\n\n    <br>Example : programmatically subscribe to events\n\n    ```python\n    from ngsildclient import SubscriptionBuilder\n\n    subscr = SubscriptionBuilder(\"https://parkingsystem.example.com:8000/subscription/high-occupancy\")\n        .description(\"Notify me of high occupancy on parking porto-23889\")\n        .select_type(\"OffStreetParking\")\n        .watch([\"occupancy\"])\n        .query('occupancy>0.9;controlledAsset==\"urn:ngsi-ld:OffStreetParking:porto-ParkingLot-23889\"')\n        .build()\n    client.subscriptions.create(subscr)\n    ```\n\n## Where to get it\n\nThe source code is currently hosted on GitHub at :\nhttps://github.com/Orange-OpenSource/python-ngsild-client\n\nBinary installer for the latest released version is available at the [Python\npackage index](https://pypi.org/project/ngsildclient).\n\n## Installation\n\n**ngsildclient** requires Python 3.9+.\n\n```sh\npip install ngsildclient\n```\n\n## Documentation\n\nUser guide is available on [Read the Docs](https://ngsildclient.readthedocs.io/en/latest/index.html).\n\nRefer to the [Cookbook](https://ngsildclient.readthedocs.io/en/latest/cookbook.html) chapter that provides many HOWTOs to :\n\n- develop various NGSI-LD Agents collecting data from heterogeneous datasources\n- forge NGSI-LD sample entities from the Smart Data Models initiative\n\n## License\n\n[Apache 2.0](LICENSE)\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "A Python library that helps building NGSI-LD entities and interacting with a NGSI-LD Context Broker",
    "version": "0.5.2",
    "split_keywords": [
        "fiware",
        "ngsi",
        "ngsi-ld",
        "ngsi agent"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "md5": "f472671cc3bc175ed204b5b98b8fdc76",
                "sha256": "4b2535cef0ad5873545c8714e643ec049734e85bdb44ce2dd43be8f0a0d1b924"
            },
            "downloads": -1,
            "filename": "ngsildclient-0.5.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "f472671cc3bc175ed204b5b98b8fdc76",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9,<4.0",
            "size": 83662,
            "upload_time": "2022-12-01T16:02:41",
            "upload_time_iso_8601": "2022-12-01T16:02:41.445562Z",
            "url": "https://files.pythonhosted.org/packages/4f/54/b364d961bca8443a7a0c28b84a788703a8ea137454c21704f559d5d061f7/ngsildclient-0.5.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "md5": "924af9ac84c7941cfd52e49cede92b10",
                "sha256": "ab0135b4bdb3aa4f2f654bc1cb1e772d027670d0accc07ac098abc04e79c7bac"
            },
            "downloads": -1,
            "filename": "ngsildclient-0.5.2.tar.gz",
            "has_sig": false,
            "md5_digest": "924af9ac84c7941cfd52e49cede92b10",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9,<4.0",
            "size": 59938,
            "upload_time": "2022-12-01T16:02:43",
            "upload_time_iso_8601": "2022-12-01T16:02:43.557561Z",
            "url": "https://files.pythonhosted.org/packages/26/7d/576cacd953fb21709fc850f3ad589c92ffedc342f27cf09292d2659838cc/ngsildclient-0.5.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2022-12-01 16:02:43",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "Orange-OpenSource",
    "github_project": "python-ngsild-client",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "ngsildclient"
}
        
Elapsed time: 0.03015s