Source code for woom.util

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Misc utilities
"""
import collections
import json
import logging
import os
import re
import subprocess
import sys

import pandas as pd


[docs] class WoomDate(pd.Timestamp): re_match_since = re.compile(r"^(years|months|days|hours|minutes|seconds)\s+since\s+(\d+.*)$", re.I).match # re_match_add = re.compile(r"^([+\-].+)$").match def __new__(cls, date, round=None): if isinstance(date, str) and date in ["now", "today"]: date = pd.to_datetime(date, utc=True) else: date = pd.to_datetime(date) if date.tzinfo is None: date = date.tz_localize("utc") # date = pd.to_datetime(date, utc=utc) # if utc: # date = date.tz_localize(None) if round: date = date.round(round) instance = super().__new__(cls, date) instance.__class__ = cls return instance def __format__(self, spec): m = self.re_match_since(spec) if m: units, origin = m.groups() origin = pd.to_datetime(origin) if origin.tzinfo is None: origin = origin.tz_localize("utc") return "{:g}".format((self - pd.to_datetime(origin)) / pd.to_timedelta(1, units)) return super().__format__(spec)
[docs] def add(self, *args, **kwargs): """Add time delta""" date = self for arg in args: date = date + pd.to_timedelta(arg) for unit, value in kwargs.items(): date = date + pd.to_timedelta(value, unit) return date
[docs] def check_dir(filepath, dry=False, logger=None): """Make sure that the directory that contains file exists Parameters ---------- filepath: str File path dry: bool Fake mode. Do not create the directory logger: logging.Logger To inform that we create the directory, even in dry mode Return ------ """ if logger is None: logger = logging.getLogger(__name__) filepath = os.path.abspath(filepath) dirname = os.path.dirname(filepath) if not os.path.exists(dirname): if logger: logger.debug(f"Creating directory: {dirname}") if not dry: os.makedirs(dirname) if logger: logger.info(f"Created directory: {dirname}") return filepath
[docs] class WoomJSONEncoder(json.JSONEncoder):
[docs] def default(self, obj): if isinstance(obj, collections.UserDict): return dict(obj) if hasattr(obj, "pid") or isinstance(obj, subprocess.Popen): return obj.pid try: return super().default(obj) except TypeError: return str(obj)
[docs] def params2env_vars(params=None, select=None, **extra_params): """Convert a dict of parameters to env vars start whose name starts with ``'WOOM_'``""" if params is None: params = extra_params else: params = params.copy() params.update(extra_params) env_vars = {} for key, value in params.items(): if select and key not in select: continue if isinstance(value, (pd.Timestamp, pd.Timedelta)): value = value.isoformat() if value is None: value = "" if isinstance(value, bool): value = str(int(value)) env_vars["WOOM_" + key.upper()] = str(value) return env_vars
[docs] def pages2ints(pages, n): """Convert a list of 1-based integers and zero-based slices to a pure list of one-based integers""" out = [] indices = [i + 1 for i in range(n)] for page in pages: if isinstance(page, int): out.append(page) else: out.extend(indices[page]) return out
#: Available colors COLORS = { "bold": "\033[1m", "green": "\033[32m", "yellow": "\033[33m", "red": "\033[31m", "reset": "\033[0m", }
[docs] def colorize(text, mapping, colorize=True): """Colorize text depending on mapping. Parameters ---------- text: str Test to colorize mapping: dict Keys are regular expressions and values are valid :data:`COLORS`. colorize: bool Whether to colorize or not. Return ------ str """ if not colorize or not sys.stdout.isatty(): return text for pattern, color in mapping.items(): m = re.match(pattern, text) if m: cc = "" for c in color.split("_"): cc += COLORS[c] return cc + text + COLORS["reset"] return text