Source code for qiskit_metal.qlibrary.core._parsed_dynamic_attrs

# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2021.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""Parsed dynamic attributes."""
import pprint
from typing import List
from typing import TYPE_CHECKING
#from ...toolbox_python.utility_functions import log_error_easy
if TYPE_CHECKING:
    from .base import QComponent


def is_ipython_magic(check_attribute: str) -> bool:
    """Ignore the following checks by jupyter."""
    return check_attribute in {
        '_ipython_canary_method_should_not_exist_',
        '_ipython_display_',
        '_repr_mimebundle_',
        '_repr_html_',
        '_repr_markdown_',
        '_repr_svg_',
        '_repr_png_',
        '_repr_pdf_',
        '_repr_jpeg_',
        '_repr_latex_',
        '_repr_json_',
        '_repr_javascript_',
        '_rapped',
        '__wrapped__',
        '__call__',
    }


[docs] class ParsedDynamicAttributes_Component(): """Provides a parsing view of the component options. When accessed, returns parse versions of the user options. Works with nested options too. Example: .. code-block:: python component.options = {'x':'1nm'} print(component.p.x) >> `float(1e7)` """ """ Special method names: See Python Data Module for Objects: https://docs.python.org/3/reference/datamodel.html https://docs.python.org/3/library/stdtypes.html#object.__dict__ https://python-reference.readthedocs.io/en/latest/docs/dunderattr/index.html https://rszalski.github.io/magicmethods/ __getattribute__: Called unconditionally to implement attribute accesses for instances of the class. __getattr__: Called when an attribute lookup has not found the attribute in the usual places. __setattr__: Called when an attribute assignment is attempted. __delattr__: Called when an attribute deletion is attempted. """ def __init__(self, component: 'QComponent', key_list: List[str] = None): """ Args: component (QComponent): Component to get options from. key_list (List[str]): List of keys. Defaults to None. """ #print(f'*** Created with {key_list}') # These names must have __xx__ or else they will go to getattr instead of getattribute self.__component__ = component # self.__d__ = component.options self.__keylist__ = key_list or [] # lis tot get current value self.__parse__ = component.design.parse_value # function def __dir__(self): # For autocompletion return list(self.__getdict__().keys()) # def _repr_html_(self): # return self.__d__._repr_html_() def __str__(self): return self.__getdict__().__str__()
[docs] def __len__(self): """Return the length.""" return len(self.__getdict__())
def __getdict__(self) -> dict: return get_nested_dict_item(self.__component__.options, self.__keylist__) def __iter__(self): return self.__getdict__().__iter__()
[docs] def items(self): """Produces tuples consisting of keys and respective parsed values for iterating over a dictionary.""" for key in self: # calls __iter__ yield (key, self.__getitem__(key))
def __getattr__(self, name: str): """Delegating Attribute Access After regular attribute access, try looking up the name This allows simpler access to columns for interactive use.""" #### Note: obj.x will always call obj.__getattribute__('x') prior to # calling obj.__getattr__('x'). # #### Former issues: # These two only come up when trying to use in ipython /jupyter environemtn # and acessing a sub dictionary in the past # Exmaple: # xx = ParsedDynamicAttributes(self, ['c']) # xx # if name.startswith('_repr') or name.startswith('_ipython'): # return #print(f'__getattr__ NAME = {name}; dict=',self.__getdict__()) return self.__getitem__(name)
[docs] def __getitem__(self, name: str): """Get the item associated with the given name. Args: name (str): Name of the item Return: str, float, list, tuple, or ast eval: Parse value Raises: AttributeError: The given name is a magic method not in the dictionary """ dic = self.__getdict__() if name not in dic: if not is_ipython_magic(name): # log_error_easy(self.__component__.logger, post_text= xx = self.__keylist__ xx = ".".join(xx) + "." + str(name) if len(xx) > 0 else name self.__component__.logger.error( '\nWarning: User tried to access a variable in the parse options' f' that is not there!\n Component name = `{self.__component__.name}`\n' f' Option name = `{xx}`') return None else: # IPython checking methods # https://github.com/jupyter/notebook/issues/2014 raise AttributeError(name) else: val = dic.get(name) #print(f'val = {val}') if isinstance(val, dict): #print(f' -> Going to create a new {self.__keylist__ + [name]}') return ParsedDynamicAttributes_Component( self.__component__, key_list=self.__keylist__ + [name]) else: return self.__parse__(val)
####### SERIALIZATION def __getstate__(self): # "I'm being pickled" return self.__dict__ def __setstate__(self, d): # f"I'm being unpickled with these values: {d}" self.__dict__ = d # def __repr__(self): # return self.__getdict__().__repr__() def __repr__(self): """For viewing. Just return the whole parse dictionary. """ b = '\033[95m\033[1m' e = '\033[0m' c = self.__component__ parsed = c.parse_value(c.options) parsed_text = pprint.pformat(parsed, indent=1) text = f"""{b}Current parsed *view* of options for {c.name}:{e} (Units are parsed to floats in default design units.) {parsed_text}""" return text
# TESTING code: """ from qiskit_metal.qlibrary.core.base import QComponent class Test(QComponent): def make(self): pass DEFAULT_OPTIONS['Test'] = { #instead of using DEFAULT_OPTIONS, use the dicts within QDesign class. 'a' : '1mm', 'b' : '1um', 'c' : { 'd' : '15um', 'e' : '10um', } } self = Test(design, 'test') self.p = ParsedDynamicAttributes(self) self.p self.p.a self.p.a.c """ def get_nested_dict_item(dic: dict, key_list: list, level=0): """Get the nested dictionary item. Args: dic (dict): Dictionary of nested items key_list (list): List of keys level (int): Internal for recussion. Defaults to 0. Returns: object: Item in the dic corresponding to the given key_list Example use: .. code-block: python myDict = Dict( aa=Dict( x1={ 'dda': '34fF' }, y1='Y', z='10um' ), bb=Dict( x2=5, y2='YYYsdg', z='100um' ), cc='100nm' ) key_list = ['cc'] print(get_nested_dict_item(myDict, key_list)) key_list = ['aa', 'x1', 'dda'] print(get_nested_dict_item(myDict, key_list)) Results in >> 100nm >> 34fF """ if not key_list: # get the root return dic if level < len(key_list) - 1: return get_nested_dict_item(dic[key_list[level]], key_list, level + 1) else: return dic[key_list[level]] # Example use """ myDict = Dict( aa=Dict( x1={ 'dda': '34fF' }, y1='Y', z='10um' ), bb=Dict( x2=5, y2='YYYsdg', z='100um' ), cc='100nm' ) key_list = ['cc'] print(get_nested_dict_item(myDict, key_list)) key_list = ['aa', 'x1', 'dda'] print(get_nested_dict_item(myDict, key_list)) print(get_nested_dict_item(myDict, ['aa'])) """