openc2lib.types.basetypes

OpenC2 structures

Definition of the base types (structures) in the OpenC2 DataModels (Sec. 3.1.1) Each OpenC2 object must derive from these classes, which affects serialization operations

  1""" OpenC2 structures
  2
  3	Definition of the base types (structures) in the OpenC2 DataModels (Sec. 3.1.1)
  4	Each OpenC2 object must derive from these classes, which
  5	affects serialization operations
  6
  7"""
  8
  9import aenum
 10import inspect
 11import logging
 12
 13logger = logging.getLogger('openc2lib')
 14""" openc2lib logger """
 15
 16
 17class Openc2Type():
 18	""" OpenC2 Language Element
 19		
 20		This class is currently unused and is only provided to have a common ancestor for all
 21		OpenC2 basic types. It may be used in the future to implement common methods or arguments.
 22	"""
 23	pass
 24
 25
 26#@register_basetype
 27class Record(Openc2Type):
 28	""" OpenC2 Record
 29
 30		Implements OpenC2 Record: 
 31			>An ordered map from a list of keys with positions to values with 
 32			positionally-defined semantics. Each key has a position and name, 
 33			and is mapped to a type.
 34
 35		It expect keys to be public class attributes. All internal attributes 
 36		must be kept private by prefixing it with an '_'.
 37
 38	"""
 39	def todict(self, e):
 40		""" Converts to dictionary 
 41		
 42			It is used to convert this object to an intermediary representation during 
 43			serialization. It takes an `Encoder` argument that is used to recursively
 44			serialize inner data and structures (the `Encoder` provides standard methods
 45			for converting base types to dictionaries).. 
 46
 47			:param e: The `Encoder` that is being used.
 48			:return: A dictionary compliants to the Language Specification's serialization
 49			rules.
 50		"""
 51		objdic = vars(self)
 52
 53		dic = {}
 54		for k,v in objdic.items():
 55			# Fix keywords corresponding to variable names that clash with Python keywords
 56			if isinstance(k, str) and k.endswith('_'):
 57				k = k.rstrip('_')
 58			# Remove empty and private elements; do not include non-string keys
 59			if not v is None and not k.startswith('_') and isinstance(k, str):
 60				dic[k] = v	
 61
 62		return e.todict(dic)
 63
 64	@classmethod
 65	def fromdict(clstype, dic, e):
 66		""" Builds instance from dictionary 
 67
 68			It is used during deserialization to create an openc2lib instance from the text message.
 69			It takes an `Encoder` instance that is used to recursively build instances of the inner
 70			objects (the `Encoder` provides standard methods to create instances of base objects like
 71			strings, integers, boolean).
 72
 73			:param dic: The intermediary dictionary representation from which the object is built.
 74			:param e: The `Encoder that is being used.
 75			:return: An instance of this class initialized from the dictionary values.
 76		"""
 77		objdic = {}
 78		# Retrieve class type for each field in the dictionary
 79		fielddesc = None
 80		for tpl in inspect.getmembers(clstype):
 81			if tpl[0] == '__annotations__':
 82				fielddesc = tpl[1]
 83
 84		for k,v in dic.items():
 85			if k not in fielddesc:
 86				raise Exception("Unknown field '" + k + "' from message")
 87			objdic[k] = e.fromdict(fielddesc[k], v)
 88
 89
 90		# A record should always have more than one field, so the following statement 
 91		# should not raise exceptions
 92		return clstype(**objdic)
 93
 94
 95
 96class Choice(Openc2Type):
 97	""" OpenC2 Choice
 98		Implements the OpenC2 Choice:
 99		>One field selected from a set of named fields. The API value has a name and a type.
100
101		It expect all allowed values to be provided in a `Register` class, which must be defined
102		as class attribute `register` in all derived classes (see `Target` and `Actuator` as examples).
103	"""
104	register = None
105	""" List of registered name/class options available """
106
107	def __init__(self, obj):
108		""" Initialize the `Choice` object
109
110			Objects used as `Choice` must be registered in advance in the `register` dictionary.
111
112			:arg obj: An object among those defined in the `register`.
113		"""
114		self.choice: str = self.register.getName(obj.__class__)
115		""" Selected name for the `Choice` """
116		self.obj = obj
117		""" Class corresponding to the `choice` """
118
119	def getObj(self):
120		""" Returns the objet instance embedded in the `register`."""
121		return self.obj
122	
123	def getName(self):
124		"""Returns the name of the choice
125
126			Returns the name of object, which is the selector carried by the `Choice` element. 
127			This does not include the object itself.
128		"""
129		return self.choice
130
131	@classmethod
132	def getClass(cls, choice):
133		""" Get the class corresponding to the current `choice` 
134			
135			It may be implemented by any derived class, if a different logic than the `Register` class 
136			is followed to store the name/class bindings.
137			:param choice: The name of the alternative that is being looked for.
138			:return: The class corresponding to the provided `choice`.
139		"""
140		return cls.register.get(choice)
141
142	def __str__(self):
143		return self.choice
144
145	def __repr__(self):
146		return str(self.obj)
147
148	def todict(self, e):
149		""" Converts to dictionary 
150		
151			It is used to convert this object to an intermediary representation during 
152			serialization. It takes an `Encoder` argument that is used to recursively
153			serialize inner data and structures (the `Encoder` provides standard methods
154			for converting base types to dictionaries).. 
155
156			:param e: The `Encoder` that is being used.
157			:return: A dictionary compliants to the Language Specification's serialization
158			rules.
159		"""
160		# In case of Choice, the specific choice may be the implementation of an additional type,
161		# which affects its representation. So, first of all, get the representation of the inner
162		# data type
163		dic = {}
164		dic[self.choice] = e.todict(self.obj)
165		return dic
166
167	@classmethod
168	def fromdict(cls, dic, e):
169		""" Builds instance from dictionary 
170
171			It is used during deserialization to create an openc2lib instance from the text message.
172			It takes an `Encoder` instance that is used to recursively build instances of the inner
173			objects (the `Encoder` provides standard methods to create instances of base objects like
174			strings, integers, boolean).
175
176			:param dic: The intermediary dictionary representation from which the object is built.
177			:param e: The `Encoder that is being used.
178			:return: An instance of this class initialized from the dictionary values.
179		"""
180		if not len(dic) == 1:
181			raise ValueError("Unexpected dict: ", dic)
182
183		for k, v in dic.items():
184			# Expected to run one time only!
185			objtype = cls.getClass(k)
186			return cls(e.fromdict(objtype, v))
187
188class Enumerated(Openc2Type, aenum.Enum):
189	""" OpenC2 Enumerated
190
191		Implements OpenC2 Enumerated:
192		>A set of named integral constants. The API value is a name.
193
194		The constants may be anything, including strings, integers, classes.
195	"""
196
197	# Convert enumerations to str
198	def todict(self, e):
199		""" Converts to dictionary 
200		
201			It is used to convert this object to an intermediary representation during 
202			serialization. It takes an `Encoder` argument that is used to recursively
203			serialize inner data and structures (the `Encoder` provides standard methods
204			for converting base types to dictionaries).. 
205
206			:param e: The `Encoder` that is being used.
207			:return: A dictionary compliants to the Language Specification's serialization
208			rules.
209		"""
210		return self.name
211
212	@classmethod
213	def fromdict(cls, dic, e):
214		""" Builds instance from dictionary 
215
216			It is used during deserialization to create an openc2lib instance from the text message.
217			It takes an `Encoder` instance that is used to recursively build instances of the inner
218			objects (the `Encoder` provides standard methods to create instances of base objects like
219			strings, integers, boolean).
220
221			:param dic: The intermediary dictionary representation from which the object is built.
222			:param e: The `Encoder that is being used.
223			:return: An instance of this class initialized from the dictionary values.
224		"""
225		try:
226			return cls[str(dic)]
227		except:
228			raise TypeError("Unexpected enum value: ", dic)
229	
230# This class should check the names are integers.
231# The enum syntax only allows to define <str = int> pairs,
232# so to use this class it is necessary to define mnemonic label
233# TODO: Test this code
234class EnumeratedID(Enumerated):
235	""" OpenC2 EnumeratedID
236
237		Implements OpenC2 EnumeratedID: 
238		>A set of unnamed integral constants. The API value is an id.
239
240		The current implementation does not check the values to be integer.
241		However, coversion to/from integer is explicitly done during the
242		intermediary dictionary serialization, hence throwing an Exception if
243		the IDs are not integers.
244	"""
245
246	def todict(self, e):
247		""" Converts to dictionary 
248		
249			It is used to convert this object to an intermediary representation during 
250			serialization. It takes an `Encoder` argument that is used to recursively
251			serialize inner data and structures (the `Encoder` provides standard methods
252			for converting base types to dictionaries).. 
253
254			:param e: The `Encoder` that is being used.
255			:return: A dictionary compliants to the Language Specification's serialization
256			rules.
257		"""
258		return int(self.value)
259
260	@classmethod
261	def fromdict(cls, dic, e):
262		""" Builds instance from dictionary 
263
264			It is used during deserialization to create an openc2lib instance from the text message.
265			It takes an `Encoder` instance that is used to recursively build instances of the inner
266			objects (the `Encoder` provides standard methods to create instances of base objects like
267			strings, integers, boolean).
268
269			:param dic: The intermediary dictionary representation from which the object is built.
270			:param e: The `Encoder that is being used.
271			:return: An instance of this class initialized from the dictionary values.
272		"""
273		try:
274			return cls(int(dic))
275		except:
276			raise TypeError("Unexpected enum value: ", dic)
277
278class Array(Openc2Type, list):
279	""" OpenC2 Array
280
281		Implements OpenC2 Array:
282		>An ordered list of unnamed fields with positionally-defined semantics. 
283		Each field has a position, label, and type.
284
285		However, position does not matter in this implementation.
286
287		Derived classes must provide a `fieldtypes` dictionary that associate each field name
288		to its class. This is strictly required in order to instantiate the object at
289		deserialization time. However, no check is performed when new items are inserted.
290	"""
291	fieldtypes = None
292	""" Field types
293
294		A `dictionary` which keys are field names and which values are the corresponding classes.
295		Must be provided by any derived class.
296	"""
297
298	def todict(self, e):
299		""" Converts to dictionary 
300		
301			It is used to convert this object to an intermediary representation during 
302			serialization. It takes an `Encoder` argument that is used to recursively
303			serialize inner data and structures (the `Encoder` provides standard methods
304			for converting base types to dictionaries).. 
305
306			:param e: The `Encoder` that is being used.
307			:return: A dictionary compliants to the Language Specification's serialization
308			rules.
309		"""
310		lis = []
311		for i in self:
312			lis.append = e.todict(i)
313		return lis
314
315	def fromdict(cls, dic, e):
316		""" !!! WARNING !!!
317			Currently not implemented because there are no examples of usage of this
318			type (only Array/net, which is not clear)
319		"""
320		raise Exception("Function not implemented")
321
322class ArrayOf:
323	""" OpenC2 ArrayOf
324
325		Implements OpenC2 ArrayOf(*vtype*):
326		>An ordered list of fields with the same semantics. 
327		Each field has a position and type *vtype*.
328
329		It extends the `Array` type. However, to make its usage simpler and compliant 
330		to the description given in the
331		Language Specification, the implementation is quite different.
332		Note that in many cases `ArrayOf` is only used to create arrays without the need
333		to derive an additional data type.
334	"""
335
336	def __new__(self, fldtype):
337		""" `ArrayOf` builder
338
339			Creates a unnamed derived class from `Array`, which `fieldtypes` is set to `fldtype`.
340			:param fldtype: The type of the fields stored in the array (indicated as *vtype* in 
341					the Language Specification.
342			:return: A new unnamed class definition.
343		"""
344		class ArrayOf(Array):
345			""" OpenC2 unnamed `ArrayOf`
346
347				This class inherits from `Array` and sets its `fieldtypes` to a given type.
348		
349				One might like to check the type of the elements before inserting them.
350				However, this is not the Python-way. Python use the duck typing approach:
351				https://en.wikipedia.org/wiki/Duck_typing
352				We ask for the type of objects just to keep this information according to
353				the OpenC2 data model.
354
355				Note: no `todict()` method is provided, since `Array.todict()` is fine here.
356			"""
357			fieldtype = fldtype
358			""" The type of values stored in this container """
359
360			@classmethod
361			def fromdict(cls, lis, e):
362				""" Builds instance from dictionary 
363		
364					It is used during deserialization to create an openc2lib instance from the text message.
365					It takes an `Encoder` instance that is used to recursively build instances of the inner
366					objects (the `Encoder` provides standard methods to create instances of base objects like
367					strings, integers, boolean).
368		
369					:param lis: The intermediary dictionary representation from which the object is built.
370					:param e: The `Encoder that is being used.
371					:return: An instance of this class initialized from the dictionary values.
372				"""
373				objlis = cls()
374				logger.debug('Building %s from %s in ArrayOf', cls, lis)
375				logger.debug('-> instantiating: %s', cls.fieldtype)
376				for k in lis:
377					objlis.append(e.fromdict(cls.fieldtype, k))
378		
379				return objlis
380			
381			# This is the code if I would like to do type checking
382			# when inserting data
383#			def append(self, item):
384#				if isinstance(item, self.fieldtype):
385#					super().append(item)
386#				else:
387#					raise ValueError(self.fieldtype,' allowed only')
388#			
389#			def insert(self, index, item):
390#				if isinstance(item, self.fieldtype):
391#					super().insert(index, item)
392#				else:
393#					raise ValueError(self.fieldtype,' allowed only')
394#			
395#			def __add__(self, item):
396#				if isinstance(item, self.fieldtype):
397#					super().__add__(item)
398#				else:
399#					raise ValueError(self.fieldtype,' allowed only')
400#			
401#			def __iadd__(self, item):
402#				if isinstance(item, self.fieldtype):
403#					super().__iadd__(item)
404#				else:
405#					raise ValueError(self.fieldtype,' allowed only')
406
407		return ArrayOf
408
409
410class Map(Openc2Type, dict):
411	""" OpenC2 Map
412
413		Implements OpenC2 Map:
414		>An unordered map from a set of specified keys to values with semantics 
415			bound to each key. Each field has an id, name and type.
416
417		However, the id is not considered in this implementation.
418
419		The implementation follows a similar logic than `Array`. Each derived class
420		is expected to provide a `fieldtypes` class attribute that associate field names 
421		with their class definition. 
422		
423		Additionally, according to the Language Specification, `Map`s may be extended by
424		Profiles. Such extensions must use the `extend` and `regext` class attributes to 
425		bind to the base element they extend and the `Profile` in which they are defined.
426	"""
427	fieldtypes: dict = None
428	""" Field types
429
430		A `dictionary` which keys are field names and which values are the corresponding classes.
431		Must be provided by any derived class.
432	"""
433	extend = None
434	""" Base class
435
436		Data types defined in the Language Specification shall not set this field. Data types defined in
437		Profiles that extends a Data Type defined in the Language Specification, must set this field to
438		the corresponding class of the base Data Type.
439
440		Note: Extensions defined in the openc2lib context are recommended to use the same name of the base
441		Data Type, and to distinguish them through appropriate usage of the namespacing mechanism.
442	"""
443	regext = {}
444	""" Registered extensions
445
446		Classes that implement a Data Type defined in the Language Specification will use this field to
447		register extensions defined by external Profiles. Classes that define extensions within Profiles
448		shall register themselves according to the specific documentation of the base type class, but 
449		shall not modify this field.
450	"""
451
452	def todict(self, e):
453		""" Converts to dictionary 
454		
455			It is used to convert this object to an intermediary representation during 
456			serialization. It takes an `Encoder` argument that is used to recursively
457			serialize inner data and structures (the `Encoder` provides standard methods
458			for converting base types to dictionaries).. 
459
460			:param e: The `Encoder` that is being used.
461			:return: A dictionary compliants to the Language Specification's serialization
462			rules.
463		"""
464		newdic=dict()
465
466		# This is necessary because self.extend.fieldtypes does
467		# not exist for non-extended classes
468		if self.extend is None:
469			return e.todict(dict(self))
470			
471		for k,v in self.items():
472			if k not in self.fieldtypes:
473				raise ValueError('Unknown field: ', k)
474			if k in self.extend.fieldtypes:
475				newdic[k] = v
476			else:
477				if self.nsid not in newdic:
478					newdic[self.nsid]={}
479				newdic[self.nsid][k]=v
480			
481		return e.todict(newdic)
482
483	@classmethod
484	def fromdict(cls, dic, e):
485		""" Builds instance from dictionary 
486
487			It is used during deserialization to create an openc2lib instance from the text message.
488			It takes an `Encoder` instance that is used to recursively build instances of the inner
489			objects (the `Encoder` provides standard methods to create instances of base objects like
490			strings, integers, boolean).
491
492			:param dic: The intermediary dictionary representation from which the object is built.
493			:param e: The `Encoder that is being used.
494			:return: An instance of this class initialized from the dictionary values.
495		"""
496		objdic = {}
497		extension = None
498		logger.debug('Building %s from %s in Map', cls, dic)
499		for k,v in dic.items():
500			if k in cls.fieldtypes:
501				objdic[k] = e.fromdict(cls.fieldtypes[k], v)
502			elif k in cls.regext:
503				logger.debug('   Using profile %s to decode: %s', k, v)
504				extension = cls.regext[k]
505				for l,w in v.items():
506					objdic[l] = e.fromdict(extension.fieldtypes[l], w)
507			else:
508				raise TypeError("Unexpected field: ", k)
509
510		if extension is not None:
511			cls = extension
512
513		return cls(objdic)
514
515class MapOf:
516	""" OpenC2 MapOf
517
518		Implements OpenC2 MapOf(*ktype, vtype*):
519		>An unordered set of keys to values with the same semantics. 
520			Each key has key type *ktype* and is mapped to value type *vtype*.
521
522		It extends `Map` with the same approach already used for `ArrayOf`.
523		`MapOf` for specific types are created as anonymous classes by passing
524		`ktype` and `vtype` as arguments.
525
526		Note: `MapOf` implementation currently does not support extensins!.
527	"""
528
529	def __new__(self,ktype, vtype):
530		""" `MapOf` builder
531
532			Creates a unnamed derived class from `Map`, which `fieldtypes` is set to a single value
533		 	`ktype: vtype`.
534			:param ktype: The key type of the items stored in the map.
535			:param vtype: The value type of the items stored in the map.
536			:return: A new unnamed class definition.
537		"""
538		class MapOf(Map):
539			""" OpenC2 unnamed `MapOf`
540
541				This class inherits from `Map` and sets its `fieldtypes` to a given type.
542		
543				Note: no `todict()` method is provided, since `Map.todict()` is fine here.
544			"""
545			fieldtypes = {ktype: vtype}
546			""" The type of values stored in this container """
547
548			@classmethod
549			def fromdict(cls, dic, e):
550				""" Builds instance from dictionary 
551		
552					It is used during deserialization to create an openc2lib instance from the text message.
553					It takes an `Encoder` instance that is used to recursively build instances of the inner
554					objects (the `Encoder` provides standard methods to create instances of base objects like
555					strings, integers, boolean).
556		
557					:param dic: The intermediary dictionary representation from which the object is built.
558					:param e: The `Encoder that is being used.
559					:return: An instance of this class initialized from the dictionary values.
560				"""
561				objdic = {}
562				logger.debug('Building %s from %s in MapOf', cls, dic)
563				for k,v in dic.items():
564					kclass = list(cls.fieldtypes)[0]
565					objk = e.fromdict(kclass, k)
566					objdic[objk] = e.fromdict(cls.fieldtypes[kclass], v)
567				return objdic
568
569		return MapOf
logger = <Logger openc2lib (WARNING)>

