Skip to content

core

Full documentation pages are generated for docstring reference only and may contain symbols imported from other modules. Imported symbols are not distinguished from locally defined symbols and will appear in any module that they are imported into. For better information on where symbols should be imported from, review the sourcecode on the github.

FoSpy.core

Synthesis

Bases: FileBlock

Represents a Synthesis loaded from a FOS file.

Source code in FoSpy/blocks/synthesis.py
@FileBlock.register_dispatch("synthesis", defaults={"metadata":{"fos_type":"synthesis"}})
@FileBlock.register_dispatch(None)
class Synthesis(FileBlock):
    """
    Represents a Synthesis loaded from a FOS file.
    """
    dispatch_from = FileBlock

    def insert_material(self, mat, idx=-1):
        # placeholder. modify for insertion at idx
        self.materials.append(mat)

    def insert_treatment(self, treat, idx=-1):
        # placeholder. modify for insertion at idx
        self.treatments.append(treat)

dispatch_from class-attribute instance-attribute

dispatch_from = FileBlock

insert_material

insert_material(mat, idx=-1)
Source code in FoSpy/blocks/synthesis.py
def insert_material(self, mat, idx=-1):
    # placeholder. modify for insertion at idx
    self.materials.append(mat)

insert_treatment

insert_treatment(treat, idx=-1)
Source code in FoSpy/blocks/synthesis.py
def insert_treatment(self, treat, idx=-1):
    # placeholder. modify for insertion at idx
    self.treatments.append(treat)

TemplateBlock

Bases: SingleBlock

