Пример #1
0
def _parse_box_dots(item):
    for idx, char in enumerate(item):
        if char == '[':
            return item[:idx], item[idx:]
        elif char == '.':
            return item[:idx], item[idx + 1:]
    raise BoxError('Could not split box dots properly')
Пример #2
0
 def to_toml(self,
             filename: Union[str, PathLike] = None,
             encoding: str = "utf-8",
             errors: str = "strict"):
     raise BoxError(
         'toml is unavailable on this system, please install the "toml" package'
     )
Пример #3
0
        def from_yaml(
            cls,
            yaml_string: str = None,
            filename: Union[str, PathLike] = None,
            encoding: str = "utf-8",
            errors: str = "strict",
            **kwargs,
        ):
            """
            Transform a yaml object string into a BoxList object.

            :param yaml_string: string to pass to `yaml.load`
            :param filename: filename to open and pass to `yaml.load`
            :param encoding: File encoding
            :param errors: How to handle encoding errors
            :param kwargs: parameters to pass to `BoxList()` or `yaml.load`
            :return: BoxList object from yaml data
            """
            box_args = {}
            for arg in list(kwargs.keys()):
                if arg in BOX_PARAMETERS:
                    box_args[arg] = kwargs.pop(arg)

            data = _from_yaml(yaml_string=yaml_string, filename=filename, encoding=encoding, errors=errors, **kwargs)
            if not data:
                return cls(**box_args)
            if not isinstance(data, list):
                raise BoxError(f"yaml data not returned as a list but rather a {type(data).__name__}")
            return cls(data, **box_args)
Пример #4
0
 def __getattr__(self, item):
     try:
         try:
             value = self.__getitem__(item, _ignore_default=True)
         except KeyError:
             value = object.__getattribute__(self, item)
     except AttributeError as err:
         if item == "__getstate__":
             raise BoxKeyError(item) from _exception_cause(err)
         if item == "_box_config":
             raise BoxError(
                 "_box_config key must exist") from _exception_cause(err)
         if self._box_config["conversion_box"]:
             safe_key = self._safe_attr(item)
             if safe_key in self._box_config["__safe_keys"]:
                 return self.__getitem__(
                     self._box_config["__safe_keys"][safe_key])
         if self._box_config["default_box"]:
             if item.startswith("_") and item.endswith("_"):
                 raise BoxKeyError(
                     f"{item}: Does not exist and internal methods are never defaulted"
                 )
             return self.__get_default(item, attr=True)
         raise BoxKeyError(str(err)) from _exception_cause(err)
     return value
Пример #5
0
    def from_json(
        cls,
        json_string: str = None,
        filename: Union[str, PathLike] = None,
        encoding: str = "utf-8",
        errors: str = "strict",
        **kwargs,
    ) -> "Box":
        """
        Transform a json object string into a Box object. If the incoming
        json is a list, you must use BoxList.from_json.

        :param json_string: string to pass to `json.loads`
        :param filename: filename to open and pass to `json.load`
        :param encoding: File encoding
        :param errors: How to handle encoding errors
        :param kwargs: parameters to pass to `Box()` or `json.loads`
        :return: Box object from json data
        """
        box_args = {}
        for arg in kwargs.copy():
            if arg in BOX_PARAMETERS:
                box_args[arg] = kwargs.pop(arg)

        data = _from_json(json_string,
                          filename=filename,
                          encoding=encoding,
                          errors=errors,
                          **kwargs)

        if not isinstance(data, dict):
            raise BoxError(
                f"json data not returned as a dictionary, but rather a {type(data).__name__}"
            )
        return cls(data, **box_args)
Пример #6
0
        def from_msgpack(
            cls,
            msgpack_bytes: bytes = None,
            filename: Union[str, PathLike] = None,
            **kwargs,
        ) -> "Box":
            """
            Transforms msgpack bytes or file into a Box object

            :param msgpack_bytes: string to pass to `msgpack.unpackb`
            :param filename: filename to open and pass to `msgpack.unpack`
            :param kwargs: parameters to pass to `Box()`
            :return: Box object
            """
            box_args = {}
            for arg in kwargs.copy():
                if arg in BOX_PARAMETERS:
                    box_args[arg] = kwargs.pop(arg)

            data = _from_msgpack(msgpack_bytes=msgpack_bytes,
                                 filename=filename,
                                 **kwargs)
            if not isinstance(data, dict):
                raise BoxError(
                    f"msgpack data not returned as a dictionary but rather a {type(data).__name__}"
                )
            return cls(data, **box_args)
