Source code for

import pdb
from abc import abstractmethod
import typing
from datetime import datetime
from typing import Union, Type, Optional

from autopilot.root import Autopilot_Type
from import Schema
from import Autopilot_Unit
from pydantic import Field

[docs]class Interface_Map(Autopilot_Type): """ Statement of equivalence between two things, potentially with some translation or parameterization, such that a base type can be written to. """ equals: typing.Type args: Optional[typing.List] = None kwargs: Optional[typing.Dict] = None conversion: Optional[typing.Callable] = None
[docs]class Interface_Mapset(Autopilot_Type): """ Metaclass for mapping base types to another format. Each field can be a Type (if it is instantiated without arguments, or can use the :class:`.Interface_Map` to specify them. The special types ``group`` and ``node`` correspond to :class:`` and :class:`` classes, for when a given interface needs to do something to create an abstract representation of a group or node in a schema's hierarchy. .. todo:: This will need to be generalized, eg. NWB doesn't need a mapping between types and objects, but mappings between annotated types and paths (eg. something within the `/data/trial_data` makes a behavioral series, etc). """ bool: Union[Interface_Map, Type] int: Union[Interface_Map, Type] float: Union[Interface_Map, Type] str: Union[Interface_Map, Type] bytes: Optional[Union[Interface_Map, Type]] datetime: Union[Interface_Map, Type] group: Optional[Union[Interface_Map, Type]] node: Optional[Union[Interface_Map, Type]]
[docs] def get(self, key, args:Optional[list]=None, kwargs:Optional[dict]=None): ret = getattr(self, key) if isinstance(ret, Interface_Map): _args = ret.args if _args is None: _args = [] if args is not None: _args = args _kwargs = ret.kwargs if _kwargs is None: _kwargs = {} if kwargs is not None: _kwargs.update(kwargs) return ret.equals(*_args, **_kwargs) else: return ret()
[docs]class Interface(Autopilot_Type): """ Create a representation of a given Schema """ map: Interface_Mapset schema_: Schema = Field(..., alias='schema')
[docs] @abstractmethod def make(self, input:typing.Any) -> bool: """ Make a given schema using the interface mapping given. Returns: bool: ``True`` if successful """
[docs]def resolve_type(type_, resolve_literal=False) -> typing.Type: """ Get the "inner" type of a model field, sans Optionals and Unions and the like Args: resolve_literal (bool): If ``True``, return the type of the inside of Literals, rather than the Literal type itself. """ if not hasattr(type_, '__args__') or (hasattr(type_, '__origin__') and type_.__origin__ == typing.Literal and not resolve_literal): # not an extended typing object. try: if issubclass(type_, Autopilot_Unit): type_ = type_._base_class() except TypeError: # Not a class, pass pass return type_ if getattr(type_, '__origin__', False) is typing.Literal: subtypes = [type(t) for t in type_.__args__ if type(t) in _permissiveness.keys()] elif getattr(type_, '__origin__', False) is typing.Union: subtypes = [resolve_type(t) for t in type_.__args__] else: # # check if this is just a list of a data type # if len(type_.__args__) == 1 and isinstance(type_.__args__[0], ModelMetaclass): # # list of a model type! # return type_.__args__[0] subtypes = [t for t in type_.__args__ if t in _permissiveness.keys()] if len(subtypes) == 0: # if we only have one type, there's no ambiguity to resolve. if len(type_.__args__) == 1: return type_.__args__[0] pdb.set_trace() raise ValueError(f'Dont know how to resolve type {type_}') # elif any([isinstance(t, ModelMetaclass) for t in subtypes]): # subtypes = [t for t in subtypes if isinstance(t, ModelMetaclass)] # return subtypes[0] # sort by permissiveness types = [(t, _permissiveness[t]) for t in subtypes] types.sort(key=lambda x: x[1]) return types[-1][0]
_permissiveness = { type(None):-1, bool:0, int:1, float:2, str:3, dict:0, datetime:0 } _NUMPY_TO_BUILTIN = { 'b': bool, 'i': int, 'u': int, 'f': float, 'c': complex, 'M': datetime, 'O': str, 'S': str, 'U': str }