openc2lib logger

class Openc2Type:
18class Openc2Type():
19	""" OpenC2 Language Element
20		
21		This class is currently unused and is only provided to have a common ancestor for all
22		OpenC2 basic types. It may be used in the future to implement common methods or arguments.
23	"""
24	pass

OpenC2 Language Element

This class is currently unused and is only provided to have a common ancestor for all OpenC2 basic types. It may be used in the future to implement common methods or arguments.

class Record(Openc2Type):
28class Record(Openc2Type):
29	""" OpenC2 Record
30
31		Implements OpenC2 Record: 
32			>An ordered map from a list of keys with positions to values with 
33			positionally-defined semantics. Each key has a position and name, 
34			and is mapped to a type.
35
36		It expect keys to be public class attributes. All internal attributes 
37		must be kept private by prefixing it with an '_'.
38
39	"""
40	def todict(self, e):
41		""" Converts to dictionary 
42		
43			It is used to convert this object to an intermediary representation during 
44			serialization. It takes an `Encoder` argument that is used to recursively
45			serialize inner data and structures (the `Encoder` provides standard methods
46			for converting base types to dictionaries).. 
47
48			:param e: The `Encoder` that is being used.
49			:return: A dictionary compliants to the Language Specification's serialization
50			rules.
51		"""
52		objdic = vars(self)
53
54		dic = {}
55		for k,v in objdic.items():
56			# Fix keywords corresponding to variable names that clash with Python keywords
57			if isinstance(k, str) and k.endswith('_'):
58				k = k.rstrip('_')
59			# Remove empty and private elements; do not include non-string keys
60			if not v is None and not k.startswith('_') and isinstance(k, str):
61				dic[k] = v	
62
63		return e.todict(dic)
64
65	@classmethod
66	def fromdict(clstype, dic, e):
67		""" Builds instance from dictionary 
68
69			It is used during deserialization to create an openc2lib instance from the text message.
70			It takes an `Encoder` instance that is used to recursively build instances of the inner
71			objects (the `Encoder` provides standard methods to create instances of base objects like
72			strings, integers, boolean).
73
74			:param dic: The intermediary dictionary representation from which the object is built.
75			:param e: The `Encoder that is being used.
76			:return: An instance of this class initialized from the dictionary values.
77		"""
78		objdic = {}
79		# Retrieve class type for each field in the dictionary
80		fielddesc = None
81		for tpl in inspect.getmembers(clstype):
82			if tpl[0] == '__annotations__':
83				fielddesc = tpl[1]
84
85		for k,v in dic.items():
86			if k not in fielddesc:
87				raise Exception("Unknown field '" + k + "' from message")
88			objdic[k] = e.fromdict(fielddesc[k], v)
89
90
91		# A record should always have more than one field, so the following statement 
92		# should not raise exceptions
93		return clstype(**objdic)