Пример #7
0
def _to_yaml(data):
    try:
        return Box.from_yaml(data)
    except YAMLError:
        raise BoxError('File is not YAML as expected')
    except BoxError:
        return BoxList.from_yaml(data)
Пример #8
0
        def from_yaml(
            cls,
            yaml_string: str = None,
            filename: Union[str, PathLike] = None,
            encoding: str = "utf-8",
            errors: str = "strict",
            **kwargs,
        ) -> "Box":
            """
            Transform a yaml object string into a Box object. By default will use SafeLoader.

            :param yaml_string: string to pass to `yaml.load`
            :param filename: filename to open and pass to `yaml.load`
            :param encoding: File encoding
            :param errors: How to handle encoding errors
            :param kwargs: parameters to pass to `Box()` or `yaml.load`
            :return: Box object from yaml data
            """
            box_args = {}
            for arg in kwargs.copy():
                if arg in BOX_PARAMETERS:
                    box_args[arg] = kwargs.pop(arg)

            data = _from_yaml(yaml_string=yaml_string,
                              filename=filename,
                              encoding=encoding,
                              errors=errors,
                              **kwargs)
            if not isinstance(data, dict):
                raise BoxError(
                    f"yaml data not returned as a dictionary but rather a {type(data).__name__}"
                )
            return cls(data, **box_args)
Пример #9
0
def _to_json(data):
    try:
        return Box.from_json(data)
    except JSONDecodeError:
        raise BoxError('File is not JSON as expected')
    except BoxError:
        return BoxList.from_json(data)
Пример #10
0
def _to_csv(box_list,
            filename: Union[str, PathLike] = None,
            encoding: str = "utf-8",
            errors: str = "strict",
            **kwargs):
    csv_column_names = list(box_list[0].keys())
    for row in box_list:
        if list(row.keys()) != csv_column_names:
            raise BoxError(
                "BoxList must contain the same dictionary structure for every item to convert to csv"
            )

    if filename:
        _exists(filename, create=True)
        out_data = open(filename,
                        "w",
                        encoding=encoding,
                        errors=errors,
                        newline="")
    else:
        out_data = StringIO("")
    writer = csv.DictWriter(out_data, fieldnames=csv_column_names, **kwargs)
    writer.writeheader()
    for data in box_list:
        writer.writerow(data)
    if not filename:
        return out_data.getvalue()  # type: ignore
    out_data.close()
Пример #11
0
        def from_toml(
            cls,
            toml_string: str = None,
            filename: Union[str, PathLike] = None,
            key_name: str = "toml",
            encoding: str = "utf-8",
            errors: str = "strict",
            **kwargs,
        ):
            """
            Transforms a toml string or file into a BoxList object

            :param toml_string: string to pass to `toml.load`
            :param filename: filename to open and pass to `toml.load`
            :param key_name: Specify the name of the key to pull the list from
                (cannot directly convert from toml)
            :param encoding: File encoding
            :param errors: How to handle encoding errors
            :param kwargs: parameters to pass to `Box()`
            :return:
            """
            box_args = {}
            for arg in list(kwargs.keys()):
                if arg in BOX_PARAMETERS:
                    box_args[arg] = kwargs.pop(arg)

            data = _from_toml(toml_string=toml_string, filename=filename, encoding=encoding, errors=errors)
            if key_name not in data:
                raise BoxError(f"{key_name} was not found.")
            return cls(data[key_name], **box_args)
Пример #12
0
        def from_msgpack(cls,
                         msgpack_bytes: bytes = None,
                         filename: Union[str, PathLike] = None,
                         **kwargs):
            """
            Transforms a toml string or file into a BoxList object

            :param msgpack_bytes: string to pass to `msgpack.packb`
            :param filename: filename to open and pass to `msgpack.pack`
            :param kwargs: parameters to pass to `Box()`
            :return:
            """
            box_args = {}
            for arg in list(kwargs.keys()):
                if arg in BOX_PARAMETERS:
                    box_args[arg] = kwargs.pop(arg)

            data = _from_msgpack(msgpack_bytes=msgpack_bytes,
                                 filename=filename,
                                 **kwargs)
            if not isinstance(data, list):
                raise BoxError(
                    f"msgpack data not returned as a list but rather a {type(data).__name__}"
                )
            return cls(data, **box_args)
Пример #13
0
 def popitem(self):
     if self._box_config["frozen_box"]:
         raise BoxError("Box is frozen")
     try:
         key = next(self.__iter__())
     except StopIteration:
         raise BoxKeyError("Empty box") from None
     return key, self.pop(key)
