Source code for solidbyte.common.utils

import hashlib
from typing import Iterable
from shutil import which
from pathlib import Path
from datetime import datetime as datetime

BUILDDIR_NAME = 'build'
SUPPORTED_EXTENSIONS = ('sol', 'vy')
JS_DATE_FORMAT = '%Y-%m-%dT%H:%M:%S.%f'


[docs]class Py36Datetime(datetime): """ Monkeypatch datetime for python<3.7 """
[docs] def fromisoformat(s): """ Load an :code:`datetime.isoformat()` date string as a :code:`datetime` object """ return datetime.strptime(s, JS_DATE_FORMAT)
[docs]def builddir(loc=None): """ Get (and create if necessary) the temporary build dir :param loc: (:class:`pathlib.Path`) to workdir (default: pwd) :returns: (:class:`pathlib.Path`) to build dir """ if loc is None: loc = Path.cwd() full_path = Path(loc, BUILDDIR_NAME) if not full_path.exists(): full_path.mkdir() elif not full_path.is_dir(): raise FileExistsError("{} exists and is blocking the build directory creation!".format( full_path )) return full_path
[docs]def get_filename_and_ext(filename): """ Return the filename and extension as a tuple :param filename: (:class:`pathlib.Path`) of file :returns: (:code:`tuple`) of (name, extension) """ if isinstance(filename, Path): filename = filename.name cmps = filename.split('.') if len(cmps) < 2: return (filename, '') ext = cmps.pop() return ('.'.join(cmps), ext)
[docs]def supported_extension(filename): """ Check if the provided filename has a supported source code extension :param filename: (:class:`pathlib.Path`) of file :returns: (:code:`bool`) if it's supported """ _, ext = get_filename_and_ext(filename) if ext in SUPPORTED_EXTENSIONS: return True return False
[docs]def source_filename_to_name(filename): """ Change a source filename to a plain name :param filename: (:class:`pathlib.Path`) of file :returns: (:code:`str`) name of file without extension """ if not supported_extension(filename): raise ValueError("Invalid source filename") name, _ = get_filename_and_ext(filename) return name
[docs]def collapse_oel(lst): """ Collapse a one-element list to a single var :param filename: (:code:`list`) with one element to collapse :returns: (:code:`Any`) the single element """ if type(lst) != list: raise ValueError("Not a list") if len(lst) != 1: raise ValueError("List has multiple elements") return lst[0]
[docs]def pop_key_from_dict(d, key): """ Remove and return an element from a dict and the modded dict without throwing an exception if a key does not exist. :param d: (:code:`dict`) the original dict :param key: (:code:`str`) they key to pop :returns: (:code:`T`) The value of the key or None """ if key not in d: return None val = d.get(key) del d[key] return val
[docs]def all_defs_in(items: Iterable, di: dict) -> bool: """ Check if all defs(tuple of name/placeholder) are in di :param items: (:code:`Iterable`) to check against di :param di: (:code:`dict`) the dict to check against :returns: (:code:`bool`) if all defs are in the dict """ for i in items: if i[0] not in di: return False return True
[docs]def defs_not_in(items: Iterable, di: dict) -> set: """ Find defs (tuple of name/placeholder) that aren't keys in a dict :param items: (:code:`Iterable`) to check against di :param di: (:code:`dict`) the dict to check against :returns: (:code:`set`) any defs not in di """ missing_items = set() for i in items: if i[0] not in di: missing_items.add(i[0]) return missing_items
[docs]def find_vyper(): """ Get the path to vyper. **DEPRECIATED** """ return which('vyper')
[docs]def hash_file(_file: Path) -> str: """ Get an sha1 hash of a file :param _file: (:class:`pathlib.Path`) the file to hash :returns: (:code:`str`) hex sha1 hash of the given file """ if not _file or not isinstance(_file, Path) or not _file.is_file(): raise ValueError("Invalid _file given to hash_file()") CHUNK_SIZE = 65536 _hash = hashlib.sha1() with _file.open() as f: while True: chunk = f.read(CHUNK_SIZE) if not chunk: break _hash.update(chunk.encode('utf-8')) return _hash.hexdigest()
[docs]def to_path(v) -> Path: """ Given a Path or str, return a Path :param v: (:code:`str` or :class:`pathlib.Path`) :returns: (:class:`pathlib.Path`) """ if isinstance(v, Path): return v return Path(v).expanduser().resolve()
[docs]def to_path_or_cwd(v) -> Path: """ Given a Path, str, or None, return a Path of the given path or the current working directory :param v: (:code:`str` or :class:`pathlib.Path`) :returns: (:class:`pathlib.Path`) """ if not v: return Path.cwd() return to_path(v)
[docs]def keys_with(thedict, term): """ Return any keys from :code:`thedict` that have :code:`term` in their value :param thedict: (:code:`dict`) The dict to search :param term: (:code:`Any`) The value to look for :returns: (:code:`list`) List of keys that match """ keys = [] for k, v in thedict.items(): if term in v: keys.append(k) return keys
[docs]def unescape_newlines(s): """ Unescape newlines in a text string :param s: (:code:`str`) String to search and replace against :returns: (:code:`str`) String with unescaped newlines """ if type(s) == bytes: s = s.decode('utf-8') return s.replace('\\n', '\n')