Source code in FoSpy/blocks/template.py
@SingleBlock.setup_dispatch(from_key="_full_class", allow_self=False)
class TemplateBlock(SingleBlock):
    _id_key = "template_name"
    _full_class = None
    _fields = None
    def __init__(self, blockDict, **kwargs):
        self._val_exceptions = {}
        from ._blockUtils import _unwrap_block

        blockDict = _unwrap_block(blockDict)
        blockDict.setdefault("template_name", self.__class__.__name__)
        super().__init__(blockDict, **kwargs)

    def _override_validators(self, validators):
        from .blocks import Block
        try:
            rename_dict = self.rename_dict()
        except AttributeError:
            rename_dict = {}

        for field in self._fields:
            if field in rename_dict:
                field = rename_dict[field]

            if field not in validators:
                continue

            val = validators[field]
            if not isinstance(val, type) or not issubclass(val, Block):
                new_val = TemplateField

            elif issubclass(val, SingleBlock):
                new_val = val.TemplateClass()

            elif issubclass(val, ListBlock):
                new_val = TemplateList.Simple(val._reqCls)

            else:
                raise NotImplementedError("Shouldn't happen")

            validators[field] = new_val

        for field in self._val_exceptions:
            validators[field] = FailedTemplateField

        return validators


    def get_req_validators(self):
        validators = super().get_req_validators()

        return self._override_validators(validators)

    def get_validators(self):
        validators = super().get_validators()

        return self._override_validators(validators)

    def find_staged_id(self):
        if not (hasattr(self, "_staged_parent")
                and self._staged_parent.has_staged()):
            return False

        staged_dict = self._staged_parent._staged_templates
        staged_reversed = {v:k for k,v in staged_dict.items()}

        return staged_reversed.get(self, False)

    def fill(self,incomplete=False,staged=False,in_place=False,**kwargs):
        if not self._full_class is not None and issubclass(self._full_class, SingleBlock):
            raise TypeError("A Template Block must be initialized from an existing class in order to be filled.")

        for prop in self._staged_templates:
            self.fill_staged_template(prop)

        staged_id = self.find_staged_id()
        if staged_id and not staged:
            _, filled = self._staged_parent.fill_staged_template(staged_id, **kwargs)
            return filled

        serial = self.serialize(keepListType=True)
        for kw, arg in kwargs.items():
            serial[kw] = arg

        flex_cls = self._full_class.TemplateClass()

        try:
            filled = self._full_class(serial)
        except Exception as e:
            filled = flex_cls(serial)

        return filled

    def serialize(self,keepListType=False, shallow=False, clean=False, **kwargs):
        # from ..parsing.validation import required_keys
        # from ..parsing.format_fos import format_field
        required = self.get_req_validators()
        required.pop('ext',None)
        required.pop('template_name',None)
        serial = super().serialize(keepListType=keepListType, shallow=shallow, clean=clean)

        out = {"template_name":serial.pop("template_name","")}

        for key, staged in self._staged_templates.items():
            serial.setdefault(key, staged.serialize(keepListType=keepListType, shallow=shallow, clean=clean))

        for key,validator in required.items():
            val = None
            if isinstance(validator,type):
                if issubclass(validator,SingleBlock):
                    val = serial.pop(key, validator.reflex())
                elif issubclass(validator, ListBlock):
                    val = serial.pop(key, validator([]).serialize())

            if val is None:
                val = serial.pop(key, TemplateField("").serialize())

            out[key] = val

        for key, val in serial.items():
            out[key] = val

        return out

    def __setattr__(self, name, value):
        from .. import _errors as err
        from .blocks import Block

        try:
            super().__setattr__(name, value)
            self._val_exceptions.pop(name, None)
        except err.FailedValidatorError as e:
            validators = self.get_validators()

            cached_val = validators.get(name, None)

            if not isinstance(cached_val, type) or not issubclass(cached_val, Block):
                self._val_exceptions[name] = e
                # newly mutated _val_exceptions should allow setattr now.
                super().__setattr__(name, value)

            elif issubclass(cached_val, SingleBlock):
                if isinstance(value, TemplateField) or value == TemplateField().serialize():
                    value = {}
                self.stage_template(name, value)

            elif issubclass(cached_val, TemplateList):
                raise NotImplementedError("A TemplateList construction failed unexpectedly.")

            else: # ListBlock Only
                from ._blockUtils import _unwrap_listblock
                from warnings import warn
                setattr(self, name, [])

                value = _unwrap_listblock(value)

                new_listblock = getattr(self, name)

                warnings = []
                for item in value:
                    try:
                        new_listblock.append(item)
                    except err.FailedValidatorError as e:
                        try:
                            new_listblock.stage_template(template=item)
                        except Exception as e:
                            warnings.append("The following item could not be set to a ListBlock or staged as a template:"
                                            f"\n\nCANDIDATE:\n{item}"
                                            f"\n\nERROR:\n{e}")
                if warnings:
                    for w in warnings:
                        warn(w, UserWarning)

    @classmethod
    def TemplateClass(cls, *args):
        if None in (cls._full_class, cls._fields):
            raise TypeError("A new Template Block must be initialized from an existing class, or a Template of that class.")

        fields = list(cls._fields)

        fields.extend([a for a in args if a not in fields])

        return cls._full_class.TemplateClass(*fields)

    @classmethod
    def _inject_defaults(cls, full_class, blockDict):
        from .. import _errors as err

        full_dispatch = getattr(full_class, "__dispatch__", {})

        next_class = None
        while next_class is not full_class:
            if next_class is None:
                next_class = full_dispatch.get("dispatch_from", full_class)
            else:
                registry = next_class.__dispatch__["registry"]
                try:
                    next_class = next(sub for sub in registry.values() if issubclass(full_class, sub))
                except StopIteration:
                    err.BlockDispatchError(
                        f"Could not find a valid dispatch chain to get from {next_class.__name__} to "
                        f"{full_class.__name__}.")

            blockDict = next_class.inject_defaults(blockDict)


        return blockDict

    def __new__(cls, blockDict, *args, **kwargs):
        from .. import _errors as err

        if None in (cls._fields, cls._full_class):
            raise err.BlockDispatchError("A Template Block must be initialized from an existing class, or a Template of that class.")

        dispatched = kwargs.pop("_dispatched", False)
        if dispatched:
            blockDict.setdefault("template_name", cls.__name__)
            return super().__new__(cls, blockDict, *args, _dispatched=True, **kwargs)

        full_class = cls._full_class
        blockDict = cls._inject_defaults(full_class, blockDict)

        template_class = full_class.TemplateClass(*cls._fields)

        for field in cls._fields:
            if blockDict.get(field, None) is None:
                blockDict[field] = TemplateField()


        return template_class(blockDict, *args, _dispatched=True, **kwargs)