Пример #14
0
def _to_yaml(file, encoding, errors, **kwargs):
    if not yaml_available:
        raise BoxError(
            f'File "{file}" is yaml but no package is available to open it. Please install "ruamel.yaml" or "PyYAML"'
        )
    try:
        return Box.from_yaml(filename=file,
                             encoding=encoding,
                             errors=errors,
                             **kwargs)
    except YAMLError:
        raise BoxError("File is not YAML as expected")
    except BoxError:
        return BoxList.from_yaml(filename=file,
                                 encoding=encoding,
                                 errors=errors,
                                 **kwargs)
Пример #15
0
    def items(self, dotted: Union[bool] = False):
        if not dotted:
            return super().items()

        if not self._box_config["box_dots"]:
            raise BoxError("Cannot return dotted keys as this Box does not have `box_dots` enabled")

        return [(k, self[k]) for k in self.keys(dotted=True)]
Пример #16
0
 def __delattr__(self, item):
     if self._box_config['frozen_box']:
         raise BoxError('Box is frozen')
     if item == '_box_config':
         raise BoxError('"_box_config" is protected')
     if item in self._protected_keys:
         raise BoxKeyError(f'Key name "{item}" is protected')
     try:
         self.__delitem__(item)
     except KeyError as err:
         if self._box_config['conversion_box']:
             safe_key = self._safe_attr(item)
             if safe_key in self._box_config['__safe_keys']:
                 self.__delitem__(self._box_config['__safe_keys'][safe_key])
                 del self._box_config['__safe_keys'][safe_key]
                 return
         raise BoxKeyError(err)
Пример #17
0
 def __delattr__(self, item):
     if self._box_config["frozen_box"]:
         raise BoxError("Box is frozen")
     if item == "_box_config":
         raise BoxError('"_box_config" is protected')
     if item in self._protected_keys:
         raise BoxKeyError(f'Key name "{item}" is protected')
     try:
         self.__delitem__(item)
     except KeyError as err:
         if self._box_config["conversion_box"]:
             safe_key = self._safe_attr(item)
             if safe_key in self._box_config["__safe_keys"]:
                 self.__delitem__(self._box_config["__safe_keys"][safe_key])
                 del self._box_config["__safe_keys"][safe_key]
                 return
         raise BoxKeyError(str(err)) from None
Пример #18
0
 def to_yaml(
     self,
     filename: Union[str, PathLike] = None,
     default_flow_style: bool = False,
     encoding: str = "utf-8",
     errors: str = "strict",
     **yaml_kwargs,
 ):
     raise BoxError('yaml is unavailable on this system, please install the "ruamel.yaml" or "PyYAML" package')
Пример #19
0
 def from_msgpack(
     cls,
     msgpack_bytes: bytes = None,
     filename: Union[str, PathLike] = None,
     encoding: str = "utf-8",
     errors: str = "strict",
     **kwargs,
 ):
     raise BoxError('msgpack is unavailable on this system, please install the "msgpack" package')
Пример #20
0
 def from_toml(
     cls,
     toml_string: str = None,
     filename: Union[str, PathLike] = None,
     encoding: str = "utf-8",
     errors: str = "strict",
     **kwargs,
 ) -> "Box":
     raise BoxError('toml is unavailable on this system, please install the "toml" package')
Пример #21
0
 def from_yaml(
     cls,
     yaml_string: str = None,
     filename: Union[str, PathLike] = None,
     encoding: str = "utf-8",
     errors: str = "strict",
     **kwargs,
 ):
     raise BoxError('yaml is unavailable on this system, please install the "ruamel.yaml" or "PyYAML" package')
Пример #22
0
def _from_yaml(
    yaml_string: str = None,
    filename: Union[str, PathLike] = None,
    encoding: str = "utf-8",
    errors: str = "strict",
    ruamel_typ: str = "rt",
    ruamel_attrs: Optional[Dict] = None,
    **kwargs,
):
    if not ruamel_attrs:
        ruamel_attrs = {}
    if filename:
        _exists(filename)
        with open(filename, "r", encoding=encoding, errors=errors) as f:
            if ruamel_available:
                yaml_loader = YAML(typ=ruamel_typ)
                for attr, value in ruamel_attrs.items():
                    setattr(yaml_loader, attr, value)
                data = yaml_loader.load(stream=f)
            elif pyyaml_available:
                if "Loader" not in kwargs:
                    kwargs["Loader"] = yaml.SafeLoader
                data = yaml.load(f, **kwargs)
            else:
                raise BoxError(
                    "No YAML Parser available, please install ruamel.yaml>0.15 or PyYAML"
                )
    elif yaml_string:
        if ruamel_available:
            yaml_loader = YAML(typ=ruamel_typ)
            for attr, value in ruamel_attrs.items():
                setattr(yaml_loader, attr, value)
            data = yaml_loader.load(stream=yaml_string)
        elif pyyaml_available:
            if "Loader" not in kwargs:
                kwargs["Loader"] = yaml.SafeLoader
            data = yaml.load(yaml_string, **kwargs)
        else:
            raise BoxError(
                "No YAML Parser available, please install ruamel.yaml>0.17 or PyYAML"
            )
    else:
        raise BoxError("from_yaml requires a string or filename")
    return data
Пример #23
0
 def __setattr__(self, key, value):
     if key != '_box_config' and self._box_config[
             'frozen_box'] and self._box_config['__created']:
         raise BoxError('Box is frozen')
     if key in self._protected_keys:
         raise BoxKeyError(f'Key name "{key}" is protected')
     if key == '_box_config':
         return object.__setattr__(self, key, value)
     value = self.__recast(key, value)
     self.__setitem__(key, value)
Пример #24
0
def _parse_box_dots(bx, item, setting=False):
    for idx, char in enumerate(item):
        if char == "[":
            return item[:idx], item[idx:]
        elif char == ".":
            if item[:idx] in bx:
                return item[:idx], item[idx + 1:]
    if setting and "." in item:
        return item.split(".", 1)
    raise BoxError("Could not split box dots properly")
Пример #25
0
 def __setitem__(self, key, value):
     if self.box_options.get("frozen_box"):
         raise BoxError("BoxList is frozen")
     if self.box_options.get("box_dots") and isinstance(key, str) and key.startswith("["):
         list_pos = _list_pos_re.search(key)
         pos = int(list_pos.groups()[0])
         if len(list_pos.group()) == len(key):
             return super(BoxList, self).__setitem__(pos, value)
         return super(BoxList, self).__getitem__(pos).__setitem__(key[len(list_pos.group()) :].lstrip("."), value)
     super(BoxList, self).__setitem__(key, value)
Пример #26
0
 def __setattr__(self, key, value):
     if key != "_box_config" and self._box_config["frozen_box"] and self._box_config["__created"]:
         raise BoxError("Box is frozen")
     if key in self._protected_keys:
         raise BoxKeyError(f'Key name "{key}" is protected')
     if key == "_box_config":
         return object.__setattr__(self, key, value)
     safe_key = self._safe_attr(key)
     if safe_key in self._box_config["__safe_keys"]:
         key = self._box_config["__safe_keys"][safe_key]
     self.__setitem__(key, value)
Пример #27
0
 def __delitem__(self, key):
     if self.box_options.get("frozen_box"):
         raise BoxError("BoxList is frozen")
     if self.box_options.get("box_dots") and isinstance(key, str) and key.startswith("["):
         list_pos = _list_pos_re.search(key)
         pos = int(list_pos.groups()[0])
         if len(list_pos.group()) == len(key):
             return super(BoxList, self).__delitem__(pos)
         if hasattr(self[pos], "__delitem__"):
             return self[pos].__delitem__(key[len(list_pos.group()) :].lstrip("."))  # type: ignore
     super(BoxList, self).__delitem__(key)
Пример #28
0
def _from_msgpack(msgpack_bytes: bytes = None,
                  filename: Union[str, PathLike] = None,
                  **kwargs):
    if filename:
        _exists(filename)
        with open(filename, "rb") as f:
            data = msgpack.unpack(f, **kwargs)
    elif msgpack_bytes:
        data = msgpack.unpackb(msgpack_bytes, **kwargs)
    else:
        raise BoxError("from_msgpack requires a string or filename")
    return data
Пример #29
0
    def pop(self, key, *args):
        if self._box_config["frozen_box"]:
            raise BoxError("Box is frozen")

        if args:
            if len(args) != 1:
                raise BoxError('pop() takes only one optional argument "default"')
            try:
                item = self[key]
            except KeyError:
                return args[0]
            else:
                del self[key]
                return item
        try:
            item = self[key]
        except KeyError:
            raise BoxKeyError(f"{key}") from None
        else:
            del self[key]
            return item
Пример #30
0
def _from_toml(toml_string=None,
               filename=None,
               encoding="utf-8",
               errors="strict"):
    if filename:
        _exists(filename)
        with open(filename, 'r', encoding=encoding, errors=errors) as f:
            data = toml.load(f)
    elif toml_string:
        data = toml.loads(toml_string)
    else:
        raise BoxError('from_toml requires a string or filename')
    return data