NTV.json_ntv.namespace
Created on Jan 20 2023
@author: Philippe@loco-labs.io
The namespace
module is part of the NTV.json_ntv
package (specification document).
It contains the Namespace
and the NtvType
classes and the str_type
method for NTV entities.
0 - Presentation
The NTVtype is defined by a name and a Namespace. The name is unique in the Namespace
A Namespace is represented by a string followed by a point. Namespaces may be nested (the global Namespace is represented by an empty string).
The Namespace representations are added to the value of an NTVtype to have an absolute representation of an NTVtype (long_name).
Example for an absolute representation of an NTVtype defined in two nested Namespace : “ns1.ns2.type” where:
- ns1. is a Namespace defined in the global Namespace,
- ns2. is a Namespace defined in the ns1. Namespace,
- type is a NTVtype defined in the ns2. Namespace
1 - Global Namespace
The structure of types by namespace makes it possible to have types corresponding to recognized standards at the global level. Generic types can also be defined (calculation of the exact type when decoding the value).
The global namespace can include the following structures:
1.1 - Simple (JSON RFC8259)
type (generic type) | value example |
---|---|
boolean (json) | true |
null (json) | null |
number (json) | 45.2 |
string (json) | "string" |
array (json) | [1, 2, 3] |
object (json) | { "str": "test", "bool": true} |
1.2 - Datation (ISO8601 and Posix)
type (generic type) | value example |
---|---|
year | 1998 |
month | 10 |
day | 21 |
wday | 2 |
yday | 251 |
week | 38 |
hour | 20 |
minute | 18 |
second | 54 |
date (dat) | “2022-01-28” |
time (dat) | “T18:23:54”, “18:23”, “T18” |
datetime (dat) | “2022-01-28T18-23-54Z”, “2022-01-28T18-23-54+0400” |
1.3 - Duration (ISO8601 and Posix)
type (generic type) | value example |
---|---|
period | "2007-03-01T13:00:00Z/2008-05-11T15:30:00Z" |
duration | "P0002-10- 15T10:30:20" |
timearray | [date1, date2] |
1.4 - Location (RFC7946 and Open Location Code):
type (generic type) | value example |
---|---|
point (loc) | [ 5.12, 45.256 ] (lon, lat) |
line (loc) | [ point1, point2, point3 ] |
ring | [ point1, point2, point3 ] |
multiline | [ line1, line2, line3] |
polygon (loc) | [ ring1, ring2, ring3] |
multipolygon (loc) | [ poly1, poly2, poly3 ] |
box (loc) | [ -10.0, -10.0, 10.0, 10.0 ] |
geojson (loc) | {“type”: “point”, “coordinates”: [40.0, 0.0] } |
codeolc (loc) | “8FW4V75V+8F6” |
1.5 - Tabular data
NTVtype | NTVvalue |
---|---|
row | JSON-array of JSON-NTV |
field | JSON-array of NTVvalue (following JSON-TAB format) |
table | JSON-array of JSON-NTV fields with the same length |
1.6 - Normalized strings
The type could be uri
, cf exemples :
- "https://www.ietf.org/rfc/rfc3986.txt"
- "https://gallica.bnf.fr/ark:/12148/bpt6k107371t"
- "urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
- "ni:///sha-256;UyaQV-Ev4rdLoHyJJWCi11OHfrYv9E1aGQAlMO2X_-Q"
- "geo:13.4125,103.86673" (RFC5870)
- "info:eu-repo/dai/nl/12345"
- "mailto:John.Doe@example.com"
- "news:comp.infosystems.www.servers.unix"
- "urn:oasis:names:specification:docbook:dtd:xml:4.1.2"
1.7 - Namespaces
Namespaces could also be defined to reference for example:
- geopolitical entities: ISO3166-1 country code (for example "fr." for France)
- data catalogs, for example:
NTVtype | example JSON-NTV |
---|---|
schemaorg. | { “:schemaorg.propertyID”: “NO2” } { “:schemaorg.unitText”:”µg/m3”} |
darwincore. | { “:darwincore.acceptedNameUsage”: “Tamias minimus” } |
1.8 - Identifiers
For example :
type | definition | exemple |
---|---|---|
fr.uic | code UIC station | 8757449 |
fr.iata | code IATA airport | CDG |
2 - Example of using a fr.
namespace
This namespace is dedicated to datasets associated with the France geopolitical namespace (see also the presentation document).
A namespace defines:
- identifiers used to access additional data,
- namespaces associated with catalogs or data sets,
- structured entities used to facilitate the use of data
2.1 - Identifiers
They could correspond to identifiers used in many referenced datasets (via a data schema or a data model).
For example :
type | definition | example |
---|---|---|
fr.dep | code département | 60 |
fr.cp | code postal | 76450 |
fr.naf | code NAF | 23 |
fr.siren | code SIREN enterprise | 418447363 |
fr.fantoir | code FANTOIR voie | 4500023086F |
fr.uai | code UAI établissement | 0951099D |
fr.aca | code académies | 22 |
fr.finessej | code FINESS entité juridique | 790001606 |
fr.rna | code WALDEC association | 843S0843004860 |
fr.spi | code SPI numéro fiscal | 1899582886173 |
fr.nir | code NIR sécurité sociale | 164026005705953 |
2.2 Namespaces
Namespaces could correspond to catalogs or data sets whose data types are identified in data models or in referenced data schemas.
For example :
type | example JSON-NTV |
---|---|
fr.sandre. | { ":fr.sandre.CdStationHydro": K163 3010 01 } { ":fr.sandre.TypStationHydro": "standard" } |
fr.synop. | { ":fr.synop.numer_sta": 07130 } { ":fr.synop.t": 300, ":fr.synop.ff": 5 } |
fr.IRVE. | { ":fr.IRVE.nom_station": "M2026" } { ":fr.IRVE.nom_operateur": "DEBELEC" } |
fr.BAN. | { ":fr.BAN.numero": 54 } { ":fr.BAN.lon": 3.5124 } |
2.3 Entities
They could correspond to assemblies of data associated with a defined structure.
For example :
type | example JSON-NTV |
---|---|
fr.parcelle | {“maParcelle:fr.parcelle”: [ 84500, 0, I, 97]} (fr.cp, fr.cadastre.préfixe, fr.cadastre.section, fr.cadastre.numéro) |
fr.adresse | {“monAdresse:fr.adresse”: [ 54, bis, rue de la mairie, 78730 ] (fr.BAN.numero, fr.BAN.rep, fr.BAN.nom_voie, fr.cp) |
1# -*- coding: utf-8 -*- 2""" 3Created on Jan 20 2023 4 5@author: Philippe@loco-labs.io 6 7The `namespace` module is part of the `NTV.json_ntv` package ([specification document]( 8https://github.com/loco-philippe/NTV/blob/main/documentation/JSON-NTV-standard.pdf)). 9 10It contains the `Namespace` and the `NtvType` classes and the `str_type` method for NTV entities. 11 12# 0 - Presentation 13 14The NTVtype is defined by a name and a Namespace. The name is unique in the Namespace 15 16A Namespace is represented by a string followed by a point. 17Namespaces may be nested (the global Namespace is represented by an empty string). 18 19The Namespace representations are added to the value of an NTVtype to have an absolute 20representation of an NTVtype (long_name). 21 22*Example for an absolute representation of an NTVtype defined in two nested Namespace :* 23*“ns1.ns2.type”* 24*where:* 25- *ns1. is a Namespace defined in the global Namespace,* 26- *ns2. is a Namespace defined in the ns1. Namespace,* 27- *type is a NTVtype defined in the ns2. Namespace* 28 29# 1 - Global Namespace 30 31The structure of types by namespace makes it possible to have types corresponding 32to recognized standards at the global level. 33Generic types can also be defined (calculation of the exact type when decoding the value). 34 35The global namespace can include the following structures: 36 37## 1.1 - Simple (JSON RFC8259) 38 39| type (generic type)| value example | 40|--------------------|-------------------------------| 41| boolean (json) | true | 42| null (json) | null | 43| number (json) | 45.2 | 44| string (json) | "string" | 45| array (json) | [1, 2, 3] | 46| object (json) | { "str": "test", "bool": true}| 47 48## 1.2 - Datation (ISO8601 and Posix) 49 50| type (generic type)| value example | 51|--------------------|-------------------------------| 52| year | 1998 | 53| month | 10 | 54| day | 21 | 55| wday | 2 | 56| yday | 251 | 57| week | 38 | 58| hour | 20 | 59| minute | 18 | 60| second | 54 | 61| date (dat) | “2022-01-28” | 62| time (dat) | “T18:23:54”, “18:23”, “T18” | 63| datetime (dat) | “2022-01-28T18-23-54Z”, “2022-01-28T18-23-54+0400” | 64 65## 1.3 - Duration (ISO8601 and Posix) 66 67| type (generic type)| value example | 68|--------------------|-------------------------------| 69| period | "2007-03-01T13:00:00Z/2008-05-11T15:30:00Z" | 70| duration | "P0002-10- 15T10:30:20" | 71| timearray | [date1, date2] | 72 73## 1.4 - Location (RFC7946 and Open Location Code): 74 75| type (generic type) | value example | 76|---------------------|------------------------------| 77| point (loc) | [ 5.12, 45.256 ] (lon, lat) | 78| line (loc) | [ point1, point2, point3 ] | 79| ring | [ point1, point2, point3 ] | 80| multiline | [ line1, line2, line3] | 81| polygon (loc) | [ ring1, ring2, ring3] | 82| multipolygon (loc) | [ poly1, poly2, poly3 ] | 83| box (loc) | [ -10.0, -10.0, 10.0, 10.0 ] | 84| geojson (loc) | {“type”: “point”, “coordinates”: [40.0, 0.0] } | 85| codeolc (loc) | “8FW4V75V+8F6” | 86 87## 1.5 - Tabular data 88 89| NTVtype | NTVvalue | 90|----------|--------------------------------------------------------| 91| row | JSON-array of JSON-NTV | 92| field | JSON-array of NTVvalue (following JSON-TAB format) | 93| table | JSON-array of JSON-NTV fields with the same length | 94 95 96## 1.6 - Normalized strings 97 98The type could be `uri`, cf exemples : 99- "https://www.ietf.org/rfc/rfc3986.txt" 100- "https://gallica.bnf.fr/ark:/12148/bpt6k107371t" 101- "urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6" 102- "ni:///sha-256;UyaQV-Ev4rdLoHyJJWCi11OHfrYv9E1aGQAlMO2X_-Q" 103- "geo:13.4125,103.86673" *(RFC5870)* 104- "info:eu-repo/dai/nl/12345" 105- "mailto:John.Doe@example.com" 106- "news:comp.infosystems.www.servers.unix" 107- "urn:oasis:names:specification:docbook:dtd:xml:4.1.2" 108 109## 1.7 - Namespaces 110 111Namespaces could also be defined to reference for example: 112- geopolitical entities: ISO3166-1 country code (for example "fr." for France) 113- data catalogs, for example: 114 115| NTVtype | example JSON-NTV | 116|--------------|----------------------------------------------------------------------| 117| schemaorg. | <div>{ “:schemaorg.propertyID”: “NO2” }</div><div>{ “:schemaorg.unitText”:”µg/m3”}</div> | 118| darwincore. | { “:darwincore.acceptedNameUsage”: “Tamias minimus” } | 119 120## 1.8 - Identifiers 121 122For example : 123 124| type | definition | exemple | 125|--------------|---------------------------------|-----------------------| 126| fr.uic | code UIC station | 8757449 | 127| fr.iata | code IATA airport | CDG | 128 129 130# 2 - Example of using a `fr.` namespace 131 132This namespace is dedicated to datasets associated with the France geopolitical namespace 133(see also the [presentation document]( 134https://github.com/loco-philippe/NTV/blob/main/documentation/JSON-NTV-namespace-fr.pdf)). 135 136A namespace defines: 137- identifiers used to access additional data, 138- namespaces associated with catalogs or data sets, 139- structured entities used to facilitate the use of data 140 141## 2.1 - Identifiers 142They could correspond to identifiers used in many referenced datasets 143(via a data schema or a data model). 144 145For example : 146 147| type | definition | example | 148|--------------|---------------------------------|-----------------------| 149| fr.dep | code département | 60 | 150| fr.cp | code postal | 76450 | 151| fr.naf | code NAF | 23 | 152| fr.siren | code SIREN enterprise | 418447363 | 153| fr.fantoir | code FANTOIR voie | 4500023086F | 154| fr.uai | code UAI établissement | 0951099D | 155| fr.aca | code académies | 22 | 156| fr.finessej | code FINESS entité juridique | 790001606 | 157| fr.rna | code WALDEC association | 843S0843004860 | 158| fr.spi | code SPI numéro fiscal | 1899582886173 | 159| fr.nir | code NIR sécurité sociale | 164026005705953 | 160 161## 2.2 Namespaces 162Namespaces could correspond to catalogs or data sets whose data types are identified 163in data models or in referenced data schemas. 164 165For example : 166 167| type | example JSON-NTV | 168|-------------|-----------------------------------------------------------| 169| fr.sandre. | <div>{ ":fr.sandre.CdStationHydro": K163 3010 01 }</div><div>{ ":fr.sandre.TypStationHydro": "standard" }</div> | 170| fr.synop. | <div>{ ":fr.synop.numer_sta": 07130 }</div><div>{ ":fr.synop.t": 300, ":fr.synop.ff": 5 }</div> | 171| fr.IRVE. | <div>{ ":fr.IRVE.nom_station": "M2026" }</div><div>{ ":fr.IRVE.nom_operateur": "DEBELEC" }</div> | 172| fr.BAN. | <div>{ ":fr.BAN.numero": 54 }</div><div>{ ":fr.BAN.lon": 3.5124 }</div>| 173 174## 2.3 Entities 175They could correspond to assemblies of data associated with a defined structure. 176 177For example : 178 179| type | example JSON-NTV | 180|--------------|----------------------------------------------------------| 181| fr.parcelle | <div>{“maParcelle:fr.parcelle”: [ 84500, 0, I, 97]}</div><div><i>(fr.cp, fr.cadastre.préfixe, fr.cadastre.section, fr.cadastre.numéro)</i></div> | 182| fr.adresse | <div>{“monAdresse:fr.adresse”: [ 54, bis, rue de la mairie, 78730 ]</div><div><i>(fr.BAN.numero, fr.BAN.rep, fr.BAN.nom_voie, fr.cp)</i></div> | 183 184""" 185import configparser 186from pathlib import Path 187import json 188import requests 189from time import time 190 191import json_ntv 192 193def agreg_type(str_typ, def_type, single): 194 '''aggregate str_typ and def_type to return an NtvType or a Namespace if not single 195 196 *Parameters* 197 198 - **str_typ** : NtvType or String (long_name) - NtvType to aggregate 199 - **def_typ** : NtvType or String (long_name) - default NtvType or Namespace 200 - **single** : Boolean - Ntv entity concerned (True if NtvSingle)''' 201 if isinstance(str_typ, NtvType): 202 str_typ = str_typ.long_name 203 def_type = str_type(def_type, single) 204 if not str_typ and (isinstance(def_type, NtvType) or 205 (not isinstance(def_type, NtvType) and not single)): 206 return def_type 207 if not str_typ: 208 return NtvType('json') 209 clas = NtvType 210 if str_typ[-1] == '.': 211 clas = Namespace 212 if not def_type: 213 return clas.add(str_typ) 214 if clas == NtvType or clas == Namespace and not single: 215 try: 216 return clas.add(str_typ) 217 except NtvTypeError: 218 return clas.add(_join_type(def_type.long_name, str_typ)) 219 raise NtvTypeError(str_typ + 'and' + 220 def_type.long_name + 'are incompatible') 221 222 223def _join_type(namesp, str_typ): 224 '''join Namespace string and NtvType or Namespace string''' 225 namesp_split = namesp.split('.')[:-1] 226 for name in str_typ.split('.'): 227 if not name in namesp_split: 228 namesp_split.append(name) 229 return '.'.join(namesp_split) 230 231 232def relative_type(str_def, str_typ): 233 '''return relative str_typ string from NtvType or Namespace str_def 234 235 *Parameters* 236 237 - **str_def** : String - long_name of the Namespace or NtvType 238 - **str_type** : String - long_name of Ntvtype to be relative ''' 239 if not str_def and not str_typ: 240 return '' 241 if str_def == str_typ: 242 return '' 243 if not str_def or not str_def in str_typ: 244 return str_typ 245 if not str_typ and str_def[-1] != ".": 246 return str_def 247 str_def_split = str_def.split('.')[:-1] 248 str_typ_split = str_typ.split('.') 249 ind = 0 250 for ind, name in enumerate(str_typ_split): 251 if not name in str_def_split: 252 break 253 return '.'.join(str_typ_split[ind:]) 254 255 256def str_type(long_name, single): 257 ''' create a NtvType or a Namespace from a string 258 259 *Parameters* 260 261 - **long_name** : String - name of the Namespace or NtvType 262 - **single** : Boolean - If True, default type is 'json', else None''' 263 if not long_name and single: 264 return NtvType('json') 265 if not long_name and not single: 266 return None 267 if isinstance(long_name, (NtvType, Namespace)): 268 return long_name 269 if not isinstance(long_name, str): 270 raise NtvTypeError('the name is not a string') 271 if long_name[-1] == '.': 272 return Namespace.add(long_name) 273 return NtvType.add(long_name) 274 275 276class NtvType(): 277 ''' type of NTV entities. 278 279 *Attributes :* 280 281 - **name** : String - name of the type 282 - **nspace** : Namespace - namespace associated 283 - **custom** : boolean - True if not referenced 284 285 The methods defined in this class are : 286 287 *classmethods* 288 - `types` 289 - `add` 290 291 *dynamic values (@property)* 292 - `gen_type` 293 - `long_name` 294 295 *instance methods* 296 - `isin_namespace` 297 ''' 298 _types_ = {} 299 300 @classmethod 301 def types(cls): 302 '''return the list of NtvType created''' 303 return [nam.long_name for nam in cls._types_.values()] 304 305 @classmethod 306 def add(cls, long_name, module=False): 307 '''activate and return a valid NtvType defined by the long name 308 309 *parameters :* 310 311 - **long_name** : String - absolut name of the NtvType 312 - **module** : boolean (default False) - if True search data in the 313 local .ini file, else in the distant repository 314 ''' 315 if long_name == '': 316 return None 317 if long_name in NtvType.types(): 318 return cls._types_[long_name] 319 split_name = long_name.rsplit('.', 1) 320 if split_name[-1] == '': 321 raise NtvTypeError(long_name + ' is not a valid NTVtype') 322 if len(split_name) == 1: 323 return cls(split_name[0]) 324 if len(split_name) == 2: 325 nspace = Namespace.add(split_name[0]+'.', module=module) 326 return cls(split_name[1], nspace) 327 raise NtvTypeError(long_name + ' is not a valid NTVtype') 328 329 def __init__(self, name, nspace=None): 330 '''NtvType constructor. 331 332 *Parameters* 333 334 - **name** : string - name of the Type 335 - **nspace** : Namespace (default None) - namespace associated''' 336 if isinstance(name, NtvType): 337 self.name = name.name 338 self.nspace = name.nspace 339 self.custom = name.custom 340 return 341 if not name or not isinstance(name, str): 342 raise NtvTypeError('null name is not allowed') 343 if not name and not nspace: 344 name = 'json' 345 if not nspace: 346 nspace = Namespace._namespaces_[''] 347 if name[0] != '$' and not nspace.custom and not name in nspace.content['type']: 348 raise NtvTypeError(name + ' is not defined in ' + nspace.long_name) 349 self.name = name 350 self.nspace = nspace 351 self.custom = nspace.custom or name[0] == '$' 352 self._types_[self.long_name] = self 353 return 354 355 def __eq__(self, other): 356 ''' equal if name and nspace are equal''' 357 if self is None and other is None: 358 return True 359 if self is None or other is None: 360 return False 361 if self.__class__.__name__ != other.__class__.__name__: 362 return False 363 return self.name == other.name and self.nspace == other.nspace 364 def __hash__(self): 365 '''return hash(name) + hash(nspace)''' 366 return hash(self.name) + hash(self.nspace) 367 368 def __str__(self): 369 '''return string format''' 370 return self.long_name 371 372 def __repr__(self): 373 '''return classname and long name''' 374 return self.__class__.__name__ + '(' + self.long_name + ')' 375 376 @property 377 def gen_type(self): 378 '''return the generic type of the NtvType''' 379 if self.custom: 380 return '' 381 return self.nspace.content['type'][self.name] 382 383 @property 384 def long_name(self): 385 '''return a string with the absolute name''' 386 return self.nspace.long_name + self.name 387 388 def isin_namespace(self, long_name): 389 '''return the number of level between self and nspace, -1 if None''' 390 return self.nspace.is_child(Namespace.add(long_name)) 391 392 393class Namespace(): 394 ''' Namespace of NTV entities. 395 396 *Attributes :* 397 398 - **name** : String - name of the namespace 399 - **file** : string - location of the file init 400 - **parent** : Namespace - parent namespace 401 - **custom** : boolean - True if not referenced 402 403 The methods defined in this class are : 404 405 *classmethods* 406 - `namespaces` 407 - `add` 408 409 *dynamic values (@property)* 410 - `long_name` 411 - `content` 412 413 *instance methods* 414 - `is_child` 415 - `is_parent` 416 ''' 417 _namespaces_ = {} 418 _pathconfig_ = 'https://raw.githubusercontent.com/loco-philippe/NTV/master/config/' 419 _global_ = "NTV_global_namespace.ini" 420 421 @classmethod 422 def namespaces(cls): 423 '''return the list of Namespace created''' 424 return [nam.long_name for nam in cls._namespaces_.values()] 425 426 @classmethod 427 def add(cls, long_name, module=False): 428 '''activate and return a valid Namespace defined by the long_name. 429 430 *parameters :* 431 432 - **long_name** : String - absolut name of the Namespace 433 - **module** : boolean (default False) - if True search data in the 434 local .ini file, else in the distant repository 435 ''' 436 if long_name in Namespace.namespaces(): 437 return cls._namespaces_[long_name] 438 split_name = long_name.rsplit('.', 2) 439 if len(split_name) == 1 or split_name[-1] != '': 440 raise NtvTypeError(long_name + ' is not a valid classname') 441 if len(split_name) == 2: 442 return cls(split_name[0]+'.', module=module) 443 if len(split_name) == 3: 444 parent = Namespace.add(split_name[0]+'.') 445 return cls(split_name[1]+'.', parent, module=module) 446 raise NtvTypeError(long_name + ' is not a valid classname') 447 448 def __init__(self, name='', parent=None, module=False): 449 ''' 450 Namespace constructor. 451 452 *Parameters* 453 454 - **name** : String - name of the namespace 455 - **parent** : Namespace - parent namespace 456 - **module** : boolean (default False) - if True search data in the 457 local .ini file, else in the distant repository 458 ''' 459 if name and parent is None: 460 parent = Namespace._namespaces_[''] 461 if name and name[0] != '$' and not parent.custom and \ 462 not name in parent.content['namespace']: 463 raise NtvTypeError(name + ' is not defined in ' + parent.long_name) 464 self.name = name 465 self.parent = parent 466 if parent: 467 self.custom = parent.custom or name[0] == '$' 468 else: 469 self.custom = False 470 self.file = Namespace._file(self.parent , self.name, self.custom, module) 471 self.content = Namespace._content(self.file, self.name, self.custom, module) 472 self._namespaces_[self.long_name] = self 473 474 def __eq__(self, other): 475 ''' equal if name and parent are equal''' 476 if self is None and other is None: 477 return True 478 if self is None or other is None: 479 return False 480 if self.__class__.__name__ != other.__class__.__name__: 481 return False 482 return self.name == other.name and self.parent == other.parent 483 484 def __hash__(self): 485 '''return hash(name) + hash(parent)''' 486 return hash(self.name) + hash(self.parent) 487 488 def __str__(self): 489 '''return string format''' 490 return self.long_name 491 492 def __repr__(self): 493 '''return classname and long name''' 494 return self.__class__.__name__ + '(' + self.long_name + ')' 495 496 @staticmethod 497 def _file(parent, name, custom, module): 498 '''return the file name of the Namespace configuration 499 500 *parameters :* 501 502 - **parent** : Namespace - Parent of the Namespace 503 - **name** : String - name of the Namespace 504 - **custom** : boolean - if True, return None (custom Namespace) 505 - **module** : boolean (default False) - if True search data in the 506 local .ini file, else in the distant repository 507 ''' 508 if custom: 509 return None 510 if parent: 511 config = configparser.ConfigParser() 512 if module: 513 p_file = Path(parent.file).stem + Path(parent.file).suffix 514 config.read(Path(json_ntv.__file__ 515 ).parent.joinpath(p_file)) 516 else: 517 config.read_string(requests.get( 518 parent.file, allow_redirects=True).content.decode()) 519 return Namespace._pathconfig_ + json.loads(config['data']['namespace'])[name] 520 return Namespace._pathconfig_ + Namespace._global_ 521 522 @staticmethod 523 def _content(file, name, custom, module): 524 '''return the content of the Namespace configuration 525 526 *parameters :* 527 528 - **file** : string - file name of the parent Namespace 529 - **name** : string - name of the Namespace 530 - **custom** : boolean - if True, return empty dict (custom Namespace) 531 - **module** : boolean (default False) - if True search data in the 532 local .ini file, else in the distant repository 533 534 *return :* 535 536 - dict : {'type': <list of ntv_type names>, 537 'namespace': <list of namespace names>} 538 ''' 539 if custom: 540 return {'type': {}, 'namespace': {}} 541 config = configparser.ConfigParser() 542 if module: 543 p_file = Path(file).stem + Path(file).suffix 544 config.read(Path(json_ntv.__file__ 545 ).parent.joinpath(p_file)) 546 else: 547 config.read_string(requests.get( 548 file, allow_redirects=True).content.decode()) 549 config_name = config['data']['name'] 550 if config_name != name: 551 raise NtvTypeError(file + ' is not correct') 552 return {'type': json.loads(config['data']['type']), 553 'namespace': json.loads(config['data']['namespace'])} 554 555 @property 556 def long_name(self): 557 '''return a string with the absolute name''' 558 if self.parent is None or self.parent.name == '': 559 return self.name 560 return self.parent.long_name + self.name 561 562 def is_child(self, nspace): 563 '''return the number of level between self and nspace, -1 if None''' 564 parent = self.parent 565 if not self.name: 566 return -1 567 if self == nspace: 568 return 0 569 rang = 1 570 while parent.name != '' and parent != nspace: 571 rang += 1 572 parent = parent.parent 573 if parent == nspace: 574 return rang 575 if parent.name == '': 576 return -1 577 578 def is_parent(self, nspace): 579 '''return the number of level between self and nspace, -1 if None''' 580 return nspace.is_child(self) 581 582 583class NtvTypeError(Exception): 584 ''' NtvType or Namespace Exception''' 585 # pass 586 587nroot = Namespace(module=True) 588for root_typ in nroot.content['type'].keys(): 589 typ = NtvType.add(root_typ, module=True) 590typ_json = NtvType('json')
194def agreg_type(str_typ, def_type, single): 195 '''aggregate str_typ and def_type to return an NtvType or a Namespace if not single 196 197 *Parameters* 198 199 - **str_typ** : NtvType or String (long_name) - NtvType to aggregate 200 - **def_typ** : NtvType or String (long_name) - default NtvType or Namespace 201 - **single** : Boolean - Ntv entity concerned (True if NtvSingle)''' 202 if isinstance(str_typ, NtvType): 203 str_typ = str_typ.long_name 204 def_type = str_type(def_type, single) 205 if not str_typ and (isinstance(def_type, NtvType) or 206 (not isinstance(def_type, NtvType) and not single)): 207 return def_type 208 if not str_typ: 209 return NtvType('json') 210 clas = NtvType 211 if str_typ[-1] == '.': 212 clas = Namespace 213 if not def_type: 214 return clas.add(str_typ) 215 if clas == NtvType or clas == Namespace and not single: 216 try: 217 return clas.add(str_typ) 218 except NtvTypeError: 219 return clas.add(_join_type(def_type.long_name, str_typ)) 220 raise NtvTypeError(str_typ + 'and' + 221 def_type.long_name + 'are incompatible')
aggregate str_typ and def_type to return an NtvType or a Namespace if not single
Parameters
- **str_typ** : NtvType or String (long_name) - NtvType to aggregate
- **def_typ** : NtvType or String (long_name) - default NtvType or Namespace
- **single** : Boolean - Ntv entity concerned (True if NtvSingle)
233def relative_type(str_def, str_typ): 234 '''return relative str_typ string from NtvType or Namespace str_def 235 236 *Parameters* 237 238 - **str_def** : String - long_name of the Namespace or NtvType 239 - **str_type** : String - long_name of Ntvtype to be relative ''' 240 if not str_def and not str_typ: 241 return '' 242 if str_def == str_typ: 243 return '' 244 if not str_def or not str_def in str_typ: 245 return str_typ 246 if not str_typ and str_def[-1] != ".": 247 return str_def 248 str_def_split = str_def.split('.')[:-1] 249 str_typ_split = str_typ.split('.') 250 ind = 0 251 for ind, name in enumerate(str_typ_split): 252 if not name in str_def_split: 253 break 254 return '.'.join(str_typ_split[ind:])
return relative str_typ string from NtvType or Namespace str_def
Parameters
- **str_def** : String - long_name of the Namespace or NtvType
- **str_type** : String - long_name of Ntvtype to be relative
257def str_type(long_name, single): 258 ''' create a NtvType or a Namespace from a string 259 260 *Parameters* 261 262 - **long_name** : String - name of the Namespace or NtvType 263 - **single** : Boolean - If True, default type is 'json', else None''' 264 if not long_name and single: 265 return NtvType('json') 266 if not long_name and not single: 267 return None 268 if isinstance(long_name, (NtvType, Namespace)): 269 return long_name 270 if not isinstance(long_name, str): 271 raise NtvTypeError('the name is not a string') 272 if long_name[-1] == '.': 273 return Namespace.add(long_name) 274 return NtvType.add(long_name)
create a NtvType or a Namespace from a string
Parameters
- **long_name** : String - name of the Namespace or NtvType
- **single** : Boolean - If True, default type is 'json', else None
277class NtvType(): 278 ''' type of NTV entities. 279 280 *Attributes :* 281 282 - **name** : String - name of the type 283 - **nspace** : Namespace - namespace associated 284 - **custom** : boolean - True if not referenced 285 286 The methods defined in this class are : 287 288 *classmethods* 289 - `types` 290 - `add` 291 292 *dynamic values (@property)* 293 - `gen_type` 294 - `long_name` 295 296 *instance methods* 297 - `isin_namespace` 298 ''' 299 _types_ = {} 300 301 @classmethod 302 def types(cls): 303 '''return the list of NtvType created''' 304 return [nam.long_name for nam in cls._types_.values()] 305 306 @classmethod 307 def add(cls, long_name, module=False): 308 '''activate and return a valid NtvType defined by the long name 309 310 *parameters :* 311 312 - **long_name** : String - absolut name of the NtvType 313 - **module** : boolean (default False) - if True search data in the 314 local .ini file, else in the distant repository 315 ''' 316 if long_name == '': 317 return None 318 if long_name in NtvType.types(): 319 return cls._types_[long_name] 320 split_name = long_name.rsplit('.', 1) 321 if split_name[-1] == '': 322 raise NtvTypeError(long_name + ' is not a valid NTVtype') 323 if len(split_name) == 1: 324 return cls(split_name[0]) 325 if len(split_name) == 2: 326 nspace = Namespace.add(split_name[0]+'.', module=module) 327 return cls(split_name[1], nspace) 328 raise NtvTypeError(long_name + ' is not a valid NTVtype') 329 330 def __init__(self, name, nspace=None): 331 '''NtvType constructor. 332 333 *Parameters* 334 335 - **name** : string - name of the Type 336 - **nspace** : Namespace (default None) - namespace associated''' 337 if isinstance(name, NtvType): 338 self.name = name.name 339 self.nspace = name.nspace 340 self.custom = name.custom 341 return 342 if not name or not isinstance(name, str): 343 raise NtvTypeError('null name is not allowed') 344 if not name and not nspace: 345 name = 'json' 346 if not nspace: 347 nspace = Namespace._namespaces_[''] 348 if name[0] != '$' and not nspace.custom and not name in nspace.content['type']: 349 raise NtvTypeError(name + ' is not defined in ' + nspace.long_name) 350 self.name = name 351 self.nspace = nspace 352 self.custom = nspace.custom or name[0] == '$' 353 self._types_[self.long_name] = self 354 return 355 356 def __eq__(self, other): 357 ''' equal if name and nspace are equal''' 358 if self is None and other is None: 359 return True 360 if self is None or other is None: 361 return False 362 if self.__class__.__name__ != other.__class__.__name__: 363 return False 364 return self.name == other.name and self.nspace == other.nspace 365 def __hash__(self): 366 '''return hash(name) + hash(nspace)''' 367 return hash(self.name) + hash(self.nspace) 368 369 def __str__(self): 370 '''return string format''' 371 return self.long_name 372 373 def __repr__(self): 374 '''return classname and long name''' 375 return self.__class__.__name__ + '(' + self.long_name + ')' 376 377 @property 378 def gen_type(self): 379 '''return the generic type of the NtvType''' 380 if self.custom: 381 return '' 382 return self.nspace.content['type'][self.name] 383 384 @property 385 def long_name(self): 386 '''return a string with the absolute name''' 387 return self.nspace.long_name + self.name 388 389 def isin_namespace(self, long_name): 390 '''return the number of level between self and nspace, -1 if None''' 391 return self.nspace.is_child(Namespace.add(long_name))
type of NTV entities.
Attributes :
- name : String - name of the type
- nspace : Namespace - namespace associated
- custom : boolean - True if not referenced
The methods defined in this class are :
classmethods
dynamic values (@property)
instance methods
330 def __init__(self, name, nspace=None): 331 '''NtvType constructor. 332 333 *Parameters* 334 335 - **name** : string - name of the Type 336 - **nspace** : Namespace (default None) - namespace associated''' 337 if isinstance(name, NtvType): 338 self.name = name.name 339 self.nspace = name.nspace 340 self.custom = name.custom 341 return 342 if not name or not isinstance(name, str): 343 raise NtvTypeError('null name is not allowed') 344 if not name and not nspace: 345 name = 'json' 346 if not nspace: 347 nspace = Namespace._namespaces_[''] 348 if name[0] != '$' and not nspace.custom and not name in nspace.content['type']: 349 raise NtvTypeError(name + ' is not defined in ' + nspace.long_name) 350 self.name = name 351 self.nspace = nspace 352 self.custom = nspace.custom or name[0] == '$' 353 self._types_[self.long_name] = self 354 return
NtvType constructor.
Parameters
- name : string - name of the Type
- nspace : Namespace (default None) - namespace associated
301 @classmethod 302 def types(cls): 303 '''return the list of NtvType created''' 304 return [nam.long_name for nam in cls._types_.values()]
return the list of NtvType created
306 @classmethod 307 def add(cls, long_name, module=False): 308 '''activate and return a valid NtvType defined by the long name 309 310 *parameters :* 311 312 - **long_name** : String - absolut name of the NtvType 313 - **module** : boolean (default False) - if True search data in the 314 local .ini file, else in the distant repository 315 ''' 316 if long_name == '': 317 return None 318 if long_name in NtvType.types(): 319 return cls._types_[long_name] 320 split_name = long_name.rsplit('.', 1) 321 if split_name[-1] == '': 322 raise NtvTypeError(long_name + ' is not a valid NTVtype') 323 if len(split_name) == 1: 324 return cls(split_name[0]) 325 if len(split_name) == 2: 326 nspace = Namespace.add(split_name[0]+'.', module=module) 327 return cls(split_name[1], nspace) 328 raise NtvTypeError(long_name + ' is not a valid NTVtype')
activate and return a valid NtvType defined by the long name
parameters :
- long_name : String - absolut name of the NtvType
- module : boolean (default False) - if True search data in the local .ini file, else in the distant repository
394class Namespace(): 395 ''' Namespace of NTV entities. 396 397 *Attributes :* 398 399 - **name** : String - name of the namespace 400 - **file** : string - location of the file init 401 - **parent** : Namespace - parent namespace 402 - **custom** : boolean - True if not referenced 403 404 The methods defined in this class are : 405 406 *classmethods* 407 - `namespaces` 408 - `add` 409 410 *dynamic values (@property)* 411 - `long_name` 412 - `content` 413 414 *instance methods* 415 - `is_child` 416 - `is_parent` 417 ''' 418 _namespaces_ = {} 419 _pathconfig_ = 'https://raw.githubusercontent.com/loco-philippe/NTV/master/config/' 420 _global_ = "NTV_global_namespace.ini" 421 422 @classmethod 423 def namespaces(cls): 424 '''return the list of Namespace created''' 425 return [nam.long_name for nam in cls._namespaces_.values()] 426 427 @classmethod 428 def add(cls, long_name, module=False): 429 '''activate and return a valid Namespace defined by the long_name. 430 431 *parameters :* 432 433 - **long_name** : String - absolut name of the Namespace 434 - **module** : boolean (default False) - if True search data in the 435 local .ini file, else in the distant repository 436 ''' 437 if long_name in Namespace.namespaces(): 438 return cls._namespaces_[long_name] 439 split_name = long_name.rsplit('.', 2) 440 if len(split_name) == 1 or split_name[-1] != '': 441 raise NtvTypeError(long_name + ' is not a valid classname') 442 if len(split_name) == 2: 443 return cls(split_name[0]+'.', module=module) 444 if len(split_name) == 3: 445 parent = Namespace.add(split_name[0]+'.') 446 return cls(split_name[1]+'.', parent, module=module) 447 raise NtvTypeError(long_name + ' is not a valid classname') 448 449 def __init__(self, name='', parent=None, module=False): 450 ''' 451 Namespace constructor. 452 453 *Parameters* 454 455 - **name** : String - name of the namespace 456 - **parent** : Namespace - parent namespace 457 - **module** : boolean (default False) - if True search data in the 458 local .ini file, else in the distant repository 459 ''' 460 if name and parent is None: 461 parent = Namespace._namespaces_[''] 462 if name and name[0] != '$' and not parent.custom and \ 463 not name in parent.content['namespace']: 464 raise NtvTypeError(name + ' is not defined in ' + parent.long_name) 465 self.name = name 466 self.parent = parent 467 if parent: 468 self.custom = parent.custom or name[0] == '$' 469 else: 470 self.custom = False 471 self.file = Namespace._file(self.parent , self.name, self.custom, module) 472 self.content = Namespace._content(self.file, self.name, self.custom, module) 473 self._namespaces_[self.long_name] = self 474 475 def __eq__(self, other): 476 ''' equal if name and parent are equal''' 477 if self is None and other is None: 478 return True 479 if self is None or other is None: 480 return False 481 if self.__class__.__name__ != other.__class__.__name__: 482 return False 483 return self.name == other.name and self.parent == other.parent 484 485 def __hash__(self): 486 '''return hash(name) + hash(parent)''' 487 return hash(self.name) + hash(self.parent) 488 489 def __str__(self): 490 '''return string format''' 491 return self.long_name 492 493 def __repr__(self): 494 '''return classname and long name''' 495 return self.__class__.__name__ + '(' + self.long_name + ')' 496 497 @staticmethod 498 def _file(parent, name, custom, module): 499 '''return the file name of the Namespace configuration 500 501 *parameters :* 502 503 - **parent** : Namespace - Parent of the Namespace 504 - **name** : String - name of the Namespace 505 - **custom** : boolean - if True, return None (custom Namespace) 506 - **module** : boolean (default False) - if True search data in the 507 local .ini file, else in the distant repository 508 ''' 509 if custom: 510 return None 511 if parent: 512 config = configparser.ConfigParser() 513 if module: 514 p_file = Path(parent.file).stem + Path(parent.file).suffix 515 config.read(Path(json_ntv.__file__ 516 ).parent.joinpath(p_file)) 517 else: 518 config.read_string(requests.get( 519 parent.file, allow_redirects=True).content.decode()) 520 return Namespace._pathconfig_ + json.loads(config['data']['namespace'])[name] 521 return Namespace._pathconfig_ + Namespace._global_ 522 523 @staticmethod 524 def _content(file, name, custom, module): 525 '''return the content of the Namespace configuration 526 527 *parameters :* 528 529 - **file** : string - file name of the parent Namespace 530 - **name** : string - name of the Namespace 531 - **custom** : boolean - if True, return empty dict (custom Namespace) 532 - **module** : boolean (default False) - if True search data in the 533 local .ini file, else in the distant repository 534 535 *return :* 536 537 - dict : {'type': <list of ntv_type names>, 538 'namespace': <list of namespace names>} 539 ''' 540 if custom: 541 return {'type': {}, 'namespace': {}} 542 config = configparser.ConfigParser() 543 if module: 544 p_file = Path(file).stem + Path(file).suffix 545 config.read(Path(json_ntv.__file__ 546 ).parent.joinpath(p_file)) 547 else: 548 config.read_string(requests.get( 549 file, allow_redirects=True).content.decode()) 550 config_name = config['data']['name'] 551 if config_name != name: 552 raise NtvTypeError(file + ' is not correct') 553 return {'type': json.loads(config['data']['type']), 554 'namespace': json.loads(config['data']['namespace'])} 555 556 @property 557 def long_name(self): 558 '''return a string with the absolute name''' 559 if self.parent is None or self.parent.name == '': 560 return self.name 561 return self.parent.long_name + self.name 562 563 def is_child(self, nspace): 564 '''return the number of level between self and nspace, -1 if None''' 565 parent = self.parent 566 if not self.name: 567 return -1 568 if self == nspace: 569 return 0 570 rang = 1 571 while parent.name != '' and parent != nspace: 572 rang += 1 573 parent = parent.parent 574 if parent == nspace: 575 return rang 576 if parent.name == '': 577 return -1 578 579 def is_parent(self, nspace): 580 '''return the number of level between self and nspace, -1 if None''' 581 return nspace.is_child(self)
Namespace of NTV entities.
Attributes :
- name : String - name of the namespace
- file : string - location of the file init
- parent : Namespace - parent namespace
- custom : boolean - True if not referenced
The methods defined in this class are :
classmethods
dynamic values (@property)
long_name
content
instance methods
449 def __init__(self, name='', parent=None, module=False): 450 ''' 451 Namespace constructor. 452 453 *Parameters* 454 455 - **name** : String - name of the namespace 456 - **parent** : Namespace - parent namespace 457 - **module** : boolean (default False) - if True search data in the 458 local .ini file, else in the distant repository 459 ''' 460 if name and parent is None: 461 parent = Namespace._namespaces_[''] 462 if name and name[0] != '$' and not parent.custom and \ 463 not name in parent.content['namespace']: 464 raise NtvTypeError(name + ' is not defined in ' + parent.long_name) 465 self.name = name 466 self.parent = parent 467 if parent: 468 self.custom = parent.custom or name[0] == '$' 469 else: 470 self.custom = False 471 self.file = Namespace._file(self.parent , self.name, self.custom, module) 472 self.content = Namespace._content(self.file, self.name, self.custom, module) 473 self._namespaces_[self.long_name] = self
Namespace constructor.
Parameters
- name : String - name of the namespace
- parent : Namespace - parent namespace
- module : boolean (default False) - if True search data in the local .ini file, else in the distant repository
422 @classmethod 423 def namespaces(cls): 424 '''return the list of Namespace created''' 425 return [nam.long_name for nam in cls._namespaces_.values()]
return the list of Namespace created
427 @classmethod 428 def add(cls, long_name, module=False): 429 '''activate and return a valid Namespace defined by the long_name. 430 431 *parameters :* 432 433 - **long_name** : String - absolut name of the Namespace 434 - **module** : boolean (default False) - if True search data in the 435 local .ini file, else in the distant repository 436 ''' 437 if long_name in Namespace.namespaces(): 438 return cls._namespaces_[long_name] 439 split_name = long_name.rsplit('.', 2) 440 if len(split_name) == 1 or split_name[-1] != '': 441 raise NtvTypeError(long_name + ' is not a valid classname') 442 if len(split_name) == 2: 443 return cls(split_name[0]+'.', module=module) 444 if len(split_name) == 3: 445 parent = Namespace.add(split_name[0]+'.') 446 return cls(split_name[1]+'.', parent, module=module) 447 raise NtvTypeError(long_name + ' is not a valid classname')
activate and return a valid Namespace defined by the long_name.
parameters :
- long_name : String - absolut name of the Namespace
- module : boolean (default False) - if True search data in the local .ini file, else in the distant repository
563 def is_child(self, nspace): 564 '''return the number of level between self and nspace, -1 if None''' 565 parent = self.parent 566 if not self.name: 567 return -1 568 if self == nspace: 569 return 0 570 rang = 1 571 while parent.name != '' and parent != nspace: 572 rang += 1 573 parent = parent.parent 574 if parent == nspace: 575 return rang 576 if parent.name == '': 577 return -1
return the number of level between self and nspace, -1 if None
NtvType or Namespace Exception
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback