def wrap( cls_or_instance: Union[EnumEncode, Type[EnumEncode]] ) -> Union['EnumWrap', Type['EnumWrap']]: ''' Returns the EnumWrap class for this enum `klass`. Returns None if not found. ''' # Get Class: klass, is_class = _to_class(cls_or_instance) # Do we know of this guy? wrap_type = _WRAPPED_ENUMS.get(klass, None) # Return what we were given: instance or class type if is_class: log.data_processing( label.normalize(_DOTTED, 'wrap'), "wrap:\n" " --in--> {}\n" " --type- {}\n" " <-type- {}", cls_or_instance, wrap_type, wrap_type) return wrap_type wrap_instance = wrap_type(cls_or_instance) log.data_processing( label.normalize(_DOTTED, 'wrap'), "wrap:\n" " -in--> {}\n" " -type- {}\n" " <-out- {}", cls_or_instance, wrap_type, wrap_instance) return wrap_instance
def recv(self) -> Tuple[Any, VerediContext]: ''' Pull a package & context from the IPC pipe. ''' package, context = self.pipe.recv() log.data_processing(self.dotted, "{} '{}' recv from sub-proc: {}, {}", self.klass, self.name, package, context) return (package, context)
def send(self, package: Any, context: VerediContext) -> None: ''' Push package & context into IPC pipe. Waits/blocks until it receives something. ''' log.data_processing(self.dotted, "{} '{}' send to sub-proc: {}, {}", self.klass, self.name, package, context) self.pipe.send((package, context))
def _ut_recv(self) -> Tuple[Any, VerediContext]: ''' Pull a package & context from the IPC unit-testing pipe. ''' package, context = self.ut_pipe.recv() log.data_processing( self.dotted, "{} '{}' TESTING pipe recv from main proc: {}, {}", self.klass, self.name, package, context) return (package, context)
def _ut_send(self, package: Any, context: VerediContext) -> None: ''' Push package & context into IPC unit-testing pipe. Waits/blocks until it receives something. ''' log.data_processing(self.dotted, "{} '{}' TESTING pipe send to main proc: {}, {}", self.klass, self.name, package, context) self.ut_pipe.send((package, context))
def unwrap(instance: Union['EnumWrap', 'Encodable']) -> EnumEncode: ''' If `instance` is an EnumWrap, returns the enum instance/value that the EnumWrap `instance` contains. Else returns `instance`. ''' if not isinstance(instance, EnumWrap): log.data_processing(label.normalize(_DOTTED, 'unwrap'), "unwrap:\n" " --ignore-> {}\n" " <-ignore-- {}", instance, instance) return instance log.data_processing(label.normalize(_DOTTED, 'unwrap'), "unwrap:\n" " -in--> {}\n" " <-out- {}", instance, instance.enum) return instance.enum
def get_data(self, *keychain: label.LabelInput) -> Nullable[Any]: ''' Get a configuration thingy from us given some keychain use to walk into our config data in 'data' entry. Returns data found at end keychain. Returns None if couldn't find a key in our config data. ''' # Ensure the keychain is in good shape from whatever was passed in. keychain = label.regularize(*keychain) data = self.get('data', *keychain) log.data_processing(self.dotted, 'get_data: keychain: {} -> data: {}', keychain, data, log_minimum=log.Level.DEBUG) return data
def get_by_doc(self, doc_type: Document, *keychain: label.LabelInput) -> Nullable[Any]: ''' Get value of `keychain` from `doc_type`. Raises a ConfigError if invalid `doc_type` supplied. Returns Null() if `doc_type` doesn't exist or `keychain` isn't in it. ''' # Ensure the keychain is in good shape from whatever was passed in. keychain = label.regularize(*keychain) log.data_processing(self.dotted, 'get_by_doc: Getting doc: {}, keychain: {}...', doc_type, keychain, log_minimum=log.Level.DEBUG) hierarchy = Document.hierarchy(doc_type) if not hierarchy.valid(*keychain): log.data_processing(self.dotted, "get_by_doc: invalid document hierarchy for " "doc: {}, keychain: {}...", doc_type, keychain, log_minimum=log.Level.DEBUG) raise log.exception( ConfigError, "Invalid keychain '{}' for {} document type. See its " "Hierarchy class for proper layout.", keychain, doc_type) # Get document type data first. doc_data = self._config.get(doc_type, None) data = doc_data if data is None: log.data_processing(self.dotted, "get_by_doc: No document type '{}' in " "our config data: {}", doc_type, self._config, log_minimum=log.Level.DEBUG, log_success=False) return Null() # Now hunt for the keychain they wanted... for key in keychain: data = data.get(key, None) if data is None: log.data_processing(self.dotted, "get_by_doc: No data for key '{}' in " "keychain {} in our config " "document data: {}", key, keychain, doc_data, log_minimum=log.Level.DEBUG, log_success=False) return Null() log.data_processing(self.dotted, "get_by_doc: Got data for {} in " "keychain {}. Data: {}", doc_type, keychain, data, log_minimum=log.Level.DEBUG, log_success=True) return data
def claim( klass: Type['Encodable'], data: EncodedEither ) -> Tuple[bool, Optional[EncodedEither], Optional[str]]: ''' For simple encodings, looks for a match to the `klass._get_decode_rx()` regex. - Returns `data` as our claim. For complex encodings, looks for `klass.type_field()` in data. It should be one of these: - a top level key, with our encodable data as the key's value. - Returns `data[klass.type_field()]` as our claim. or - a top level 'claim' key, with our encodable data as all of `data`. - Returns `data` as our claim. Returns a tuple of: - bool: Can claim. - True if this Encodable class thinks it can/should decode this. - False otherwise. - EncodedEither: - Our claim of the data. - Optional[str]: Reason. - If can claim, this is None. - If cannot claim, this is a string describing why not. ''' # log.data_processing( # klass.dotted, # "{} checking for claim of data:\n" # " {}", # klass.klass, data) # --- # Simple? # --- # Is it EncodedSimple type and intended for this class? if klass.encoded_as(data) == Encoding.SIMPLE: # log.data_processing( # klass.dotted, # "{} checking for Encoding.SIMPLE claim of data:\n" # " {}", # klass.klass, data) # If it's a simple encode and we don't have a decode regex for # that, then... No; It can't be ours. decode_rx = klass._get_decode_rx() if not decode_rx: # log.data_processing( # klass.dotted, # "{} has no Encoding.SIMPLE decode regex; " # "cannot claim data:\n" # " {}", # klass.klass, data) reason = (f"{klass.klass} is (probably) encoded simply " f"but has no {klass.klass}._get_decode_rx(): " f"rx: {decode_rx}, data: {data}") return False, None, reason # Check if decode_rx likes the data. claimed = bool(decode_rx.match(data)) data_claim = data if claimed else None reason = (None if claimed else "No regex match.") if claimed: log.data_processing( klass.dotted, "{} {} Encoding.SIMPLE data:\n" " {}", klass.klass, 'staking claim on' if claimed else 'will not claim', data) return claimed, data_claim, None # Does this class only do simple encode/decode? if not klass.encoding().has(Encoding.COMPLEX): # log.data_processing( # klass.dotted, # "{} was not Encoding.SIMPLE, and we don't do " # "Encoding.COMPLEX. Will not claim data:\n" # " {}", # klass.klass, data) return (False, None, "Class only encodes simply and didn't match data.") # log.data_processing( # klass.dotted, # "{} checking for Encoding.COMPLEX claim of data:\n" # " {}", # klass.klass, data) # --- # Complex? # --- # Else it's EncodedComplex. # Encoded with full registree information? if klass.was_encoded_with_registry(data): log.data_processing( klass.dotted, "{} was encoded with registry. Staking claim on data:\n" " {}", klass.klass, data[klass.ENCODABLE_PAYLOAD_FIELD]) return True, data[klass.ENCODABLE_PAYLOAD_FIELD], None # Are we a sub-field? if klass.type_field() in data: log.data_processing( klass.dotted, "{} was encoded with type_field. Staking claim on data:\n" " {}", klass.klass, data[klass.type_field()]) # Our type is a top level key, so our claim is the key's value. return True, data[klass.type_field()], None # Are we this whole thing? if klass._is_type_field(data): log.data_processing( klass.dotted, "{}... um... /is/ type_field? IDK. Staking claim on data:\n" " {}", klass.klass, data) # Our type is in the 'type' field, so our claim is this whole # data thing. return True, data, None # --- # No Claim on Data. # --- # Doesn't have our type_field() value, so no. reason = (f"{klass.klass} is (probably) encoded but doesn't have " f"our type-field ('{klass.type_field()}') at top level or " "as 'type' value.") # # Debug output full data structure, but don't build the pretty string # # unless we're actually logging it. # if log.will_output(log.Group.DATA_PROCESSING): # log.data_processing( # klass.dotted, # reason + "\n" # + "Will not claim data:\n {}", # pretty.indented(data)) return False, None, reason