Source code for ngsildclient.utils.urn

#!/usr/bin/env python3

# Software Name: ngsildclient
# SPDX-FileCopyrightText: Copyright (c) 2021 Orange
# SPDX-License-Identifier: Apache 2.0
#
# This software is distributed under the Apache 2.0;
# see the NOTICE file for more details.
#
# Author: Fabien BATTELLO <fabien.battello@orange.com> et al.

"""
This module contains helper functions to URI/URN in the NGSI-LD namespace.

References
----------
.. [2] ETSI, 2021. "NGSI-LD namespace" in Context Information Management (CIM); NGSI-LD API
    ETSI GS CIM 009 V1.4.2, Annex A.3, p.183, 2021-04.
"""

import re
import logging

from typing import overload, Optional
from ngsildclient.api.constants import ENDPOINT_ENTITIES

NID_PATTERN = re.compile(r"^[0-9a-zA-Z\-]+$")
"""Regex pattern that matches a valid namespace identifier (`regex.Pattern`).
"""

URN_PATTERN = re.compile(r"^urn:(?P<nid>[0-9a-zA-Z\-]+):(?P<nss>.+)$")
"""Regex pattern that extracts NID and NSS from a full valid urn string(`regex.Pattern`).
"""

ENTITY_TYPE_PATTERN = re.compile(r"^([^:]+):.*")
"""Regex pattern that extracts type from a NGSI-LD NSS following naming convention.(`regex.Pattern`).
"""

logger = logging.getLogger(__name__)


[docs]class UrnError(Exception): """Exception raised when parsing invalid urn/uri.""" pass
[docs]class Urn: """Helper class to handle NGSI-LD urn/uri and allow to work with unprefixed strings.""" DEFAULT_NID = "ngsi-ld" # """Default NGSI-LD namespace value # """ @overload def __init__(self, fqn: str) -> None: """Construct by providing the fully qualified string. Parameters ---------- fqn : str the fully qualified name, starting with `urn:` """ ... @overload def __init__(self, *, nss: str, nid: str = DEFAULT_NID) -> None: """Construct by specifying the URN parts. Parameters ---------- nss : str the namespace specific string nid : str, optional the namespace identifier, by default DEFAULT_NID """ ... def __init__(self, fqn: str = None, *, nss: str = None, nid: str = DEFAULT_NID) -> None: self.scheme = "urn" if nss and nid: self.nss = nss self.nid = nid elif fqn: m = URN_PATTERN.match(fqn) if m is None: raise UrnError(f"Bad urn format : {fqn}") d = m.groupdict() self.nss = d["nss"] self.nid = d["nid"] else: raise ValueError("Wrong arguments") @property def fqn(self) -> str: """Returns the fully-qualified name Returns ------- str the fully qualified name Example ------- >>> from ngsildclient.utils.urn import Urn >>> urn = Urn(nss="AirQualityObserved:RZ:Obsv4567") >>> print(urn.fqn) urn:ngsi-ld:AirQualityObserved:RZ:Obsv4567 """ return f"{self.scheme}:{self.nid}:{self.nss}" def __eq__(self, other) -> bool: if other.__class__ is not self.__class__: return NotImplemented return self.nid == other.nid and self.nss == other.nss def __repr__(self) -> str: return self.fqn
[docs] def infertype(self) -> Optional[str]: """Infer type. Work only when following the naming convention `urn:ngsi-ld:<type>:...` Returns ------- Optional[str] the inferred NGSI LD type if found """ m = ENTITY_TYPE_PATTERN.match(self.nss) return m.group(1) if m else None
[docs] @staticmethod def is_valid_nid(nid: str) -> bool: """Check whether the given nid is a valid one Parameters ---------- nid : str the nid string to be checked Returns ------- bool True if if the nid is valid Example ------- >>> from ngsildclient.utils.urn import Urn >>> print(Urn.is_valid_nid("ngsi-ld")) True >>> print(Urn.is_valid_nid("ngsi+ld")) False """ m = NID_PATTERN.match(nid) return m is not None
[docs] @staticmethod def is_prefixed(value: str) -> bool: """Check whether the given string is prefixed (URN scheme+NID) Parameters ---------- value : str the string value to be checked Returns ------- bool True if the string value starts with the NGSI-LD u`urn:ngsi-ld:` Example ------- >>> from ngsildclient.utils.urn import Urn >>> print(Urn.is_prefixed("urn:ngsi-ld:AirQualityObserved:RZ:Obsv4567")) True """ return value.startswith("urn:ngsi-ld:")
[docs] @staticmethod def prefix(value: str) -> str: """Prefix a string with URN scheme+NID Parameters ---------- value : str the string to be prefixed Returns ------- str the string prefixed (if not already prefixed) Example ------- >>> from ngsildclient.utils.urn import Urn >>> print(Urn.prefix("AirQualityObserved:RZ:Obsv4567")) urn:ngsi-ld:AirQualityObserved:RZ:Obsv4567 """ if value is None: return None return value if Urn.is_prefixed(value) else f"urn:ngsi-ld:{value}"
[docs] @staticmethod def unprefix(value: str) -> str: """Remove the prefix (URN scheme+NID) Parameters ---------- value : str the string to be unprefixed Returns ------- str the string without the prefix Example ------- >>> from ngsildclient.utils.urn import Urn >>> print(Urn.unprefix("urn:ngsi-ld:AirQualityObserved:RZ:Obsv4567")) AirQualityObserved:RZ:Obsv4567 """ if value is None: return None return Urn(value).nss if Urn.is_prefixed(value) else value