_fields class-attribute instance-attribute

_fields = None

_full_class class-attribute instance-attribute

_full_class = None

_id_key class-attribute instance-attribute

_id_key = 'template_name'

_val_exceptions instance-attribute

_val_exceptions = {}

TemplateClass classmethod

TemplateClass(*args)
Source code in FoSpy/blocks/template.py
@classmethod
def TemplateClass(cls, *args):
    if None in (cls._full_class, cls._fields):
        raise TypeError("A new Template Block must be initialized from an existing class, or a Template of that class.")

    fields = list(cls._fields)

    fields.extend([a for a in args if a not in fields])

    return cls._full_class.TemplateClass(*fields)

__init__

__init__(blockDict, **kwargs)
Source code in FoSpy/blocks/template.py
def __init__(self, blockDict, **kwargs):
    self._val_exceptions = {}
    from ._blockUtils import _unwrap_block

    blockDict = _unwrap_block(blockDict)
    blockDict.setdefault("template_name", self.__class__.__name__)
    super().__init__(blockDict, **kwargs)

__new__

__new__(blockDict, *args, **kwargs)
Source code in FoSpy/blocks/template.py
def __new__(cls, blockDict, *args, **kwargs):
    from .. import _errors as err

    if None in (cls._fields, cls._full_class):
        raise err.BlockDispatchError("A Template Block must be initialized from an existing class, or a Template of that class.")

    dispatched = kwargs.pop("_dispatched", False)
    if dispatched:
        blockDict.setdefault("template_name", cls.__name__)
        return super().__new__(cls, blockDict, *args, _dispatched=True, **kwargs)

    full_class = cls._full_class
    blockDict = cls._inject_defaults(full_class, blockDict)

    template_class = full_class.TemplateClass(*cls._fields)

    for field in cls._fields:
        if blockDict.get(field, None) is None:
            blockDict[field] = TemplateField()


    return template_class(blockDict, *args, _dispatched=True, **kwargs)

__setattr__

__setattr__(name, value)
Source code in FoSpy/blocks/template.py
def __setattr__(self, name, value):
    from .. import _errors as err
    from .blocks import Block

    try:
        super().__setattr__(name, value)
        self._val_exceptions.pop(name, None)
    except err.FailedValidatorError as e:
        validators = self.get_validators()

        cached_val = validators.get(name, None)

        if not isinstance(cached_val, type) or not issubclass(cached_val, Block):
            self._val_exceptions[name] = e
            # newly mutated _val_exceptions should allow setattr now.
            super().__setattr__(name, value)

        elif issubclass(cached_val, SingleBlock):
            if isinstance(value, TemplateField) or value == TemplateField().serialize():
                value = {}
            self.stage_template(name, value)

        elif issubclass(cached_val, TemplateList):
            raise NotImplementedError("A TemplateList construction failed unexpectedly.")

        else: # ListBlock Only
            from ._blockUtils import _unwrap_listblock
            from warnings import warn
            setattr(self, name, [])

            value = _unwrap_listblock(value)

            new_listblock = getattr(self, name)

            warnings = []
            for item in value:
                try:
                    new_listblock.append(item)
                except err.FailedValidatorError as e:
                    try:
                        new_listblock.stage_template(template=item)
                    except Exception as e:
                        warnings.append("The following item could not be set to a ListBlock or staged as a template:"
                                        f"\n\nCANDIDATE:\n{item}"
                                        f"\n\nERROR:\n{e}")
            if warnings:
                for w in warnings:
                    warn(w, UserWarning)

_inject_defaults classmethod