OpenC2 Record

Implements OpenC2 Record:

An ordered map from a list of keys with positions to values with positionally-defined semantics. Each key has a position and name, and is mapped to a type.

It expect keys to be public class attributes. All internal attributes must be kept private by prefixing it with an '_'.

def todict(self, e):
40	def todict(self, e):
41		""" Converts to dictionary 
42		
43			It is used to convert this object to an intermediary representation during 
44			serialization. It takes an `Encoder` argument that is used to recursively
45			serialize inner data and structures (the `Encoder` provides standard methods
46			for converting base types to dictionaries).. 
47
48			:param e: The `Encoder` that is being used.
49			:return: A dictionary compliants to the Language Specification's serialization
50			rules.
51		"""
52		objdic = vars(self)
53
54		dic = {}
55		for k,v in objdic.items():
56			# Fix keywords corresponding to variable names that clash with Python keywords
57			if isinstance(k, str) and k.endswith('_'):
58				k = k.rstrip('_')
59			# Remove empty and private elements; do not include non-string keys
60			if not v is None and not k.startswith('_') and isinstance(k, str):
61				dic[k] = v	
62
63		return e.todict(dic)

Converts to dictionary

It is used to convert this object to an intermediary representation during serialization. It takes an Encoder argument that is used to recursively serialize inner data and structures (the Encoder provides standard methods for converting base types to dictionaries)..

