Source code for logilab.common

# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of logilab-common.
#
# logilab-common is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 2.1 of the License, or (at your option) any
# later version.
#
# logilab-common is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with logilab-common.  If not, see <http://www.gnu.org/licenses/>.
"""Logilab common library (aka Logilab's extension to the standard library).

:type STD_BLACKLIST: tuple
:var STD_BLACKLIST: directories ignored by default by the functions in
  this package which have to recurse into directories

:type IGNORED_EXTENSIONS: tuple
:var IGNORED_EXTENSIONS: file extensions that may usually be ignored
"""
__docformat__ = "restructuredtext en"

import sys
import types

if sys.version_info < (3, 10):
    from importlib_metadata import version
else:
    from importlib.metadata import version

from typing import List, Sequence

__version__ = version("logilab-common")

# deprecated, but keep compatibility with pylint < 1.4.4
__pkginfo__ = types.ModuleType("__pkginfo__")
__pkginfo__.__package__ = __name__
# mypy output: Module has no attribute "version"
# logilab's magic
__pkginfo__.version = __version__  # type: ignore
sys.modules["logilab.common.__pkginfo__"] = __pkginfo__

STD_BLACKLIST = ("CVS", ".svn", ".hg", ".git", ".tox", "debian", "dist", "build")

IGNORED_EXTENSIONS = (".pyc", ".pyo", ".elc", "~", ".swp", ".orig")

# set this to False if you've mx DateTime installed but you don't want your db
# adapter to use it (should be set before you got a connection)
USE_MX_DATETIME = True


[docs]class attrdict(dict): """A dictionary for which keys are also accessible as attributes.""" def __getattr__(self, attr: str) -> str: try: return self[attr] except KeyError: raise AttributeError(attr)
[docs]class dictattr(dict): def __init__(self, proxy): self.__proxy = proxy def __getitem__(self, attr): try: return getattr(self.__proxy, attr) except AttributeError: raise KeyError(attr)
[docs]class nullobject: def __repr__(self): return "<nullobject>" def __bool__(self): return False __nonzero__ = __bool__
[docs]class tempattr: def __init__(self, obj, attr, value): self.obj = obj self.attr = attr self.value = value def __enter__(self): self.oldvalue = getattr(self.obj, self.attr) setattr(self.obj, self.attr, self.value) return self.obj def __exit__(self, exctype, value, traceback): setattr(self.obj, self.attr, self.oldvalue)
# flatten ----- # XXX move in a specific module and use yield instead # do not mix flatten and translate # # def iterable(obj): # try: iter(obj) # except: return False # return True # # def is_string_like(obj): # try: obj +'' # except (TypeError, ValueError): return False # return True # # def is_scalar(obj): # return is_string_like(obj) or not iterable(obj) # # def flatten(seq): # for item in seq: # if is_scalar(item): # yield item # else: # for subitem in flatten(item): # yield subitem
[docs]def flatten(iterable, tr_func=None, results=None): """Flatten a list of list with any level. If tr_func is not None, it should be a one argument function that'll be called on each final element. :rtype: list >>> flatten([1, [2, 3]]) [1, 2, 3] """ if results is None: results = [] for val in iterable: if isinstance(val, (list, tuple)): flatten(val, tr_func, results) elif tr_func is None: results.append(val) else: results.append(tr_func(val)) return results
# XXX is function below still used ?
[docs]def make_domains(lists): """ Given a list of lists, return a list of domain for each list to produce all combinations of possibles values. :rtype: list Example: >>> make_domains(['a', 'b'], ['c','d', 'e']) [['a', 'b', 'a', 'b', 'a', 'b'], ['c', 'c', 'd', 'd', 'e', 'e']] """ domains = [] for iterable in lists: new_domain = iterable[:] for i in range(len(domains)): domains[i] = domains[i] * len(iterable) if domains: missing = (len(domains[0]) - len(iterable)) / len(iterable) i = 0 for j in range(len(iterable)): value = iterable[j] for dummy in range(missing): new_domain.insert(i, value) i += 1 i += 1 domains.append(new_domain) return domains
# private stuff ################################################################ def _handle_blacklist(blacklist: Sequence[str], dirnames: List[str], filenames: List[str]) -> None: """remove files/directories in the black list dirnames/filenames are usually from os.walk """ for norecurs in blacklist: if norecurs in dirnames: dirnames.remove(norecurs) elif norecurs in filenames: filenames.remove(norecurs)