_inject_defaults(full_class, blockDict)
Source code in FoSpy/blocks/template.py
@classmethod
def _inject_defaults(cls, full_class, blockDict):
    from .. import _errors as err

    full_dispatch = getattr(full_class, "__dispatch__", {})

    next_class = None
    while next_class is not full_class:
        if next_class is None:
            next_class = full_dispatch.get("dispatch_from", full_class)
        else:
            registry = next_class.__dispatch__["registry"]
            try:
                next_class = next(sub for sub in registry.values() if issubclass(full_class, sub))
            except StopIteration:
                err.BlockDispatchError(
                    f"Could not find a valid dispatch chain to get from {next_class.__name__} to "
                    f"{full_class.__name__}.")

        blockDict = next_class.inject_defaults(blockDict)


    return blockDict

_override_validators

_override_validators(validators)
Source code in FoSpy/blocks/template.py
def _override_validators(self, validators):
    from .blocks import Block
    try:
        rename_dict = self.rename_dict()
    except AttributeError:
        rename_dict = {}

    for field in self._fields:
        if field in rename_dict:
            field = rename_dict[field]

        if field not in validators:
            continue

        val = validators[field]
        if not isinstance(val, type) or not issubclass(val, Block):
            new_val = TemplateField

        elif issubclass(val, SingleBlock):
            new_val = val.TemplateClass()

        elif issubclass(val, ListBlock):
            new_val = TemplateList.Simple(val._reqCls)

        else:
            raise NotImplementedError("Shouldn't happen")

        validators[field] = new_val

    for field in self._val_exceptions:
        validators[field] = FailedTemplateField

    return validators

fill

fill(
    incomplete=False, staged=False, in_place=False, **kwargs
)
Source code in FoSpy/blocks/template.py
def fill(self,incomplete=False,staged=False,in_place=False,**kwargs):
    if not self._full_class is not None and issubclass(self._full_class, SingleBlock):
        raise TypeError("A Template Block must be initialized from an existing class in order to be filled.")

    for prop in self._staged_templates:
        self.fill_staged_template(prop)

    staged_id = self.find_staged_id()
    if staged_id and not staged:
        _, filled = self._staged_parent.fill_staged_template(staged_id, **kwargs)
        return filled

    serial = self.serialize(keepListType=True)
    for kw, arg in kwargs.items():
        serial[kw] = arg

    flex_cls = self._full_class.TemplateClass()

    try:
        filled = self._full_class(serial)
    except Exception as e:
        filled = flex_cls(serial)

    return filled

find_staged_id

find_staged_id()
Source code in FoSpy/blocks/template.py
def find_staged_id(self):
    if not (hasattr(self, "_staged_parent")
            and self._staged_parent.has_staged()):
        return False

    staged_dict = self._staged_parent._staged_templates
    staged_reversed = {v:k for k,v in staged_dict.items()}

    return staged_reversed.get(self, False)

get_req_validators

get_req_validators()
Source code in FoSpy/blocks/template.py
def get_req_validators(self):
    validators = super().get_req_validators()

    return self._override_validators(validators)

get_validators

get_validators()
Source code in FoSpy/blocks/template.py
def get_validators(self):
    validators = super().get_validators()

    return self._override_validators(validators)

serialize

serialize(
    keepListType=False, shallow=False, clean=False, **kwargs
)
Source code in FoSpy/blocks/template.py
def serialize(self,keepListType=False, shallow=False, clean=False, **kwargs):
    # from ..parsing.validation import required_keys
    # from ..parsing.format_fos import format_field
    required = self.get_req_validators()
    required.pop('ext',None)
    required.pop('template_name',None)
    serial = super().serialize(keepListType=keepListType, shallow=shallow, clean=clean)

    out = {"template_name":serial.pop("template_name","")}

    for key, staged in self._staged_templates.items():
        serial.setdefault(key, staged.serialize(keepListType=keepListType, shallow=shallow, clean=clean))

    for key,validator in required.items():
        val = None
        if isinstance(validator,type):
            if issubclass(validator,SingleBlock):
                val = serial.pop(key, validator.reflex())
            elif issubclass(validator, ListBlock):
                val = serial.pop(key, validator([]).serialize())

        if val is None:
            val = serial.pop(key, TemplateField("").serialize())

        out[key] = val

    for key, val in serial.items():
        out[key] = val

    return out