Parameters
  • e: The Encoder that is being used.
Returns

A dictionary compliants to the Language Specification's serialization rules.

@classmethod
def fromdict(clstype, dic, e):
65	@classmethod
66	def fromdict(clstype, dic, e):
67		""" Builds instance from dictionary 
68
69			It is used during deserialization to create an openc2lib instance from the text message.
70			It takes an `Encoder` instance that is used to recursively build instances of the inner
71			objects (the `Encoder` provides standard methods to create instances of base objects like
72			strings, integers, boolean).
73
74			:param dic: The intermediary dictionary representation from which the object is built.
75			:param e: The `Encoder that is being used.
76			:return: An instance of this class initialized from the dictionary values.
77		"""
78		objdic = {}
79		# Retrieve class type for each field in the dictionary
80		fielddesc = None
81		for tpl in inspect.getmembers(clstype):
82			if tpl[0] == '__annotations__':
83				fielddesc = tpl[1]
84
85		for k,v in dic.items():
86			if k not in fielddesc:
87				raise Exception("Unknown field '" + k + "' from message")
88			objdic[k] = e.fromdict(fielddesc[k], v)
89
90
91		# A record should always have more than one field, so the following statement 
92		# should not raise exceptions
93		return clstype(**objdic)

Builds instance from dictionary

It is used during deserialization to create an openc2lib instance from the text message. It takes an Encoder instance that is used to recursively build instances of the inner objects (the Encoder provides standard methods to create instances of base objects like strings, integers, boolean).

Parameters
  • dic: The intermediary dictionary representation from which the object is built.
  • e: The `Encoder that is being used.
Returns

An instance of this class initialized from the dictionary values.

class Choice(Openc2Type):
 97class Choice(Openc2Type):
 98	""" OpenC2 Choice
 99		Implements the OpenC2 Choice:
100		>One field selected from a set of named fields. The API value has a name and a type.
101
102		It expect all allowed values to be provided in a `Register` class, which must be defined
103		as class attribute `register` in all derived classes (see `Target` and `Actuator` as examples).
104	"""
105	register = None
106	""" List of registered name/class options available """
107
108	def __init__(self, obj):
109		""" Initialize the `Choice` object
110
111			Objects used as `Choice` must be registered in advance in the `register` dictionary.
112
113			:arg obj: An object among those defined in the `register`.
114		"""
115		self.choice: str = self.register.getName(obj.__class__)
116		""" Selected name for the `Choice` """
117		self.obj = obj
118		""" Class corresponding to the `choice` """
119
120	def getObj(self):
121		""" Returns the objet instance embedded in the `register`."""
122		return self.obj
123	
124	def getName(self):
125		"""Returns the name of the choice
126
127			Returns the name of object, which is the selector carried by the `Choice` element. 
128			This does not include the object itself.
129		"""
130		return self.choice
131
132	@classmethod
133	def getClass(cls, choice):
134		""" Get the class corresponding to the current `choice` 
135			
136			It may be implemented by any derived class, if a different logic than the `Register` class 
137			is followed to store the name/class bindings.
138			:param choice: The name of the alternative that is being looked for.
139			:return: The class corresponding to the provided `choice`.
140		"""
141		return cls.register.get(choice)
142
143	def __str__(self):
144		return self.choice
145
146	def __repr__(self):
147		return str(self.obj)
148
149	def todict(self, e):
150		""" Converts to dictionary 
151		
152			It is used to convert this object to an intermediary representation during 
153			serialization. It takes an `Encoder` argument that is used to recursively
154			serialize inner data and structures (the `Encoder` provides standard methods
155			for converting base types to dictionaries).. 
156
157			:param e: The `Encoder` that is being used.
158			:return: A dictionary compliants to the Language Specification's serialization
159			rules.
160		"""
161		# In case of Choice, the specific choice may be the implementation of an additional type,
162		# which affects its representation. So, first of all, get the representation of the inner
163		# data type
164		dic = {}
165		dic[self.choice] = e.todict(self.obj)
166		return dic
167
168	@classmethod
169	def fromdict(cls, dic, e):
170		""" Builds instance from dictionary 
171
172			It is used during deserialization to create an openc2lib instance from the text message.
173			It takes an `Encoder` instance that is used to recursively build instances of the inner
174			objects (the `Encoder` provides standard methods to create instances of base objects like
175			strings, integers, boolean).
176
177			:param dic: The intermediary dictionary representation from which the object is built.
178			:param e: The `Encoder that is being used.
179			:return: An instance of this class initialized from the dictionary values.
180		"""
181		if not len(dic) == 1:
182			raise ValueError("Unexpected dict: ", dic)
183
184		for k, v in dic.items():
185			# Expected to run one time only!
186			objtype = cls.getClass(k)
187			return cls(e.fromdict(objtype, v))

OpenC2 Choice Implements the OpenC2 Choice:

One field selected from a set of named fields. The API value has a name and a type.

It expect all allowed values to be provided in a Register class, which must be defined as class attribute register in all derived classes (see Target and Actuator as examples).

Choice(obj)
108	def __init__(self, obj):
109		""" Initialize the `Choice` object
110
111			Objects used as `Choice` must be registered in advance in the `register` dictionary.
112
113			:arg obj: An object among those defined in the `register`.
114		"""
115		self.choice: str = self.register.getName(obj.__class__)
116		""" Selected name for the `Choice` """
117		self.obj = obj
118		""" Class corresponding to the `choice` """

Initialize the Choice object

Objects used as Choice must be registered in advance in the register dictionary.

:arg obj: An object among those defined in the register.

register = None

List of registered name/class options available

choice: str

Selected name for the Choice

obj

Class corresponding to the choice

def getObj(self):
120	def getObj(self):
121		""" Returns the objet instance embedded in the `register`."""
122		return self.obj

Returns the objet instance embedded in the register.

def getName(self):
124	def getName(self):
125		"""Returns the name of the choice
126
127			Returns the name of object, which is the selector carried by the `Choice` element. 
128			This does not include the object itself.
129		"""
130		return self.choice

Returns the name of the choice

Returns the name of object, which is the selector carried by the Choice element. This does not include the object itself.

@classmethod
def getClass(cls, choice):
132	@classmethod
133	def getClass(cls, choice):
134		""" Get the class corresponding to the current `choice` 
135			
136			It may be implemented by any derived class, if a different logic than the `Register` class 
137			is followed to store the name/class bindings.
138			:param choice: The name of the alternative that is being looked for.
139			:return: The class corresponding to the provided `choice`.
140		"""
141		return cls.register.get(choice)

Get the class corresponding to the current choice

It may be implemented by any derived class, if a different logic than the Register class is followed to store the name/class bindings.

Parameters
  • choice: The name of the alternative that is being looked for.
Returns

The class corresponding to the provided choice.

def todict(self, e):
149	def todict(self, e):
150		""" Converts to dictionary 
151		
152			It is used to convert this object to an intermediary representation during 
153			serialization. It takes an `Encoder` argument that is used to recursively
154			serialize inner data and structures (the `Encoder` provides standard methods
155			for converting base types to dictionaries).. 
156
157			:param e: The `Encoder` that is being used.
158			:return: A dictionary compliants to the Language Specification's serialization
159			rules.
160		"""
161		# In case of Choice, the specific choice may be the implementation of an additional type,
162		# which affects its representation. So, first of all, get the representation of the inner
163		# data type
164		dic = {}
165		dic[self.choice] = e.todict(self.obj)
166		return dic

Converts to dictionary

It is used to convert this object to an intermediary representation during serialization. It takes an Encoder argument that is used to recursively serialize inner data and structures (the Encoder provides standard methods for converting base types to dictionaries)..

Parameters
  • e: The Encoder that is being used.
Returns

A dictionary compliants to the Language Specification's serialization rules.

@classmethod
def fromdict(cls, dic, e):
168	@classmethod
169	def fromdict(cls, dic, e):
170		""" Builds instance from dictionary 
171
172			It is used during deserialization to create an openc2lib instance from the text message.
173			It takes an `Encoder` instance that is used to recursively build instances of the inner
174			objects (the `Encoder` provides standard methods to create instances of base objects like
175			strings, integers, boolean).
176
177			:param dic: The intermediary dictionary representation from which the object is built.
178			:param e: The `Encoder that is being used.
179			:return: An instance of this class initialized from the dictionary values.
180		"""
181		if not len(dic) == 1:
182			raise ValueError("Unexpected dict: ", dic)
183
184		for k, v in dic.items():
185			# Expected to run one time only!
186			objtype = cls.getClass(k)
187			return cls(e.fromdict(objtype, v))

Builds instance from dictionary

It is used during deserialization to create an openc2lib instance from the text message. It takes an Encoder instance that is used to recursively build instances of the inner objects (the Encoder provides standard methods to create instances of base objects like strings, integers, boolean).

Parameters
  • dic: The intermediary dictionary representation from which the object is built.
  • e: The `Encoder that is being used.
