-
Notifications
You must be signed in to change notification settings - Fork 21
/
utils.py
118 lines (90 loc) · 3.23 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# This code is part of OpenFE and is licensed under the MIT license.
# For details, see https://github.com/OpenFreeEnergy/openfe
import click
import importlib
import functools
from typing import Callable, Optional
from datetime import datetime
import logging
def import_thing(import_string: str):
"""Obtain an object from a valid qualname (or fully qualified name)
Parameters
----------
import_string : str
the qualname
Returns
-------
Any :
the object from that namespace
"""
splitted = import_string.split('.')
if len(splitted) > 1:
# if the string has a dot, import the module and getattr the object
obj = splitted[-1]
mod = ".".join(splitted[:-1])
module = importlib.import_module(mod)
result = getattr(module, obj)
else:
# if there is no dot, import and return the module
mod = splitted[0]
result = importlib.import_module(mod)
return result
def write(string: str):
"""
This is abstracted so that we can change output mechanism here and it
will automatically update in all commands.
"""
click.echo(string)
def _should_configure_logger(logger: logging.Logger):
"""Determine whether a logger should be configured.
Separated from configure_logger for ease of testing.
"""
if isinstance(logger, logging.LoggerAdapter):
logger = logger.logger
if logger.hasHandlers():
return False
# walk up the logging tree to see if any parent loggers are not default
l = logger
while (
l.parent is not None # not the root logger
and l.level == logging.NOTSET # level not already set
and l.propagate # configured to use parent when not set
):
l = l.parent
is_default = (l == logging.root and l.level == logging.WARNING)
return is_default
def configure_logger(logger_name: str, level: int = logging.INFO, *,
handler: Optional[logging.Handler] = None):
"""Configure the logger at ``logger_name`` to be at ``level``.
This is used to prevent accidentally overwriting existing logging
configurations.
This is particularly useful for setting INFO-level log messages to be
seen in the CLI (with the default handler/formatter).
Parameters
----------
logger_name: str
name of the logger to configure
level: int
level to set the logger to use, typically one of the constants
defined in the ``logging`` module.
"""
logger = logging.getLogger(logger_name)
if _should_configure_logger(logger):
logger.setLevel(level)
if handler is not None:
logger.addHandler(handler)
def print_duration(function: Callable) -> Callable:
"""
Helper function to denote that a function should print a duration information.
A function decorated with this decorator will print out the execution time of
the decorated function.
"""
@functools.wraps(function)
def wrapper(*args, **kwargs):
start_time = datetime.now()
result = function(*args, **kwargs)
end_time = datetime.now()
duration = end_time - start_time
write("\tDuration: " + str(duration) + "\n")
return result
return wrapper