uai-openlabel


Nameuai-openlabel JSON
Version 0.3.7 PyPI version JSON
download
home_pagehttps://github.com/understand-ai/uai_openlabel
SummaryA library to produce and parse JSONs in the OpenLABEL format.
upload_time2024-04-22 10:51:10
maintainerNone
docs_urlNone
authorunderstand.ai
requires_python<3.12,>=3.9
licenseMIT
keywords asam openlabel
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # uai_openlabel

This repository is an implementation of the [ASAM OpenLABEL](https://www.asam.net/standards/detail/openlabel/) v1.0.0 standard. 
OpenLABEL defines a JSON schema for saving annotations in the context of data labeling. 

## How to use

This library can be installed via pip using `pip install uai_openlabel` or with poetry using `poetry add uai_openlabel`. 

The entry point to the uai_openlabel data structure is `OpenLabel`, importable via `from uai_openlabel import OpenLabel`. 
To export an example OpenLABEL file and save it to disk, do

```python
import json
from pathlib import Path
from uai_openlabel import OpenLabel

example = OpenLabel.example()
with Path("where/to/save/example.json").open("w") as f:
    json.dump(example.to_dict(exclude_none=True), f)
```

Use `to_dict(exlude_none=True)` to remove any none-valued fields from the dataclass.
This makes the export much more compact and is also the way the official ASAM examples are serialized.


# Development

## Poetry
This package uses Poetry, a tool for dependency management and packaging.
Please install it via the official installer from [here](https://python-poetry.org/docs/).

## Working with this repository
This repository employs several tools to ensure a constant and good code quality.

### Black
[Black](https://black.readthedocs.io/en/stable/index.html) is a code formatter that we use to assure consistent code style across our projects.
Use it in-between, or after your code changes, via `poetry run black .` in the root directory of this repository.

### MyPy
[Mypy](https://mypy.readthedocs.io/en/stable/) is a static type checker for Python.
Mypy can be run with `poetry run mypy .` in the root directory of this repository.

### Ruff
[Ruff](https://docs.astral.sh/ruff/) is a Python linter and code formatter. 
It can be run with `poetry run ruff .` in the root directory of this repository. 


## Things left to be implemented

Not implemented because they aren't needed yet.

* Section `7.10.2 Semantic segmentation: image`
* Section `7.10.4 Mesh`
* Section `7.10.5 Mat and binary`
* Section `7.10.6 Point2d and Point3d`

Please choose a test-driven-development: Find an example JSON in the OpenLABEL spec and create a de- & re-serialization
test for it. Then implement the features required to pass the test.


## Debugging apischema

Debugging problems in (de)serialization with apischema is tricky because apischema is in a compiled state when
installing it from PyPI.
To have a better debugging experience, it is advisable to clone the [apischema repository](https://github.com/wyfo/apischema)
locally alongside this repository.
Then, set the apischema dependency as `apischema = { path="../apischema", develop=true }` in `pyproject.toml`.
Follow up with `poetry lock; poetry install --sync`.
Now you can more easily get the keys and values where apischema is throwing exceptions. 


## MyPy specialties in this library

### Mapping instead of dict

Throughout this repository, you'll find the usage of `Mapping` type decorators instead of `dict`. 
The type `Mapping` is _covariant_, while `dict` is _invariant_ 
(read about it [here](https://mypy.readthedocs.io/en/stable/generics.html#variance-of-generic-types)).  
This is important if you want to extend the base OpenLABEL spec with a customer-specific spec that overrides fields 
and narrows down the type, like such:   

```python
from dataclasses import dataclass, field
from typing import Mapping


class LowerCaseStr(str):
    def __init__(self, val: str):
        if not val.islower():
            raise ValueError(f"{val} isn't lower-case")


@dataclass
class Action:
    name: str = field()


@dataclass
class CustomAction(Action):
    name: LowerCaseStr = field()


@dataclass
class OpenLabel:
    # Setting the type to dict will cause a MyPy error
    actions: Mapping[str, Action] = field()


@dataclass
class CustomOpenLabel(OpenLabel):
    actions: dict[str, CustomAction] = field()
```

### Why all these `_no_default` default values? 

When creating dataclasses that inherit from each other, an issue that can occur is that a subclass has a field without 
a default, while the parent class contains fields with defaults. 
When this occurs, you'll see `TypeErrors` when trying to execute it, and PyCharm will complain too. 

To fix this, there are several possibilities, the best of them are discussed [here](https://stackoverflow.com/a/53085935/5568461). 
Other possibilities involve using metaclass magic and a deep forest of complicated code that would make the code harder to 
understand. 

The cleanest solution that a) doesn't double the class count, b) is understood by PyCharm, and c) sticks with plain dataclasses, 
is the following: 
On fields that may not be left empty according to the official OpenLABEL spec, we set a `default_factory` that raises an exception.

In order for apischema to work, we have to add the `apischema.metadata.required` in the field's metadata, 
otherwise apischema will call the default factory before checking if there even is a value to be deserialized. 


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/understand-ai/uai_openlabel",
    "name": "uai-openlabel",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<3.12,>=3.9",
    "maintainer_email": null,
    "keywords": "ASAM OpenLABEL",
    "author": "understand.ai",
    "author_email": "postmaster@understand.ai",
    "download_url": "https://files.pythonhosted.org/packages/de/07/fa602479ffcdaf9c07e3d07517e63d3629cd87a038c72279a9521196dae7/uai_openlabel-0.3.7.tar.gz",
    "platform": null,
    "description": "# uai_openlabel\n\nThis repository is an implementation of the [ASAM OpenLABEL](https://www.asam.net/standards/detail/openlabel/) v1.0.0 standard. \nOpenLABEL defines a JSON schema for saving annotations in the context of data labeling. \n\n## How to use\n\nThis library can be installed via pip using `pip install uai_openlabel` or with poetry using `poetry add uai_openlabel`. \n\nThe entry point to the uai_openlabel data structure is `OpenLabel`, importable via `from uai_openlabel import OpenLabel`. \nTo export an example OpenLABEL file and save it to disk, do\n\n```python\nimport json\nfrom pathlib import Path\nfrom uai_openlabel import OpenLabel\n\nexample = OpenLabel.example()\nwith Path(\"where/to/save/example.json\").open(\"w\") as f:\n    json.dump(example.to_dict(exclude_none=True), f)\n```\n\nUse `to_dict(exlude_none=True)` to remove any none-valued fields from the dataclass.\nThis makes the export much more compact and is also the way the official ASAM examples are serialized.\n\n\n# Development\n\n## Poetry\nThis package uses Poetry, a tool for dependency management and packaging.\nPlease install it via the official installer from [here](https://python-poetry.org/docs/).\n\n## Working with this repository\nThis repository employs several tools to ensure a constant and good code quality.\n\n### Black\n[Black](https://black.readthedocs.io/en/stable/index.html) is a code formatter that we use to assure consistent code style across our projects.\nUse it in-between, or after your code changes, via `poetry run black .` in the root directory of this repository.\n\n### MyPy\n[Mypy](https://mypy.readthedocs.io/en/stable/) is a static type checker for Python.\nMypy can be run with `poetry run mypy .` in the root directory of this repository.\n\n### Ruff\n[Ruff](https://docs.astral.sh/ruff/) is a Python linter and code formatter. \nIt can be run with `poetry run ruff .` in the root directory of this repository. \n\n\n## Things left to be implemented\n\nNot implemented because they aren't needed yet.\n\n* Section `7.10.2 Semantic segmentation: image`\n* Section `7.10.4 Mesh`\n* Section `7.10.5 Mat and binary`\n* Section `7.10.6 Point2d and Point3d`\n\nPlease choose a test-driven-development: Find an example JSON in the OpenLABEL spec and create a de- & re-serialization\ntest for it. Then implement the features required to pass the test.\n\n\n## Debugging apischema\n\nDebugging problems in (de)serialization with apischema is tricky because apischema is in a compiled state when\ninstalling it from PyPI.\nTo have a better debugging experience, it is advisable to clone the [apischema repository](https://github.com/wyfo/apischema)\nlocally alongside this repository.\nThen, set the apischema dependency as `apischema = { path=\"../apischema\", develop=true }` in `pyproject.toml`.\nFollow up with `poetry lock; poetry install --sync`.\nNow you can more easily get the keys and values where apischema is throwing exceptions. \n\n\n## MyPy specialties in this library\n\n### Mapping instead of dict\n\nThroughout this repository, you'll find the usage of `Mapping` type decorators instead of `dict`. \nThe type `Mapping` is _covariant_, while `dict` is _invariant_ \n(read about it [here](https://mypy.readthedocs.io/en/stable/generics.html#variance-of-generic-types)).  \nThis is important if you want to extend the base OpenLABEL spec with a customer-specific spec that overrides fields \nand narrows down the type, like such:   \n\n```python\nfrom dataclasses import dataclass, field\nfrom typing import Mapping\n\n\nclass LowerCaseStr(str):\n    def __init__(self, val: str):\n        if not val.islower():\n            raise ValueError(f\"{val} isn't lower-case\")\n\n\n@dataclass\nclass Action:\n    name: str = field()\n\n\n@dataclass\nclass CustomAction(Action):\n    name: LowerCaseStr = field()\n\n\n@dataclass\nclass OpenLabel:\n    # Setting the type to dict will cause a MyPy error\n    actions: Mapping[str, Action] = field()\n\n\n@dataclass\nclass CustomOpenLabel(OpenLabel):\n    actions: dict[str, CustomAction] = field()\n```\n\n### Why all these `_no_default` default values? \n\nWhen creating dataclasses that inherit from each other, an issue that can occur is that a subclass has a field without \na default, while the parent class contains fields with defaults. \nWhen this occurs, you'll see `TypeErrors` when trying to execute it, and PyCharm will complain too. \n\nTo fix this, there are several possibilities, the best of them are discussed [here](https://stackoverflow.com/a/53085935/5568461). \nOther possibilities involve using metaclass magic and a deep forest of complicated code that would make the code harder to \nunderstand. \n\nThe cleanest solution that a) doesn't double the class count, b) is understood by PyCharm, and c) sticks with plain dataclasses, \nis the following: \nOn fields that may not be left empty according to the official OpenLABEL spec, we set a `default_factory` that raises an exception.\n\nIn order for apischema to work, we have to add the `apischema.metadata.required` in the field's metadata, \notherwise apischema will call the default factory before checking if there even is a value to be deserialized. \n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A library to produce and parse JSONs in the OpenLABEL format.",
    "version": "0.3.7",
    "project_urls": {
        "Homepage": "https://github.com/understand-ai/uai_openlabel",
        "Repository": "https://github.com/understand-ai/uai_openlabel"
    },
    "split_keywords": [
        "asam",
        "openlabel"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d47ede7c9be046f9de87fa0e1b4ff501eb4ce6e7f94dbc39704b3458a883cf93",
                "md5": "ec05444c913c218cf1319d02079cc7ae",
                "sha256": "fd3decc49f634974fcd5ee07594702d73bd439d20a9495c53aec9c661f5c0d56"
            },
            "downloads": -1,
            "filename": "uai_openlabel-0.3.7-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "ec05444c913c218cf1319d02079cc7ae",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<3.12,>=3.9",
            "size": 57585,
            "upload_time": "2024-04-22T10:51:08",
            "upload_time_iso_8601": "2024-04-22T10:51:08.709252Z",
            "url": "https://files.pythonhosted.org/packages/d4/7e/de7c9be046f9de87fa0e1b4ff501eb4ce6e7f94dbc39704b3458a883cf93/uai_openlabel-0.3.7-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "de07fa602479ffcdaf9c07e3d07517e63d3629cd87a038c72279a9521196dae7",
                "md5": "5cdd569ce44ed703e14f02f685dc2fb5",
                "sha256": "c8ccd851f2f443d3f66ae4ccc30e7375c940c73025aeb4b0a3f28b8bb2d24c56"
            },
            "downloads": -1,
            "filename": "uai_openlabel-0.3.7.tar.gz",
            "has_sig": false,
            "md5_digest": "5cdd569ce44ed703e14f02f685dc2fb5",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<3.12,>=3.9",
            "size": 30769,
            "upload_time": "2024-04-22T10:51:10",
            "upload_time_iso_8601": "2024-04-22T10:51:10.425549Z",
            "url": "https://files.pythonhosted.org/packages/de/07/fa602479ffcdaf9c07e3d07517e63d3629cd87a038c72279a9521196dae7/uai_openlabel-0.3.7.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-22 10:51:10",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "understand-ai",
    "github_project": "uai_openlabel",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "uai-openlabel"
}
        
Elapsed time: 0.24310s