Returns

An instance of this class initialized from the dictionary values.

class Enumerated(Openc2Type, aenum._enum.Enum):
189class Enumerated(Openc2Type, aenum.Enum):
190	""" OpenC2 Enumerated
191
192		Implements OpenC2 Enumerated:
193		>A set of named integral constants. The API value is a name.
194
195		The constants may be anything, including strings, integers, classes.
196	"""
197
198	# Convert enumerations to str
199	def todict(self, e):
200		""" Converts to dictionary 
201		
202			It is used to convert this object to an intermediary representation during 
203			serialization. It takes an `Encoder` argument that is used to recursively
204			serialize inner data and structures (the `Encoder` provides standard methods
205			for converting base types to dictionaries).. 
206
207			:param e: The `Encoder` that is being used.
208			:return: A dictionary compliants to the Language Specification's serialization
209			rules.
210		"""
211		return self.name
212
213	@classmethod
214	def fromdict(cls, dic, e):
215		""" Builds instance from dictionary 
216
217			It is used during deserialization to create an openc2lib instance from the text message.
218			It takes an `Encoder` instance that is used to recursively build instances of the inner
219			objects (the `Encoder` provides standard methods to create instances of base objects like
220			strings, integers, boolean).
221
222			:param dic: The intermediary dictionary representation from which the object is built.
223			:param e: The `Encoder that is being used.
224			:return: An instance of this class initialized from the dictionary values.
225		"""
226		try:
227			return cls[str(dic)]
228		except:
229			raise TypeError("Unexpected enum value: ", dic)

OpenC2 Enumerated

Implements OpenC2 Enumerated:

A set of named integral constants. The API value is a name.

The constants may be anything, including strings, integers, classes.

def todict(self, e):
199	def todict(self, e):
200		""" Converts to dictionary 
201		
202			It is used to convert this object to an intermediary representation during 
203			serialization. It takes an `Encoder` argument that is used to recursively
204			serialize inner data and structures (the `Encoder` provides standard methods
205			for converting base types to dictionaries).. 
206
207			:param e: The `Encoder` that is being used.
208			:return: A dictionary compliants to the Language Specification's serialization
209			rules.
210		"""
211		return self.name

Converts to dictionary

It is used to convert this object to an intermediary representation during serialization. It takes an Encoder argument that is used to recursively serialize inner data and structures (the Encoder provides standard methods for converting base types to dictionaries)..

Parameters
  • e: The Encoder that is being used.
Returns

A dictionary compliants to the Language Specification's serialization rules.

@classmethod
def fromdict(cls, dic, e):
213	@classmethod
214	def fromdict(cls, dic, e):
215		""" Builds instance from dictionary 
216
217			It is used during deserialization to create an openc2lib instance from the text message.
218			It takes an `Encoder` instance that is used to recursively build instances of the inner
219			objects (the `Encoder` provides standard methods to create instances of base objects like
220			strings, integers, boolean).
221
222			:param dic: The intermediary dictionary representation from which the object is built.
223			:param e: The `Encoder that is being used.
224			:return: An instance of this class initialized from the dictionary values.
225		"""
226		try:
227			return cls[str(dic)]
228		except:
229			raise TypeError("Unexpected enum value: ", dic)

Builds instance from dictionary

It is used during deserialization to create an openc2lib instance from the text message. It takes an Encoder instance that is used to recursively build instances of the inner objects (the Encoder provides standard methods to create instances of base objects like strings, integers, boolean).

Parameters
  • dic: The intermediary dictionary representation from which the object is built.
  • e: The `Encoder that is being used.
Returns

An instance of this class initialized from the dictionary values.

Inherited Members
aenum._enum.Enum
name
value
values
class EnumeratedID(Enumerated):
235class EnumeratedID(Enumerated):
236	""" OpenC2 EnumeratedID
237
238		Implements OpenC2 EnumeratedID: 
239		>A set of unnamed integral constants. The API value is an id.
240
241		The current implementation does not check the values to be integer.
242		However, coversion to/from integer is explicitly done during the
243		intermediary dictionary serialization, hence throwing an Exception if
244		the IDs are not integers.
245	"""
246
247	def todict(self, e):
248		""" Converts to dictionary 
249		
250			It is used to convert this object to an intermediary representation during 
251			serialization. It takes an `Encoder` argument that is used to recursively
252			serialize inner data and structures (the `Encoder` provides standard methods
253			for converting base types to dictionaries).. 
254
255			:param e: The `Encoder` that is being used.
256			:return: A dictionary compliants to the Language Specification's serialization
257			rules.
258		"""
259		return int(self.value)
260
261	@classmethod
262	def fromdict(cls, dic, e):
263		""" Builds instance from dictionary 
264
265			It is used during deserialization to create an openc2lib instance from the text message.
266			It takes an `Encoder` instance that is used to recursively build instances of the inner
267			objects (the `Encoder` provides standard methods to create instances of base objects like
268			strings, integers, boolean).
269
270			:param dic: The intermediary dictionary representation from which the object is built.
271			:param e: The `Encoder that is being used.
272			:return: An instance of this class initialized from the dictionary values.
273		"""
274		try:
275			return cls(int(dic))
276		except:
277			raise TypeError("Unexpected enum value: ", dic)

OpenC2 EnumeratedID

Implements OpenC2 EnumeratedID:

A set of unnamed integral constants. The API value is an id.

The current implementation does not check the values to be integer. However, coversion to/from integer is explicitly done during the intermediary dictionary serialization, hence throwing an Exception if the IDs are not integers.

def todict(self, e):
247	def todict(self, e):
248		""" Converts to dictionary 
249		
250			It is used to convert this object to an intermediary representation during 
251			serialization. It takes an `Encoder` argument that is used to recursively
252			serialize inner data and structures (the `Encoder` provides standard methods
253			for converting base types to dictionaries).. 
254
255			:param e: The `Encoder` that is being used.
256			:return: A dictionary compliants to the Language Specification's serialization
257			rules.
258		"""
259		return int(self.value)

Converts to dictionary

It is used to convert this object to an intermediary representation during serialization. It takes an Encoder argument that is used to recursively serialize inner data and structures (the Encoder provides standard methods for converting base types to dictionaries)..

Parameters
  • e: The Encoder that is being used.
Returns

A dictionary compliants to the Language Specification's serialization rules.

@classmethod
def fromdict(cls, dic, e):
261	@classmethod
262	def fromdict(cls, dic, e):
263		""" Builds instance from dictionary 
264
265			It is used during deserialization to create an openc2lib instance from the text message.
266			It takes an `Encoder` instance that is used to recursively build instances of the inner
267			objects (the `Encoder` provides standard methods to create instances of base objects like
268			strings, integers, boolean).
269
270			:param dic: The intermediary dictionary representation from which the object is built.
271			:param e: The `Encoder that is being used.
272			:return: An instance of this class initialized from the dictionary values.
273		"""
274		try:
275			return cls(int(dic))
276		except:
277			raise TypeError("Unexpected enum value: ", dic)

Builds instance from dictionary

It is used during deserialization to create an openc2lib instance from the text message. It takes an Encoder instance that is used to recursively build instances of the inner objects (the Encoder provides standard methods to create instances of base objects like strings, integers, boolean).

Parameters
  • dic: The intermediary dictionary representation from which the object is built.
  • e: The `Encoder that is being used.
