NTV.json_ntv.namespace
@author: Philippe@loco-labs.io
The namespace
module is part of the NTV.json_ntv
package (specification document).
It contains the Namespace
, Datatype
, DatatypeError
classes and
the functions agreg_type
, from_file
, mapping
, relative_type
and str_type
.
Namespace and Datatype entities are used to define NTVtype.
For more information, see the user guide or the github repository.
1# -*- coding: utf-8 -*- 2""" 3@author: Philippe@loco-labs.io 4 5The `namespace` module is part of the `NTV.json_ntv` package ([specification document]( 6https://loco-philippe.github.io/ES/JSON%20semantic%20format%20(JSON-NTV).htm)). 7 8It contains the `Namespace`, `Datatype`, `DatatypeError` classes and 9the functions `agreg_type`, `from_file`, `mapping`, `relative_type` and `str_type`. 10 11Namespace and Datatype entities are used to define NTVtype. 12 13For more information, see the 14[user guide](https://loco-philippe.github.io/NTV/documentation/user_guide.html) 15or the [github repository](https://github.com/loco-philippe/NTV). 16 17""" 18import configparser 19from pathlib import Path 20import json 21import requests 22 23import json_ntv 24from json_ntv.ntv_util import NtvUtil 25from json_ntv.ntv_validate import Validator 26 27SCH_ORG = 'https://schema.org/' 28 29 30def agreg_type(str_typ, def_type, single): 31 '''aggregate str_typ and def_type to return an Datatype or a Namespace if not single 32 33 *Parameters* 34 35 - **str_typ** : Datatype or String (long_name) - Datatype to aggregate 36 - **def_typ** : Datatype or String (long_name) - default Datatype or Namespace 37 - **single** : Boolean - Ntv entity concerned (True if NtvSingle)''' 38 if isinstance(str_typ, Datatype): 39 str_typ = str_typ.long_name 40 def_type = str_type(def_type, single) 41 if not str_typ and (not single or isinstance(def_type, Datatype)): 42 return def_type 43 if not str_typ: 44 return Datatype('json') 45 clas = Namespace if str_typ[-1] == '.' else Datatype 46 if not def_type: 47 return clas.add(str_typ) 48 if clas == Datatype or clas == Namespace and not single: 49 try: 50 return clas.add(str_typ) 51 except DatatypeError: 52 for typ in _join_type(def_type.long_name, str_typ): 53 try: 54 return clas.add(typ) 55 except DatatypeError: 56 pass 57 raise DatatypeError(str_typ + ' and ' + 58 def_type.long_name + ' are incompatible') 59 60 61def from_file(file, name, long_parent=None): 62 '''create a set of Datatype and Namespace associated to a custom Namespace 63 64 *Parameters* 65 66 - **file** : .ini file - description of the Datatype and Namespace 67 - **name** : string - name of the root custom Namespace 68 - **long_parent** : longname of the parent Namespace of the root Namespace 69 ''' 70 long_parent = '' if not long_parent else long_parent 71 if name[0] != '$': 72 raise DatatypeError(name + ' is not a custom Datatype') 73 if not long_parent in Namespace.namespaces(): 74 raise DatatypeError(long_parent + ' is not a valid Datatype') 75 schema_nsp = Namespace(name, long_parent) 76 config = configparser.ConfigParser() 77 config.read(file) 78 if not name in config.sections(): 79 raise DatatypeError(name + ' is not present in ' + str(file)) 80 _add_namespace(config, schema_nsp) 81 82 83def mapping(typ=None, func=None): 84 if typ and func: 85 Datatype.add(typ).validate = func 86 else: 87 if isinstance(typ, str): 88 func_lis = [typ + '_valid'] 89 elif isinstance(typ, (list, tuple)): 90 func_lis = [typ_str + '_valid' for typ_str in typ] 91 else: 92 func_lis = [typ_str + '_valid' for typ_str in Datatype._types_] 93 for func_str in func_lis: 94 if func_str in Validator.__dict__: 95 Datatype.add( 96 func_str[:-6]).validate = Validator.__dict__[func_str] 97 98 99def relative_type(str_def, str_typ): 100 '''return relative str_typ string from Datatype or Namespace str_def 101 102 *Parameters* 103 104 - **str_def** : String - long_name of the Namespace or Datatype 105 - **str_type** : String - long_name of Ntvtype to be relative ''' 106 if not str_def and not str_typ: 107 return '' 108 if str_def == str_typ: 109 return '' 110 if not str_def or not str_def in str_typ: 111 return str_typ 112 if not str_typ and str_def[-1] != ".": 113 return str_def 114 str_def_split = str_def.split('.')[:-1] 115 str_typ_split = str_typ.split('.') 116 ind = 0 117 for ind, name in enumerate(str_typ_split): 118 if not name in str_def_split: 119 break 120 return '.'.join(str_typ_split[ind:]) 121 122 123def str_type(long_name, single): 124 ''' create a Datatype or a Namespace from a string 125 126 *Parameters* 127 128 - **long_name** : String - name of the Namespace or Datatype 129 - **single** : Boolean - If True, default type is 'json', else None''' 130 if not long_name and single: 131 return Datatype('json') 132 if not long_name and not single: 133 return None 134 if long_name.__class__.__name__ in ['Datatype', 'Namespace']: 135 return long_name 136 if not isinstance(long_name, str): 137 raise DatatypeError('the long_name is not a string') 138 if long_name[-1] == '.': 139 return Namespace.add(long_name) 140 return Datatype.add(long_name) 141 142 143def _add_namespace(config, namesp): 144 '''create the child Namespace and the child Datatype of the parent namespace''' 145 if namesp.name in config.sections(): 146 confname = config[namesp.name] 147 if 'namespace' in confname: 148 for nspname in json.loads(confname['namespace']): 149 nsp = Namespace(nspname, namesp, force=True) 150 _add_namespace(config, nsp) 151 if 'type' in confname: 152 for typ in json.loads(confname['type']): 153 Datatype(typ, namesp, force=True) 154 155 156def _join_type(namesp, str_typ): 157 '''join Namespace string and Datatype or Namespace string''' 158 namesp_sp = namesp.split('.') 159 str_typ_sp = str_typ.split('.') 160 idx = -1 161 if str_typ_sp[0] in namesp_sp: 162 idx = namesp_sp.index(str_typ_sp[0]) 163 if namesp_sp[idx:] != str_typ_sp[:len(namesp_sp[idx:])]: 164 idx = -1 165 if idx > -1: 166 namesp_sp = namesp_sp[:idx] 167 return ['.'.join(namesp_sp[:i+1]+str_typ_sp) for i in range(len(namesp_sp)-1, -1, -1)] 168 169 """namesp_split = namesp.split('.')[:-1] 170 for name in str_typ.split('.'): 171 if not name in namesp_split: 172 namesp_split.append(name) 173 return '.'.join(namesp_split)""" 174 175 176def _isin_schemaorg(name, prop=True, typ=None): 177 ''' return True if a schema.org Property is present and associated to a Type 178 or if a schema.org Type is present''' 179 n_org = name if prop else name[:-1] 180 t_org = typ[:-1] if typ else None 181 req_name = requests.get( 182 SCH_ORG + n_org, allow_redirects=True).content.decode() 183 if not prop: 184 return 'Type</ti' in req_name 185 is_prop = 'Property</ti' in req_name 186 if not t_org: 187 return is_prop 188 if is_prop: 189 return '/' + n_org in requests.get(SCH_ORG + t_org, allow_redirects=True 190 ).content.decode() 191 return False 192 193 194class Datatype(NtvUtil): 195 ''' type of NTV entities. 196 197 *Attributes :* 198 199 - **name** : String - name of the type 200 - **nspace** : Namespace - namespace associated 201 - **custom** : boolean - True if not referenced 202 203 The methods defined in this class are : 204 205 *staticmethods* 206 - `types` 207 - `add` 208 209 *dynamic values (@property)* 210 - `gen_type` 211 - `long_name` 212 213 *instance methods* 214 - `isin_namespace` 215 - `validate` 216 ''' 217 218 @staticmethod 219 def types(): 220 '''return the list of Datatype created''' 221 return [nam.long_name for nam in NtvUtil._types_.values()] 222 223 @classmethod 224 def add(cls, long_name, module=False, force=False, validate=None): 225 '''activate and return a valid Datatype defined by the long name 226 227 *parameters :* 228 229 - **long_name** : String - absolut name of the Datatype 230 - **module** : boolean (default False) - if True search data in the 231 local .ini file, else in the distant repository 232 - **validate** : function (default None) - validate function to include 233 ''' 234 if long_name == '': 235 return None 236 if long_name in Datatype.types(): 237 return NtvUtil._types_[long_name] 238 split_name = long_name.rsplit('.', 1) 239 if split_name[-1] == '': 240 raise DatatypeError(long_name + ' is not a valid Datatype') 241 if len(split_name) == 1: 242 return cls(split_name[0], force=force, validate=validate) 243 if len(split_name) == 2: 244 nspace = Namespace.add( 245 split_name[0]+'.', module=module, force=force) 246 return cls(split_name[1], nspace, force=force) 247 raise DatatypeError(long_name + ' is not a valid Datatype') 248 249 def __init__(self, name, nspace=None, force=False, validate=None): 250 '''Datatype constructor. 251 252 *Parameters* 253 254 - **name** : string - name of the Type 255 - **nspace** : Namespace (default None) - namespace associated 256 - **force** : boolean (default False) - if True, no Namespace control 257 - **validate** : function (default None) - validate function to include''' 258 if isinstance(name, Datatype): 259 self.name = name.name 260 self.nspace = name.nspace 261 self.custom = name.custom 262 self.validate = name.validate 263 return 264 if not name or not isinstance(name, str): 265 raise DatatypeError('null name is not allowed') 266 if not name and not nspace: 267 name = 'json' 268 if not nspace: 269 nspace = NtvUtil._namespaces_[''] 270 if nspace.file and SCH_ORG in nspace.file: 271 if not _isin_schemaorg(name, typ=nspace.name): 272 raise DatatypeError( 273 name + ' is not a schema.org Property associated to the ' + nspace.name + 'Type ') 274 else: 275 if not (name[0] == '$' or force or name in nspace.content['type']): 276 raise DatatypeError( 277 name + ' is not defined in ' + nspace.long_name) 278 self.name = name 279 self.nspace = nspace 280 self.custom = nspace.custom or name[0] == '$' 281 if validate: 282 self.validate = validate 283 NtvUtil._types_[self.long_name] = self 284 return 285 286 def __eq__(self, other): 287 ''' equal if name and nspace are equal''' 288 if self is None and other is None: 289 return True 290 if self is None or other is None: 291 return False 292 if self.__class__.__name__ != other.__class__.__name__: 293 return False 294 return self.name == other.name and self.nspace == other.nspace 295 296 def __hash__(self): 297 '''return hash(name) + hash(nspace)''' 298 return hash(self.name) + hash(self.nspace) 299 300 def __str__(self): 301 '''return string format''' 302 return self.long_name 303 304 def __repr__(self): 305 '''return classname and long name''' 306 return self.__class__.__name__ + '(' + self.long_name + ')' 307 308 @property 309 def gen_type(self): 310 '''return the generic type of the Datatype''' 311 if self.custom: 312 return '' 313 return self.nspace.content['type'][self.name] 314 315 @property 316 def long_name(self): 317 '''return a string with the absolute name''' 318 return self.nspace.long_name + self.name 319 320 def isin_namespace(self, long_name): 321 '''return the number of level between self and nspace, -1 if None''' 322 return self.nspace.is_child(Namespace.add(long_name)) 323 324 def validate(self, value): 325 return None 326 327 328class Namespace(NtvUtil): 329 ''' Namespace of NTV entities. 330 331 *Attributes :* 332 333 - **name** : String - name of the namespace 334 - **file** : string - location of the file init 335 - **content** : dict - {'type': <list of ntv_type names>, 336 'namespace': <list of namespace names>} 337 - **parent** : Namespace - parent namespace 338 - **custom** : boolean - True if not referenced 339 340 The methods defined in this class are : 341 342 *staticmethods* 343 - `namespaces` 344 345 *classmethods* 346 - `add` 347 348 *dynamic values (@property)* 349 - `long_name` 350 351 *instance methods* 352 - `is_child` 353 - `is_parent` 354 ''' 355 _pathconfig_ = 'https://raw.githubusercontent.com/loco-philippe/NTV/master/json_ntv/config/' 356 _global_ = "NTV_global_namespace.ini" 357 358 @staticmethod 359 def namespaces(): 360 '''return the list of Namespace created''' 361 return [nam.long_name for nam in NtvUtil._namespaces_.values()] 362 363 @classmethod 364 def add(cls, long_name, module=False, force=False): 365 '''activate and return a valid Namespace defined by the long_name. 366 367 *parameters :* 368 369 - **long_name** : String - absolut name of the Namespace 370 - **module** : boolean (default False) - if True search data in the 371 local .ini file, else in the distant repository 372 ''' 373 if long_name in Namespace.namespaces(): 374 return NtvUtil._namespaces_[long_name] 375 split_name = long_name.rsplit('.', 2) 376 if len(split_name) == 1 or split_name[-1] != '': 377 raise DatatypeError(long_name + ' is not a valid Namespace') 378 if len(split_name) == 2: 379 return cls(split_name[0]+'.', module=module, force=force) 380 if len(split_name) == 3: 381 parent = Namespace.add(split_name[0]+'.', force=force) 382 return cls(split_name[1]+'.', parent, module=module, force=force) 383 raise DatatypeError(long_name + ' is not a valid Namespace') 384 385 def __init__(self, name='', parent=None, module=False, force=False): 386 ''' 387 Namespace constructor. 388 389 *Parameters* 390 391 - **name** : String - name of the namespace 392 - **parent** : Namespace - parent namespace 393 - **module** : boolean (default False) - if True search data in the 394 local .ini file, else in the distant repository 395 - **content** : dict : {'type': <list of ntv_type names>, 396 'namespace': <list of namespace names>} 397 ''' 398 if name and not parent: 399 parent = NtvUtil._namespaces_[''] 400 '''if name and name[0] != '$' and not force and not ( 401 name in parent.content['namespace'] or 'schema.org' in parent.file): 402 raise DatatypeError(name + ' is not defined in ' + parent.long_name)''' 403 404 if parent and parent.file and SCH_ORG in parent.file: 405 if not _isin_schemaorg(name, False): 406 raise DatatypeError(name + ' is not a schema.org Type ') 407 else: 408 if name and not (name[0] == '$' or force or name in parent.content['namespace']): 409 raise DatatypeError( 410 name + ' is not defined in ' + parent.long_name) 411 412 self.name = name 413 self.parent = parent 414 self.custom = parent.custom or name[0] == '$' if parent else False 415 self.file = Namespace._file( 416 self.parent, self.name, self.custom, module) 417 self.content = Namespace._content( 418 self.file, self.name, self.custom, module) 419 NtvUtil._namespaces_[self.long_name] = self 420 421 def __eq__(self, other): 422 ''' equal if name and parent are equal''' 423 if self is None and other is None: 424 return True 425 if self is None or other is None: 426 return False 427 if self.__class__.__name__ != other.__class__.__name__: 428 return False 429 return self.name == other.name and self.parent == other.parent 430 431 def __hash__(self): 432 '''return hash(name) + hash(parent)''' 433 return hash(self.name) + hash(self.parent) 434 435 def __str__(self): 436 '''return string format''' 437 return self.long_name 438 439 def __repr__(self): 440 '''return classname and long name''' 441 return self.__class__.__name__ + '(' + self.long_name + ')' 442 443 @staticmethod 444 def _file(parent, name, custom, module): 445 '''return the file name of the Namespace configuration 446 447 *parameters :* 448 449 - **parent** : Namespace - Parent of the Namespace 450 - **name** : String - name of the Namespace 451 - **custom** : boolean - if True, return None (custom Namespace) 452 - **module** : boolean (default False) - if True search data in the 453 local .ini file, else in the distant repository 454 ''' 455 if custom: 456 return None 457 if parent: 458 if 'schema.org' in parent.file or name == 'org.': 459 return SCH_ORG 460 config = configparser.ConfigParser() 461 if module: 462 p_file = Path(parent.file).stem + Path(parent.file).suffix 463 config.read(Path(json_ntv.__file__).parent / 'config' / p_file) 464 else: 465 config.read_string(requests.get( 466 parent.file, allow_redirects=True).content.decode()) 467 return Namespace._pathconfig_ + json.loads(config['data']['namespace'])[name] 468 return Namespace._pathconfig_ + Namespace._global_ 469 470 @staticmethod 471 def _content(file, name, custom, module): 472 '''return the content of the Namespace configuration 473 474 *parameters :* 475 476 - **file** : string - file name of the parent Namespace 477 - **name** : string - name of the Namespace 478 - **custom** : boolean - if True, return empty dict (custom Namespace) 479 - **module** : boolean (default False) - if True search data in the 480 local .ini file, else in the distant repository 481 482 *return :* 483 484 - dict : {'type': <list of ntv_type names>, 485 'namespace': <list of namespace names>} 486 ''' 487 if custom or 'schema.org' in file: 488 return {'type': {}, 'namespace': {}} 489 config = configparser.ConfigParser() 490 if module: 491 p_file = Path(file).stem + Path(file).suffix 492 config.read(Path(json_ntv.__file__).parent / 'config' / p_file) 493 else: 494 config.read_string(requests.get( 495 file, allow_redirects=True).content.decode()) 496 config_name = config['data']['name'] 497 if config_name != name: 498 raise DatatypeError(file + ' is not correct') 499 return {'type': json.loads(config['data']['type']), 500 'namespace': json.loads(config['data']['namespace'])} 501 502 @property 503 def long_name(self): 504 '''return a string with the absolute name''' 505 if self.parent is None or self.parent.name == '': 506 return self.name 507 return self.parent.long_name + self.name 508 509 def is_child(self, nspace): 510 '''return the number of level between self and nspace, -1 if None''' 511 parent = self.parent 512 if not self.name: 513 return -1 514 if self == nspace: 515 return 0 516 rang = 1 517 while parent.name != '' and parent != nspace: 518 rang += 1 519 parent = parent.parent 520 if parent == nspace: 521 return rang 522 if parent.name == '': 523 return -1 524 525 def is_parent(self, nspace): 526 '''return the number of level between self and nspace, -1 if None''' 527 return nspace.is_child(self) 528 529 530class DatatypeError(Exception): 531 ''' Datatype or Namespace Exception''' 532 533 534nroot = Namespace(module=True) 535for root_typ in nroot.content['type']: 536 #typ = Datatype.add(root_typ, module=True) 537 typ = Datatype.add(root_typ, module=True, 538 validate=Validator.__dict__[root_typ + '_valid']) 539# mapping(Datatype.types()) 540typ_json = Datatype('json')
31def agreg_type(str_typ, def_type, single): 32 '''aggregate str_typ and def_type to return an Datatype or a Namespace if not single 33 34 *Parameters* 35 36 - **str_typ** : Datatype or String (long_name) - Datatype to aggregate 37 - **def_typ** : Datatype or String (long_name) - default Datatype or Namespace 38 - **single** : Boolean - Ntv entity concerned (True if NtvSingle)''' 39 if isinstance(str_typ, Datatype): 40 str_typ = str_typ.long_name 41 def_type = str_type(def_type, single) 42 if not str_typ and (not single or isinstance(def_type, Datatype)): 43 return def_type 44 if not str_typ: 45 return Datatype('json') 46 clas = Namespace if str_typ[-1] == '.' else Datatype 47 if not def_type: 48 return clas.add(str_typ) 49 if clas == Datatype or clas == Namespace and not single: 50 try: 51 return clas.add(str_typ) 52 except DatatypeError: 53 for typ in _join_type(def_type.long_name, str_typ): 54 try: 55 return clas.add(typ) 56 except DatatypeError: 57 pass 58 raise DatatypeError(str_typ + ' and ' + 59 def_type.long_name + ' are incompatible')
aggregate str_typ and def_type to return an Datatype or a Namespace if not single
Parameters
- **str_typ** : Datatype or String (long_name) - Datatype to aggregate
- **def_typ** : Datatype or String (long_name) - default Datatype or Namespace
- **single** : Boolean - Ntv entity concerned (True if NtvSingle)
62def from_file(file, name, long_parent=None): 63 '''create a set of Datatype and Namespace associated to a custom Namespace 64 65 *Parameters* 66 67 - **file** : .ini file - description of the Datatype and Namespace 68 - **name** : string - name of the root custom Namespace 69 - **long_parent** : longname of the parent Namespace of the root Namespace 70 ''' 71 long_parent = '' if not long_parent else long_parent 72 if name[0] != '$': 73 raise DatatypeError(name + ' is not a custom Datatype') 74 if not long_parent in Namespace.namespaces(): 75 raise DatatypeError(long_parent + ' is not a valid Datatype') 76 schema_nsp = Namespace(name, long_parent) 77 config = configparser.ConfigParser() 78 config.read(file) 79 if not name in config.sections(): 80 raise DatatypeError(name + ' is not present in ' + str(file)) 81 _add_namespace(config, schema_nsp)
create a set of Datatype and Namespace associated to a custom Namespace
Parameters
- **file** : .ini file - description of the Datatype and Namespace
- **name** : string - name of the root custom Namespace
- **long_parent** : longname of the parent Namespace of the root Namespace
84def mapping(typ=None, func=None): 85 if typ and func: 86 Datatype.add(typ).validate = func 87 else: 88 if isinstance(typ, str): 89 func_lis = [typ + '_valid'] 90 elif isinstance(typ, (list, tuple)): 91 func_lis = [typ_str + '_valid' for typ_str in typ] 92 else: 93 func_lis = [typ_str + '_valid' for typ_str in Datatype._types_] 94 for func_str in func_lis: 95 if func_str in Validator.__dict__: 96 Datatype.add( 97 func_str[:-6]).validate = Validator.__dict__[func_str]
100def relative_type(str_def, str_typ): 101 '''return relative str_typ string from Datatype or Namespace str_def 102 103 *Parameters* 104 105 - **str_def** : String - long_name of the Namespace or Datatype 106 - **str_type** : String - long_name of Ntvtype to be relative ''' 107 if not str_def and not str_typ: 108 return '' 109 if str_def == str_typ: 110 return '' 111 if not str_def or not str_def in str_typ: 112 return str_typ 113 if not str_typ and str_def[-1] != ".": 114 return str_def 115 str_def_split = str_def.split('.')[:-1] 116 str_typ_split = str_typ.split('.') 117 ind = 0 118 for ind, name in enumerate(str_typ_split): 119 if not name in str_def_split: 120 break 121 return '.'.join(str_typ_split[ind:])
return relative str_typ string from Datatype or Namespace str_def
Parameters
- **str_def** : String - long_name of the Namespace or Datatype
- **str_type** : String - long_name of Ntvtype to be relative
124def str_type(long_name, single): 125 ''' create a Datatype or a Namespace from a string 126 127 *Parameters* 128 129 - **long_name** : String - name of the Namespace or Datatype 130 - **single** : Boolean - If True, default type is 'json', else None''' 131 if not long_name and single: 132 return Datatype('json') 133 if not long_name and not single: 134 return None 135 if long_name.__class__.__name__ in ['Datatype', 'Namespace']: 136 return long_name 137 if not isinstance(long_name, str): 138 raise DatatypeError('the long_name is not a string') 139 if long_name[-1] == '.': 140 return Namespace.add(long_name) 141 return Datatype.add(long_name)
create a Datatype or a Namespace from a string
Parameters
- **long_name** : String - name of the Namespace or Datatype
- **single** : Boolean - If True, default type is 'json', else None
195class Datatype(NtvUtil): 196 ''' type of NTV entities. 197 198 *Attributes :* 199 200 - **name** : String - name of the type 201 - **nspace** : Namespace - namespace associated 202 - **custom** : boolean - True if not referenced 203 204 The methods defined in this class are : 205 206 *staticmethods* 207 - `types` 208 - `add` 209 210 *dynamic values (@property)* 211 - `gen_type` 212 - `long_name` 213 214 *instance methods* 215 - `isin_namespace` 216 - `validate` 217 ''' 218 219 @staticmethod 220 def types(): 221 '''return the list of Datatype created''' 222 return [nam.long_name for nam in NtvUtil._types_.values()] 223 224 @classmethod 225 def add(cls, long_name, module=False, force=False, validate=None): 226 '''activate and return a valid Datatype defined by the long name 227 228 *parameters :* 229 230 - **long_name** : String - absolut name of the Datatype 231 - **module** : boolean (default False) - if True search data in the 232 local .ini file, else in the distant repository 233 - **validate** : function (default None) - validate function to include 234 ''' 235 if long_name == '': 236 return None 237 if long_name in Datatype.types(): 238 return NtvUtil._types_[long_name] 239 split_name = long_name.rsplit('.', 1) 240 if split_name[-1] == '': 241 raise DatatypeError(long_name + ' is not a valid Datatype') 242 if len(split_name) == 1: 243 return cls(split_name[0], force=force, validate=validate) 244 if len(split_name) == 2: 245 nspace = Namespace.add( 246 split_name[0]+'.', module=module, force=force) 247 return cls(split_name[1], nspace, force=force) 248 raise DatatypeError(long_name + ' is not a valid Datatype') 249 250 def __init__(self, name, nspace=None, force=False, validate=None): 251 '''Datatype constructor. 252 253 *Parameters* 254 255 - **name** : string - name of the Type 256 - **nspace** : Namespace (default None) - namespace associated 257 - **force** : boolean (default False) - if True, no Namespace control 258 - **validate** : function (default None) - validate function to include''' 259 if isinstance(name, Datatype): 260 self.name = name.name 261 self.nspace = name.nspace 262 self.custom = name.custom 263 self.validate = name.validate 264 return 265 if not name or not isinstance(name, str): 266 raise DatatypeError('null name is not allowed') 267 if not name and not nspace: 268 name = 'json' 269 if not nspace: 270 nspace = NtvUtil._namespaces_[''] 271 if nspace.file and SCH_ORG in nspace.file: 272 if not _isin_schemaorg(name, typ=nspace.name): 273 raise DatatypeError( 274 name + ' is not a schema.org Property associated to the ' + nspace.name + 'Type ') 275 else: 276 if not (name[0] == '$' or force or name in nspace.content['type']): 277 raise DatatypeError( 278 name + ' is not defined in ' + nspace.long_name) 279 self.name = name 280 self.nspace = nspace 281 self.custom = nspace.custom or name[0] == '$' 282 if validate: 283 self.validate = validate 284 NtvUtil._types_[self.long_name] = self 285 return 286 287 def __eq__(self, other): 288 ''' equal if name and nspace are equal''' 289 if self is None and other is None: 290 return True 291 if self is None or other is None: 292 return False 293 if self.__class__.__name__ != other.__class__.__name__: 294 return False 295 return self.name == other.name and self.nspace == other.nspace 296 297 def __hash__(self): 298 '''return hash(name) + hash(nspace)''' 299 return hash(self.name) + hash(self.nspace) 300 301 def __str__(self): 302 '''return string format''' 303 return self.long_name 304 305 def __repr__(self): 306 '''return classname and long name''' 307 return self.__class__.__name__ + '(' + self.long_name + ')' 308 309 @property 310 def gen_type(self): 311 '''return the generic type of the Datatype''' 312 if self.custom: 313 return '' 314 return self.nspace.content['type'][self.name] 315 316 @property 317 def long_name(self): 318 '''return a string with the absolute name''' 319 return self.nspace.long_name + self.name 320 321 def isin_namespace(self, long_name): 322 '''return the number of level between self and nspace, -1 if None''' 323 return self.nspace.is_child(Namespace.add(long_name)) 324 325 def validate(self, value): 326 return None
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 :
staticmethods
dynamic values (@property)
instance methods
250 def __init__(self, name, nspace=None, force=False, validate=None): 251 '''Datatype constructor. 252 253 *Parameters* 254 255 - **name** : string - name of the Type 256 - **nspace** : Namespace (default None) - namespace associated 257 - **force** : boolean (default False) - if True, no Namespace control 258 - **validate** : function (default None) - validate function to include''' 259 if isinstance(name, Datatype): 260 self.name = name.name 261 self.nspace = name.nspace 262 self.custom = name.custom 263 self.validate = name.validate 264 return 265 if not name or not isinstance(name, str): 266 raise DatatypeError('null name is not allowed') 267 if not name and not nspace: 268 name = 'json' 269 if not nspace: 270 nspace = NtvUtil._namespaces_[''] 271 if nspace.file and SCH_ORG in nspace.file: 272 if not _isin_schemaorg(name, typ=nspace.name): 273 raise DatatypeError( 274 name + ' is not a schema.org Property associated to the ' + nspace.name + 'Type ') 275 else: 276 if not (name[0] == '$' or force or name in nspace.content['type']): 277 raise DatatypeError( 278 name + ' is not defined in ' + nspace.long_name) 279 self.name = name 280 self.nspace = nspace 281 self.custom = nspace.custom or name[0] == '$' 282 if validate: 283 self.validate = validate 284 NtvUtil._types_[self.long_name] = self 285 return
Datatype constructor.
Parameters
- name : string - name of the Type
- nspace : Namespace (default None) - namespace associated
- force : boolean (default False) - if True, no Namespace control
- validate : function (default None) - validate function to include
219 @staticmethod 220 def types(): 221 '''return the list of Datatype created''' 222 return [nam.long_name for nam in NtvUtil._types_.values()]
return the list of Datatype created
224 @classmethod 225 def add(cls, long_name, module=False, force=False, validate=None): 226 '''activate and return a valid Datatype defined by the long name 227 228 *parameters :* 229 230 - **long_name** : String - absolut name of the Datatype 231 - **module** : boolean (default False) - if True search data in the 232 local .ini file, else in the distant repository 233 - **validate** : function (default None) - validate function to include 234 ''' 235 if long_name == '': 236 return None 237 if long_name in Datatype.types(): 238 return NtvUtil._types_[long_name] 239 split_name = long_name.rsplit('.', 1) 240 if split_name[-1] == '': 241 raise DatatypeError(long_name + ' is not a valid Datatype') 242 if len(split_name) == 1: 243 return cls(split_name[0], force=force, validate=validate) 244 if len(split_name) == 2: 245 nspace = Namespace.add( 246 split_name[0]+'.', module=module, force=force) 247 return cls(split_name[1], nspace, force=force) 248 raise DatatypeError(long_name + ' is not a valid Datatype')
activate and return a valid Datatype defined by the long name
parameters :
- long_name : String - absolut name of the Datatype
- module : boolean (default False) - if True search data in the local .ini file, else in the distant repository
- validate : function (default None) - validate function to include
321 def isin_namespace(self, long_name): 322 '''return the number of level between self and nspace, -1 if None''' 323 return self.nspace.is_child(Namespace.add(long_name))
return the number of level between self and nspace, -1 if None
Inherited Members
- json_ntv.ntv_util.NtvUtil
- from_obj_name
- decode_ntv_tab
- to_ntvpointer
329class Namespace(NtvUtil): 330 ''' Namespace of NTV entities. 331 332 *Attributes :* 333 334 - **name** : String - name of the namespace 335 - **file** : string - location of the file init 336 - **content** : dict - {'type': <list of ntv_type names>, 337 'namespace': <list of namespace names>} 338 - **parent** : Namespace - parent namespace 339 - **custom** : boolean - True if not referenced 340 341 The methods defined in this class are : 342 343 *staticmethods* 344 - `namespaces` 345 346 *classmethods* 347 - `add` 348 349 *dynamic values (@property)* 350 - `long_name` 351 352 *instance methods* 353 - `is_child` 354 - `is_parent` 355 ''' 356 _pathconfig_ = 'https://raw.githubusercontent.com/loco-philippe/NTV/master/json_ntv/config/' 357 _global_ = "NTV_global_namespace.ini" 358 359 @staticmethod 360 def namespaces(): 361 '''return the list of Namespace created''' 362 return [nam.long_name for nam in NtvUtil._namespaces_.values()] 363 364 @classmethod 365 def add(cls, long_name, module=False, force=False): 366 '''activate and return a valid Namespace defined by the long_name. 367 368 *parameters :* 369 370 - **long_name** : String - absolut name of the Namespace 371 - **module** : boolean (default False) - if True search data in the 372 local .ini file, else in the distant repository 373 ''' 374 if long_name in Namespace.namespaces(): 375 return NtvUtil._namespaces_[long_name] 376 split_name = long_name.rsplit('.', 2) 377 if len(split_name) == 1 or split_name[-1] != '': 378 raise DatatypeError(long_name + ' is not a valid Namespace') 379 if len(split_name) == 2: 380 return cls(split_name[0]+'.', module=module, force=force) 381 if len(split_name) == 3: 382 parent = Namespace.add(split_name[0]+'.', force=force) 383 return cls(split_name[1]+'.', parent, module=module, force=force) 384 raise DatatypeError(long_name + ' is not a valid Namespace') 385 386 def __init__(self, name='', parent=None, module=False, force=False): 387 ''' 388 Namespace constructor. 389 390 *Parameters* 391 392 - **name** : String - name of the namespace 393 - **parent** : Namespace - parent namespace 394 - **module** : boolean (default False) - if True search data in the 395 local .ini file, else in the distant repository 396 - **content** : dict : {'type': <list of ntv_type names>, 397 'namespace': <list of namespace names>} 398 ''' 399 if name and not parent: 400 parent = NtvUtil._namespaces_[''] 401 '''if name and name[0] != '$' and not force and not ( 402 name in parent.content['namespace'] or 'schema.org' in parent.file): 403 raise DatatypeError(name + ' is not defined in ' + parent.long_name)''' 404 405 if parent and parent.file and SCH_ORG in parent.file: 406 if not _isin_schemaorg(name, False): 407 raise DatatypeError(name + ' is not a schema.org Type ') 408 else: 409 if name and not (name[0] == '$' or force or name in parent.content['namespace']): 410 raise DatatypeError( 411 name + ' is not defined in ' + parent.long_name) 412 413 self.name = name 414 self.parent = parent 415 self.custom = parent.custom or name[0] == '$' if parent else False 416 self.file = Namespace._file( 417 self.parent, self.name, self.custom, module) 418 self.content = Namespace._content( 419 self.file, self.name, self.custom, module) 420 NtvUtil._namespaces_[self.long_name] = self 421 422 def __eq__(self, other): 423 ''' equal if name and parent are equal''' 424 if self is None and other is None: 425 return True 426 if self is None or other is None: 427 return False 428 if self.__class__.__name__ != other.__class__.__name__: 429 return False 430 return self.name == other.name and self.parent == other.parent 431 432 def __hash__(self): 433 '''return hash(name) + hash(parent)''' 434 return hash(self.name) + hash(self.parent) 435 436 def __str__(self): 437 '''return string format''' 438 return self.long_name 439 440 def __repr__(self): 441 '''return classname and long name''' 442 return self.__class__.__name__ + '(' + self.long_name + ')' 443 444 @staticmethod 445 def _file(parent, name, custom, module): 446 '''return the file name of the Namespace configuration 447 448 *parameters :* 449 450 - **parent** : Namespace - Parent of the Namespace 451 - **name** : String - name of the Namespace 452 - **custom** : boolean - if True, return None (custom Namespace) 453 - **module** : boolean (default False) - if True search data in the 454 local .ini file, else in the distant repository 455 ''' 456 if custom: 457 return None 458 if parent: 459 if 'schema.org' in parent.file or name == 'org.': 460 return SCH_ORG 461 config = configparser.ConfigParser() 462 if module: 463 p_file = Path(parent.file).stem + Path(parent.file).suffix 464 config.read(Path(json_ntv.__file__).parent / 'config' / p_file) 465 else: 466 config.read_string(requests.get( 467 parent.file, allow_redirects=True).content.decode()) 468 return Namespace._pathconfig_ + json.loads(config['data']['namespace'])[name] 469 return Namespace._pathconfig_ + Namespace._global_ 470 471 @staticmethod 472 def _content(file, name, custom, module): 473 '''return the content of the Namespace configuration 474 475 *parameters :* 476 477 - **file** : string - file name of the parent Namespace 478 - **name** : string - name of the Namespace 479 - **custom** : boolean - if True, return empty dict (custom Namespace) 480 - **module** : boolean (default False) - if True search data in the 481 local .ini file, else in the distant repository 482 483 *return :* 484 485 - dict : {'type': <list of ntv_type names>, 486 'namespace': <list of namespace names>} 487 ''' 488 if custom or 'schema.org' in file: 489 return {'type': {}, 'namespace': {}} 490 config = configparser.ConfigParser() 491 if module: 492 p_file = Path(file).stem + Path(file).suffix 493 config.read(Path(json_ntv.__file__).parent / 'config' / p_file) 494 else: 495 config.read_string(requests.get( 496 file, allow_redirects=True).content.decode()) 497 config_name = config['data']['name'] 498 if config_name != name: 499 raise DatatypeError(file + ' is not correct') 500 return {'type': json.loads(config['data']['type']), 501 'namespace': json.loads(config['data']['namespace'])} 502 503 @property 504 def long_name(self): 505 '''return a string with the absolute name''' 506 if self.parent is None or self.parent.name == '': 507 return self.name 508 return self.parent.long_name + self.name 509 510 def is_child(self, nspace): 511 '''return the number of level between self and nspace, -1 if None''' 512 parent = self.parent 513 if not self.name: 514 return -1 515 if self == nspace: 516 return 0 517 rang = 1 518 while parent.name != '' and parent != nspace: 519 rang += 1 520 parent = parent.parent 521 if parent == nspace: 522 return rang 523 if parent.name == '': 524 return -1 525 526 def is_parent(self, nspace): 527 '''return the number of level between self and nspace, -1 if None''' 528 return nspace.is_child(self)
Namespace of NTV entities.
Attributes :
- name : String - name of the namespace
- file : string - location of the file init
- content : dict - {'type':
- ,
'namespace':
- }
- parent : Namespace - parent namespace
- custom : boolean - True if not referenced
The methods defined in this class are :
staticmethods
classmethods
dynamic values (@property)
instance methods
386 def __init__(self, name='', parent=None, module=False, force=False): 387 ''' 388 Namespace constructor. 389 390 *Parameters* 391 392 - **name** : String - name of the namespace 393 - **parent** : Namespace - parent namespace 394 - **module** : boolean (default False) - if True search data in the 395 local .ini file, else in the distant repository 396 - **content** : dict : {'type': <list of ntv_type names>, 397 'namespace': <list of namespace names>} 398 ''' 399 if name and not parent: 400 parent = NtvUtil._namespaces_[''] 401 '''if name and name[0] != '$' and not force and not ( 402 name in parent.content['namespace'] or 'schema.org' in parent.file): 403 raise DatatypeError(name + ' is not defined in ' + parent.long_name)''' 404 405 if parent and parent.file and SCH_ORG in parent.file: 406 if not _isin_schemaorg(name, False): 407 raise DatatypeError(name + ' is not a schema.org Type ') 408 else: 409 if name and not (name[0] == '$' or force or name in parent.content['namespace']): 410 raise DatatypeError( 411 name + ' is not defined in ' + parent.long_name) 412 413 self.name = name 414 self.parent = parent 415 self.custom = parent.custom or name[0] == '$' if parent else False 416 self.file = Namespace._file( 417 self.parent, self.name, self.custom, module) 418 self.content = Namespace._content( 419 self.file, self.name, self.custom, module) 420 NtvUtil._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
- content : dict : {'type':
- ,
'namespace':
- }
359 @staticmethod 360 def namespaces(): 361 '''return the list of Namespace created''' 362 return [nam.long_name for nam in NtvUtil._namespaces_.values()]
return the list of Namespace created
364 @classmethod 365 def add(cls, long_name, module=False, force=False): 366 '''activate and return a valid Namespace defined by the long_name. 367 368 *parameters :* 369 370 - **long_name** : String - absolut name of the Namespace 371 - **module** : boolean (default False) - if True search data in the 372 local .ini file, else in the distant repository 373 ''' 374 if long_name in Namespace.namespaces(): 375 return NtvUtil._namespaces_[long_name] 376 split_name = long_name.rsplit('.', 2) 377 if len(split_name) == 1 or split_name[-1] != '': 378 raise DatatypeError(long_name + ' is not a valid Namespace') 379 if len(split_name) == 2: 380 return cls(split_name[0]+'.', module=module, force=force) 381 if len(split_name) == 3: 382 parent = Namespace.add(split_name[0]+'.', force=force) 383 return cls(split_name[1]+'.', parent, module=module, force=force) 384 raise DatatypeError(long_name + ' is not a valid Namespace')
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
510 def is_child(self, nspace): 511 '''return the number of level between self and nspace, -1 if None''' 512 parent = self.parent 513 if not self.name: 514 return -1 515 if self == nspace: 516 return 0 517 rang = 1 518 while parent.name != '' and parent != nspace: 519 rang += 1 520 parent = parent.parent 521 if parent == nspace: 522 return rang 523 if parent.name == '': 524 return -1
return the number of level between self and nspace, -1 if None
526 def is_parent(self, nspace): 527 '''return the number of level between self and nspace, -1 if None''' 528 return nspace.is_child(self)
return the number of level between self and nspace, -1 if None
Inherited Members
- json_ntv.ntv_util.NtvUtil
- from_obj_name
- decode_ntv_tab
- to_ntvpointer
Datatype or Namespace Exception
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback