Source code for jacinle.utils.container

#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# File   : container.py
# Author : Jiayuan Mao
# Email  : maojiayuan@gmail.com
# Date   : 01/18/2018
#
# This file is part of Jacinle.
# Distributed under terms of the MIT license.

import copy
import collections
from typing import Any, Optional, Iterable

from jacinle.utils.meta import repr_from_str
from jacinle.utils.printing import kvformat, kvprint

__all__ = ['G', 'g', 'GView', 'SlotAttrObject', 'OrderedSet']


[docs] class G(dict): """A simple container that wraps a dict and provides attribute access to the dict. Example: >>> g = G() >>> g.a = 1 >>> g['b'] = 2 """ def __getattr__(self, k): if k not in self: raise AttributeError return self[k] def __setattr__(self, k, v): self[k] = v def __delattr__(self, k): del self[k]
[docs] def format(self, sep=': ', end='\n'): """Format the dict as a string using :func:`jacinle.utils.printing.kvformat`.""" return kvformat(self, sep=sep, end=end)
[docs] def print(self, sep=': ', end='\n', file=None): """Print the dict using :func:`jacinle.utils.printing.kvprint`.""" return kvprint(self, sep=sep, end=end, file=file)
g = G() """A simple global dict-like object."""
[docs] class GView(object): """A simple container that wraps a dict and provides attribute access to the dict. In contrast to :class:`G`, this class wraps around an existing dict."""
[docs] def __init__(self, dict_=None): """Initialize the container.""" if dict_ is None: dict_ = dict() object.__setattr__(self, '_dict', dict_)
def __getattr__(self, k): if k not in self.raw(): raise AttributeError return self.raw()[k] def __setattr__(self, k, v): self.raw()[k] = v def __delattr__(self, k): del self.raw()[k] def __getitem__(self, k): return self.raw()[k] def __setitem__(self, k, v): self.raw()[k] = v def __delitem__(self, k): del self.raw()[k] def __contains__(self, k): return k in self.raw() def __iter__(self): return iter(self.raw().items())
[docs] def raw(self): """Return the underlying :class:`dict`.""" return object.__getattribute__(self, '_dict')
[docs] def update(self, other): """Update the underlying dict with another dict.""" self.raw().update(other)
[docs] def keys(self): """Return the keys of the underlying dict.""" return self.raw().keys()
[docs] def values(self): """Return the values of the underlying dict.""" return self.raw().values()
[docs] def items(self): """Iterate over the items of the underlying dict.""" return self.raw().items()
[docs] def copy(self): """Return a shallow copy of the underlying dict.""" return GView(self.raw().copy())
[docs] def format(self, sep=': ', end='\n'): """Format the dict as a string using :func:`jacinle.utils.printing.kvformat`.""" return kvformat(self.raw(), sep=sep, end=end)
[docs] def print(self, sep=': ', end='\n', file=None): """Print the dict using :func:`jacinle.utils.printing.kvprint`.""" return kvprint(self.raw(), sep=sep, end=end, file=file)
def __str__(self): return self.format() __repr__ = repr_from_str
[docs] class SlotAttrObject(object): """Create a object that allows only a fixed set of attributes to be set."""
[docs] def __init__(self, **kwargs): """Initialize the object. Args: kwargs: the attributes to be set. """ for k, v in kwargs.items(): setattr(self, k, v)
[docs] def update(self, **kwargs): """Update the attributes of the object.""" for k, v in kwargs.items(): setattr(self, k, v)
[docs] def clone(self, deep: bool = False): """Return a shallow or a deep copy of the object.""" if deep: return copy.deepcopy(self) return copy.copy(self)
def __setattr__(self, k, v): assert not k.startswith('_') if k not in type(self).__dict__: # do not use hasattr; since it may result in infinite recursion raise AttributeError( '{}: could not set non-existing attribute {}'.format( self, k)) cvt = getattr(type(self), '_convert_{}'.format(k), None) if cvt is not None: v = cvt(v) super().__setattr__(k, v)
[docs] class OrderedSet(object): """A set that keeps the order of the elements."""
[docs] def __init__(self, initial_list: Optional[Iterable[Any]] = None): """Initialize the set. Args: initial_list: the initial list of elements. """ if initial_list is not None: self._dict = collections.OrderedDict([(v, True) for v in initial_list]) else: self._dict = collections.OrderedDict()
[docs] def as_list(self): """Return the elements as a list.""" return list(self._dict.keys())
[docs] def append(self, value): """Append an element to the set.""" self._dict[value] = True
[docs] def remove(self, value): """Remove an element from the set.""" del self._dict[value]
def __contains__(self, value): return value in self._dict def __iter__(self): yield from self._dict.keys()