Returns

An instance of this class initialized from the dictionary values.

Inherited Members
aenum._enum.Enum
name
value
values
class Array(Openc2Type, builtins.list):
279class Array(Openc2Type, list):
280	""" OpenC2 Array
281
282		Implements OpenC2 Array:
283		>An ordered list of unnamed fields with positionally-defined semantics. 
284		Each field has a position, label, and type.
285
286		However, position does not matter in this implementation.
287
288		Derived classes must provide a `fieldtypes` dictionary that associate each field name
289		to its class. This is strictly required in order to instantiate the object at
290		deserialization time. However, no check is performed when new items are inserted.
291	"""
292	fieldtypes = None
293	""" Field types
294
295		A `dictionary` which keys are field names and which values are the corresponding classes.
296		Must be provided by any derived class.
297	"""
298
299	def todict(self, e):
300		""" Converts to dictionary 
301		
302			It is used to convert this object to an intermediary representation during 
303			serialization. It takes an `Encoder` argument that is used to recursively
304			serialize inner data and structures (the `Encoder` provides standard methods
305			for converting base types to dictionaries).. 
306
307			:param e: The `Encoder` that is being used.
308			:return: A dictionary compliants to the Language Specification's serialization
309			rules.
310		"""
311		lis = []
312		for i in self:
313			lis.append = e.todict(i)
314		return lis
315
316	def fromdict(cls, dic, e):
317		""" !!! WARNING !!!
318			Currently not implemented because there are no examples of usage of this
319			type (only Array/net, which is not clear)
320		"""
321		raise Exception("Function not implemented")

OpenC2 Array

Implements OpenC2 Array:

An ordered list of unnamed fields with positionally-defined semantics. Each field has a position, label, and type.

However, position does not matter in this implementation.

Derived classes must provide a fieldtypes dictionary that associate each field name to its class. This is strictly required in order to instantiate the object at deserialization time. However, no check is performed when new items are inserted.

fieldtypes = None

Field types

A dictionary which keys are field names and which values are the corresponding classes. Must be provided by any derived class.

def todict(self, e):
299	def todict(self, e):
300		""" Converts to dictionary 
301		
302			It is used to convert this object to an intermediary representation during 
303			serialization. It takes an `Encoder` argument that is used to recursively
304			serialize inner data and structures (the `Encoder` provides standard methods
305			for converting base types to dictionaries).. 
306
307			:param e: The `Encoder` that is being used.
308			:return: A dictionary compliants to the Language Specification's serialization
309			rules.
310		"""
311		lis = []
312		for i in self:
313			lis.append = e.todict(i)
314		return lis

Converts to dictionary

It is used to convert this object to an intermediary representation during serialization. It takes an Encoder argument that is used to recursively serialize inner data and structures (the Encoder provides standard methods for converting base types to dictionaries)..

Parameters
  • e: The Encoder that is being used.
Returns

A dictionary compliants to the Language Specification's serialization rules.

def fromdict(cls, dic, e):
316	def fromdict(cls, dic, e):
317		""" !!! WARNING !!!
318			Currently not implemented because there are no examples of usage of this
319			type (only Array/net, which is not clear)
320		"""
321		raise Exception("Function not implemented")

!!! WARNING !!! Currently not implemented because there are no examples of usage of this type (only Array/net, which is not clear)

Inherited Members
builtins.list
list
clear
copy
append
insert
extend
pop
remove
index
count
reverse
sort
class ArrayOf:
323class ArrayOf:
324	""" OpenC2 ArrayOf
325
326		Implements OpenC2 ArrayOf(*vtype*):
327		>An ordered list of fields with the same semantics. 
328		Each field has a position and type *vtype*.
329
330		It extends the `Array` type. However, to make its usage simpler and compliant 
331		to the description given in the
332		Language Specification, the implementation is quite different.
333		Note that in many cases `ArrayOf` is only used to create arrays without the need
334		to derive an additional data type.
335	"""
336
337	def __new__(self, fldtype):
338		""" `ArrayOf` builder
339
340			Creates a unnamed derived class from `Array`, which `fieldtypes` is set to `fldtype`.
341			:param fldtype: The type of the fields stored in the array (indicated as *vtype* in 
342					the Language Specification.
343			:return: A new unnamed class definition.
344		"""
345		class ArrayOf(Array):
346			""" OpenC2 unnamed `ArrayOf`
347
348				This class inherits from `Array` and sets its `fieldtypes` to a given type.
349		
350				One might like to check the type of the elements before inserting them.
351				However, this is not the Python-way. Python use the duck typing approach:
352				https://en.wikipedia.org/wiki/Duck_typing
353				We ask for the type of objects just to keep this information according to
354				the OpenC2 data model.
355
356				Note: no `todict()` method is provided, since `Array.todict()` is fine here.
357			"""
358			fieldtype = fldtype
359			""" The type of values stored in this container """
360
361			@classmethod
362			def fromdict(cls, lis, e):
363				""" Builds instance from dictionary 
364		
365					It is used during deserialization to create an openc2lib instance from the text message.
366					It takes an `Encoder` instance that is used to recursively build instances of the inner
367					objects (the `Encoder` provides standard methods to create instances of base objects like
368					strings, integers, boolean).
369		
370					:param lis: The intermediary dictionary representation from which the object is built.
371					:param e: The `Encoder that is being used.
372					:return: An instance of this class initialized from the dictionary values.
373				"""
374				objlis = cls()
375				logger.debug('Building %s from %s in ArrayOf', cls, lis)
376				logger.debug('-> instantiating: %s', cls.fieldtype)
377				for k in lis:
378					objlis.append(e.fromdict(cls.fieldtype, k))
379		
380				return objlis
381			
382			# This is the code if I would like to do type checking
383			# when inserting data
384#			def append(self, item):
385#				if isinstance(item, self.fieldtype):
386#					super().append(item)
387#				else:
388#					raise ValueError(self.fieldtype,' allowed only')
389#			
390#			def insert(self, index, item):
391#				if isinstance(item, self.fieldtype):
392#					super().insert(index, item)
393#				else:
394#					raise ValueError(self.fieldtype,' allowed only')
395#			
396#			def __add__(self, item):
397#				if isinstance(item, self.fieldtype):
398#					super().__add__(item)
399#				else:
400#					raise ValueError(self.fieldtype,' allowed only')
401#			
402#			def __iadd__(self, item):
403#				if isinstance(item, self.fieldtype):
404#					super().__iadd__(item)
405#				else:
406#					raise ValueError(self.fieldtype,' allowed only')
407
408		return ArrayOf

