Source code for qmat.utils

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Utility function for `qmat`
"""
import inspect
import pkgutil
import functools
from time import time

[docs] def checkOverriding(cls, name, isProperty=True): """Check if a class overrides a method with a given name""" method = getattr(cls, name) parent = getattr(cls.mro()[-2], name) assert method != parent, \ f"{name} method must be overriden in {cls.__name__} class" if isProperty: assert type(method) == property, \ f"{name} method must be a property in {cls.__name__} class" else: pass
# TODO : check that signatures are the same
[docs] def checkGenericConstr(cls): """Check if a class implement a constructor with a `**kwargs` generic parameter""" sig = inspect.signature(cls.__init__) try: par = sig.parameters["kwargs"] assert par.kind == par.VAR_KEYWORD except (KeyError, AssertionError): raise AssertionError(f"{cls.__name__} class requires **kwargs in its constructor")
[docs] def storeAlias(cls, dico, alias): """Store a class into a dictionary with a given alias""" assert alias not in dico, f"{alias} alias already registered in {dico}" dico[alias] = cls
[docs] def storeClass(cls, dico): """Store a class into a dictionary""" storeAlias(cls, dico, cls.__name__) aliases = getattr(cls, "aliases", None) if aliases: assert isinstance(aliases, list), \ f"aliases must be a list in class {cls.__name__}" for alias in aliases: storeAlias(cls, dico, alias)
[docs] def importAll(localVars, __all__, __path__, __name__, __import__): """Import all submodules in the current (sub-)package""" __all__ += [var for var in localVars.keys() if not var.startswith('__')] for _, moduleName, _ in pkgutil.walk_packages(__path__): __all__.append(moduleName) __import__(__name__+'.'+moduleName)
[docs] def getClasses(dico, module=None): """Retrieve all classes stored into a dictionary, filtering aliases""" classes = {} if module is None: check = lambda cls: True else: check = lambda cls: cls.__module__.endswith("."+module) for key, cls in dico.items(): if cls not in classes.values() and check(cls): classes[key] = cls return classes
[docs] def useQGen(__init__): r""" Wrapper to extract :math:`Q_\Delta`-generator parameters from `kwargs` arguments, using either a :math:`Q`-generator `qGen` or separately given parameters. """ pNames = [p.name for p in inspect.signature(__init__).parameters.values() if (p.kind == p.POSITIONAL_OR_KEYWORD) and p.name != "self"] @functools.wraps(__init__) def wrapper(self, *args, **kwargs): if "coll" in kwargs: # TODO : remove in future version import warnings warnings.warn("using the `coll` argument is deprecated. Use `qGen` instead!", DeprecationWarning) assert "qGen" not in kwargs, "`coll` and `qGen` given together, that's an ambiguous call !" kwargs["qGen"] = kwargs.pop("coll") params = {name: value for name, value in zip(pNames, args)} qGen = kwargs.pop("qGen", None) params.update(kwargs) if qGen is not None: qGenParams = self.extractParams(qGen) qGenParams.update(params) params = qGenParams __init__(self, **params) return wrapper
[docs] class Timer(): """ Utility Timer class, that can be used as follow : >>> with Timer("stuff"): # prints "Starting stuff ... >>> # ... do stuff >>> # prints " -- tWall : {tWall}s The description at the end can be replaced using the `descr` constructor parameter, and the final wall time can be scaled using the `scale` parameter. Can also be used like this : >>> clock = Timer("stuff") >>> clock.start() >>> # ... do stuff >>> clock.stop() >>> tWall = clock.tWall """ def __init__(self, name, scale=1, descr="tWall"): self.name = name self.scale = scale self.descr = descr
[docs] def start(self): print(f"Starting {self.name} ...") self.tStart = time()
[docs] def stop(self): self.tWall = time() - self.tStart self.tWall /= self.scale print(f" -- {self.descr} : {self.tWall:1.2e}s")
def __enter__(self): self.start() def __exit__(self, exc_type, exc_value, traceback): self.stop()