OpenC2 ArrayOf

Implements OpenC2 ArrayOf(vtype):

An ordered list of fields with the same semantics. Each field has a position and type vtype.

It extends the Array type. However, to make its usage simpler and compliant to the description given in the Language Specification, the implementation is quite different. Note that in many cases ArrayOf is only used to create arrays without the need to derive an additional data type.

ArrayOf(fldtype)
337	def __new__(self, fldtype):
338		""" `ArrayOf` builder
339
340			Creates a unnamed derived class from `Array`, which `fieldtypes` is set to `fldtype`.
341			:param fldtype: The type of the fields stored in the array (indicated as *vtype* in 
342					the Language Specification.
343			:return: A new unnamed class definition.
344		"""
345		class ArrayOf(Array):
346			""" OpenC2 unnamed `ArrayOf`
347
348				This class inherits from `Array` and sets its `fieldtypes` to a given type.
349		
350				One might like to check the type of the elements before inserting them.
351				However, this is not the Python-way. Python use the duck typing approach:
352				https://en.wikipedia.org/wiki/Duck_typing
353				We ask for the type of objects just to keep this information according to
354				the OpenC2 data model.
355
356				Note: no `todict()` method is provided, since `Array.todict()` is fine here.
357			"""
358			fieldtype = fldtype
359			""" The type of values stored in this container """
360
361			@classmethod
362			def fromdict(cls, lis, e):
363				""" Builds instance from dictionary 
364		
365					It is used during deserialization to create an openc2lib instance from the text message.
366					It takes an `Encoder` instance that is used to recursively build instances of the inner
367					objects (the `Encoder` provides standard methods to create instances of base objects like
368					strings, integers, boolean).
369		
370					:param lis: The intermediary dictionary representation from which the object is built.
371					:param e: The `Encoder that is being used.
372					:return: An instance of this class initialized from the dictionary values.
373				"""
374				objlis = cls()
375				logger.debug('Building %s from %s in ArrayOf', cls, lis)
376				logger.debug('-> instantiating: %s', cls.fieldtype)
377				for k in lis:
378					objlis.append(e.fromdict(cls.fieldtype, k))
379		
380				return objlis
381			
382			# This is the code if I would like to do type checking
383			# when inserting data
384#			def append(self, item):
385#				if isinstance(item, self.fieldtype):
386#					super().append(item)
387#				else:
388#					raise ValueError(self.fieldtype,' allowed only')
389#			
390#			def insert(self, index, item):
391#				if isinstance(item, self.fieldtype):
392#					super().insert(index, item)
393#				else:
394#					raise ValueError(self.fieldtype,' allowed only')
395#			
396#			def __add__(self, item):
397#				if isinstance(item, self.fieldtype):
398#					super().__add__(item)
399#				else:
400#					raise ValueError(self.fieldtype,' allowed only')
401#			
402#			def __iadd__(self, item):
403#				if isinstance(item, self.fieldtype):
404#					super().__iadd__(item)
405#				else:
406#					raise ValueError(self.fieldtype,' allowed only')
407
408		return ArrayOf

ArrayOf builder

Creates a unnamed derived class from Array, which fieldtypes is set to fldtype.

Parameters
  • fldtype: The type of the fields stored in the array (indicated as vtype in the Language Specification.
Returns

A new unnamed class definition.

class Map(Openc2Type, builtins.dict):
411class Map(Openc2Type, dict):
412	""" OpenC2 Map
413
414		Implements OpenC2 Map:
415		>An unordered map from a set of specified keys to values with semantics 
416			bound to each key. Each field has an id, name and type.
417
418		However, the id is not considered in this implementation.
419
420		The implementation follows a similar logic than `Array`. Each derived class
421		is expected to provide a `fieldtypes` class attribute that associate field names 
422		with their class definition. 
423		
424		Additionally, according to the Language Specification, `Map`s may be extended by
425		Profiles. Such extensions must use the `extend` and `regext` class attributes to 
426		bind to the base element they extend and the `Profile` in which they are defined.
427	"""
428	fieldtypes: dict = None
429	""" Field types
430
431		A `dictionary` which keys are field names and which values are the corresponding classes.
432		Must be provided by any derived class.
433	"""
434	extend = None
435	""" Base class
436
437		Data types defined in the Language Specification shall not set this field. Data types defined in
438		Profiles that extends a Data Type defined in the Language Specification, must set this field to
439		the corresponding class of the base Data Type.
440
441		Note: Extensions defined in the openc2lib context are recommended to use the same name of the base
442		Data Type, and to distinguish them through appropriate usage of the namespacing mechanism.
443	"""
444	regext = {}
445	""" Registered extensions
446
447		Classes that implement a Data Type defined in the Language Specification will use this field to
448		register extensions defined by external Profiles. Classes that define extensions within Profiles
449		shall register themselves according to the specific documentation of the base type class, but 
450		shall not modify this field.
451	"""
452
453	def todict(self, e):
454		""" Converts to dictionary 
455		
456			It is used to convert this object to an intermediary representation during 
457			serialization. It takes an `Encoder` argument that is used to recursively
458			serialize inner data and structures (the `Encoder` provides standard methods
459			for converting base types to dictionaries).. 
460
461			:param e: The `Encoder` that is being used.
462			:return: A dictionary compliants to the Language Specification's serialization
463			rules.
464		"""
465		newdic=dict()
466
467		# This is necessary because self.extend.fieldtypes does
468		# not exist for non-extended classes
469		if self.extend is None:
470			return e.todict(dict(self))
471			
472		for k,v in self.items():
473			if k not in self.fieldtypes:
474				raise ValueError('Unknown field: ', k)
475			if k in self.extend.fieldtypes:
476				newdic[k] = v
477			else:
478				if self.nsid not in newdic:
479					newdic[self.nsid]={}
480				newdic[self.nsid][k]=v
481			
482		return e.todict(newdic)
483
484	@classmethod
485	def fromdict(cls, dic, e):
486		""" Builds instance from dictionary 
487
488			It is used during deserialization to create an openc2lib instance from the text message.
489			It takes an `Encoder` instance that is used to recursively build instances of the inner
490			objects (the `Encoder` provides standard methods to create instances of base objects like
491			strings, integers, boolean).
492
493			:param dic: The intermediary dictionary representation from which the object is built.
494			:param e: The `Encoder that is being used.
495			:return: An instance of this class initialized from the dictionary values.
496		"""
497		objdic = {}
498		extension = None
499		logger.debug('Building %s from %s in Map', cls, dic)
500		for k,v in dic.items():
501			if k in cls.fieldtypes:
502				objdic[k] = e.fromdict(cls.fieldtypes[k], v)
503			elif k in cls.regext:
504				logger.debug('   Using profile %s to decode: %s', k, v)
505				extension = cls.regext[k]
506				for l,w in v.items():
507					objdic[l] = e.fromdict(extension.fieldtypes[l], w)
508			else:
509				raise TypeError("Unexpected field: ", k)
510
511		if extension is not None:
512			cls = extension
513
514		return cls(objdic)

OpenC2 Map

Implements OpenC2 Map:

An unordered map from a set of specified keys to values with semantics bound to each key. Each field has an id, name and type.

However, the id is not considered in this implementation.

The implementation follows a similar logic than Array. Each derived class is expected to provide a fieldtypes class attribute that associate field names with their class definition.

Additionally, according to the Language Specification, Maps may be extended by Profiles. Such extensions must use the extend and regext class attributes to bind to the base element they extend and the Profile in which they are defined.

fieldtypes: dict = None

Field types

A dictionary which keys are field names and which values are the corresponding classes. Must be provided by any derived class.

extend = None

Base class

Data types defined in the Language Specification shall not set this field. Data types defined in Profiles that extends a Data Type defined in the Language Specification, must set this field to the corresponding class of the base Data Type.

Note: Extensions defined in the openc2lib context are recommended to use the same name of the base Data Type, and to distinguish them through appropriate usage of the namespacing mechanism.

regext = {}

Registered extensions

Classes that implement a Data Type defined in the Language Specification will use this field to register extensions defined by external Profiles. Classes that define extensions within Profiles shall register themselves according to the specific documentation of the base type class, but shall not modify this field.

def todict(self, e):
453	def todict(self, e):
454		""" Converts to dictionary 
455		
456			It is used to convert this object to an intermediary representation during 
457			serialization. It takes an `Encoder` argument that is used to recursively
458			serialize inner data and structures (the `Encoder` provides standard methods
459			for converting base types to dictionaries).. 
460
461			:param e: The `Encoder` that is being used.
462			:return: A dictionary compliants to the Language Specification's serialization
463			rules.
464		"""
465		newdic=dict()
466
467		# This is necessary because self.extend.fieldtypes does
468		# not exist for non-extended classes
469		if self.extend is None:
470			return e.todict(dict(self))
471			
472		for k,v in self.items():
473			if k not in self.fieldtypes:
474				raise ValueError('Unknown field: ', k)
475			if k in self.extend.fieldtypes:
476				newdic[k] = v
477			else:
478				if self.nsid not in newdic:
479					newdic[self.nsid]={}
480				newdic[self.nsid][k]=v
481			
482		return e.todict(newdic)

Converts to dictionary

It is used to convert this object to an intermediary representation during serialization. It takes an Encoder argument that is used to recursively serialize inner data and structures (the Encoder provides standard methods for converting base types to dictionaries)..

Parameters
  • e: The Encoder that is being used.
Returns

A dictionary compliants to the Language Specification's serialization rules.

@classmethod
def fromdict(cls, dic, e):
484	@classmethod
485	def fromdict(cls, dic, e):
486		""" Builds instance from dictionary 
487
488			It is used during deserialization to create an openc2lib instance from the text message.
489			It takes an `Encoder` instance that is used to recursively build instances of the inner
490			objects (the `Encoder` provides standard methods to create instances of base objects like
491			strings, integers, boolean).
492
493			:param dic: The intermediary dictionary representation from which the object is built.
494			:param e: The `Encoder that is being used.
495			:return: An instance of this class initialized from the dictionary values.
496		"""
497		objdic = {}
498		extension = None
499		logger.debug('Building %s from %s in Map', cls, dic)
500		for k,v in dic.items():
501			if k in cls.fieldtypes:
502				objdic[k] = e.fromdict(cls.fieldtypes[k], v)
503			elif k in cls.regext:
504				logger.debug('   Using profile %s to decode: %s', k, v)
505				extension = cls.regext[k]
506				for l,w in v.items():
507					objdic[l] = e.fromdict(extension.fieldtypes[l], w)
508			else:
509				raise TypeError("Unexpected field: ", k)
510
511		if extension is not None:
512			cls = extension
513
514		return cls(objdic)

Builds instance from dictionary

It is used during deserialization to create an openc2lib instance from the text message. It takes an Encoder instance that is used to recursively build instances of the inner objects (the Encoder provides standard methods to create instances of base objects like strings, integers, boolean).

Parameters
  • dic: The intermediary dictionary representation from which the object is built.
  • e: The `Encoder that is being used.
Returns

An instance of this class initialized from the dictionary values.

Inherited Members
builtins.dict
get
setdefault
pop
popitem
keys
items
values
update
fromkeys
clear
copy
class MapOf:
516class MapOf:
517	""" OpenC2 MapOf
518
519		Implements OpenC2 MapOf(*ktype, vtype*):
520		>An unordered set of keys to values with the same semantics. 
521			Each key has key type *ktype* and is mapped to value type *vtype*.
522
523		It extends `Map` with the same approach already used for `ArrayOf`.
524		`MapOf` for specific types are created as anonymous classes by passing
525		`ktype` and `vtype` as arguments.
526
527		Note: `MapOf` implementation currently does not support extensins!.
528	"""
529
530	def __new__(self,ktype, vtype):
531		""" `MapOf` builder
532
533			Creates a unnamed derived class from `Map`, which `fieldtypes` is set to a single value
534		 	`ktype: vtype`.
535			:param ktype: The key type of the items stored in the map.
536			:param vtype: The value type of the items stored in the map.
537			:return: A new unnamed class definition.
538		"""
539		class MapOf(Map):
540			""" OpenC2 unnamed `MapOf`
541
542				This class inherits from `Map` and sets its `fieldtypes` to a given type.
543		
544				Note: no `todict()` method is provided, since `Map.todict()` is fine here.
545			"""
546			fieldtypes = {ktype: vtype}
547			""" The type of values stored in this container """
548
549			@classmethod
550			def fromdict(cls, dic, e):
551				""" Builds instance from dictionary 
552		
553					It is used during deserialization to create an openc2lib instance from the text message.
554					It takes an `Encoder` instance that is used to recursively build instances of the inner
555					objects (the `Encoder` provides standard methods to create instances of base objects like
556					strings, integers, boolean).
557		
558					:param dic: The intermediary dictionary representation from which the object is built.
559					:param e: The `Encoder that is being used.
560					:return: An instance of this class initialized from the dictionary values.
561				"""
562				objdic = {}
563				logger.debug('Building %s from %s in MapOf', cls, dic)
564				for k,v in dic.items():
565					kclass = list(cls.fieldtypes)[0]
566					objk = e.fromdict(kclass, k)
567					objdic[objk] = e.fromdict(cls.fieldtypes[kclass], v)
568				return objdic
569
570		return MapOf

OpenC2 MapOf

Implements OpenC2 MapOf(ktype, vtype):

An unordered set of keys to values with the same semantics. Each key has key type ktype and is mapped to value type vtype.

It extends Map with the same approach already used for ArrayOf. MapOf for specific types are created as anonymous classes by passing ktype and vtype as arguments.

Note: MapOf implementation currently does not support extensins!.

MapOf(ktype, vtype)
530	def __new__(self,ktype, vtype):
531		""" `MapOf` builder
532
533			Creates a unnamed derived class from `Map`, which `fieldtypes` is set to a single value
534		 	`ktype: vtype`.
535			:param ktype: The key type of the items stored in the map.
536			:param vtype: The value type of the items stored in the map.
537			:return: A new unnamed class definition.
538		"""
539		class MapOf(Map):
540			""" OpenC2 unnamed `MapOf`
541
542				This class inherits from `Map` and sets its `fieldtypes` to a given type.
543		
544				Note: no `todict()` method is provided, since `Map.todict()` is fine here.
545			"""
546			fieldtypes = {ktype: vtype}
547			""" The type of values stored in this container """
548
549			@classmethod
550			def fromdict(cls, dic, e):
551				""" Builds instance from dictionary 
552		
553					It is used during deserialization to create an openc2lib instance from the text message.
554					It takes an `Encoder` instance that is used to recursively build instances of the inner
555					objects (the `Encoder` provides standard methods to create instances of base objects like
556					strings, integers, boolean).
557		
558					:param dic: The intermediary dictionary representation from which the object is built.
559					:param e: The `Encoder that is being used.
560					:return: An instance of this class initialized from the dictionary values.
561				"""
562				objdic = {}
563				logger.debug('Building %s from %s in MapOf', cls, dic)
564				for k,v in dic.items():
565					kclass = list(cls.fieldtypes)[0]
566					objk = e.fromdict(kclass, k)
567					objdic[objk] = e.fromdict(cls.fieldtypes[kclass], v)
568				return objdic
569
570		return MapOf

MapOf builder

Creates a unnamed derived class from Map, which fieldtypes is set to a single value ktype: vtype.

Parameters
  • ktype: The key type of the items stored in the map.
  • vtype: The value type of the items stored in the map.
Returns

A new unnamed class definition.