Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from typing import Any, Callable, Dict, List, Optional, Union
3from itertools import dropwhile, takewhile
4from pathlib import Path
5import inspect
6import logging
7import os
9import wrapt
11LOG_LEVEL = os.environ.get('LOG_LEVEL', 'WARNING').upper()
12logging.basicConfig(level=LOG_LEVEL)
13LOGGER = logging.getLogger(__name__)
14# ------------------------------------------------------------------------------
16'''
17Imports only python builtins and contains only function for use within or
18outside of Docker environment (ie no dependencies or specific python versions.)
19'''
22def relative_path(module, path):
23 # type: (Union[str, Path], Union[str, Path]) -> Path
24 '''
25 Resolve path given current module's file path and given suffix.
27 Args:
28 module (str or Path): Always __file__ of current module.
29 path (str or Path): Path relative to __file__.
31 Returns:
32 Path: Resolved Path object.
33 '''
34 module_root = Path(module).parent
35 path_ = Path(path).parts # type: Any
36 path_ = list(dropwhile(lambda x: x == ".", path_))
37 up = len(list(takewhile(lambda x: x == "..", path_)))
38 path_ = Path(*path_[up:])
39 root = list(module_root.parents)[up - 1]
40 output = Path(root, path_).absolute()
42 LOGGER.debug(
43 f'relative_path called with: {module} and {path_}. Returned: {output}')
44 return output
47def get_function_signature(function):
48 # type: (Callable) -> Dict
49 '''
50 Inspect a given function and return its arguments as a list and its keyword
51 arguments as a dict.
53 Args:
54 function (function): Function to be inspected.
56 Returns:
57 dict: args and kwargs.
58 '''
59 spec = inspect.getfullargspec(function)
60 args = list(spec.args)
61 kwargs = {} # type: Any
62 if spec.defaults is not None:
63 args = args[:-len(spec.defaults)]
64 kwargs = list(spec.args)[-len(spec.defaults):]
65 kwargs = dict(zip(kwargs, spec.defaults))
66 return dict(args=args, kwargs=kwargs)
69def api_function(wrapped=None, **kwargs):
70 # type: (Optional[Callable], **Any) -> Callable
71 '''
72 A decorator that enforces keyword argument only function signatures and
73 required keyword argument values when called.
75 Args:
76 wrapped (function): For dev use. Default: None.
77 \*\*kwargs (dict): Keyword arguments. # noqa: W605
79 Raises:
80 TypeError: If non-keyword argument found in functionn signature.
81 ValueError: If keyword arg with value of '<required>' is found.
83 Returns:
84 api function.
85 '''
86 @wrapt.decorator
87 def wrapper(wrapped, instance, args, kwargs):
88 sig = get_function_signature(wrapped)
90 # ensure no arguments are present
91 if len(sig['args']) > 0:
92 msg = 'Function may only have keyword arguments. '
93 msg += f"Found non-keyword arguments: {sig['args']}."
94 raise TypeError(msg)
96 # ensure all required kwarg values are present
97 params = sig['kwargs']
98 params.update(kwargs)
99 for key, val in params.items():
100 if val == '<required>':
101 msg = f'Missing required keyword argument: {key}.'
102 raise ValueError(msg)
104 LOGGER.debug(f'{wrapped} called with {params}.')
105 return wrapped(*args, **kwargs)
106 return wrapper(wrapped)
109def is_standard_module(name):
110 # type: (str) -> bool
111 '''
112 Determines if given module name is a python builtin.
114 Args:
115 name (str): Python module name.
117 Returns:
118 bool: Whether string names a python module.
119 '''
120 return name in _PYTHON_STANDARD_MODULES
123_PYTHON_STANDARD_MODULES = [
124 '__future__',
125 '__main__',
126 '_dummy_thread',
127 '_thread',
128 'abc',
129 'aifc',
130 'argparse',
131 'array',
132 'ast',
133 'asynchat',
134 'asyncio',
135 'asyncore',
136 'atexit',
137 'audioop',
138 'base64',
139 'bdb',
140 'binascii',
141 'binhex',
142 'bisect',
143 'builtins',
144 'bz2',
145 'calendar',
146 'cgi',
147 'cgitb',
148 'chunk',
149 'cmath',
150 'cmd',
151 'code',
152 'codecs',
153 'codeop',
154 'collections',
155 'collections.abc',
156 'colorsys',
157 'compileall',
158 'concurrent',
159 'concurrent.futures',
160 'configparser',
161 'contextlib',
162 'contextvars',
163 'copy',
164 'copyreg',
165 'cProfile',
166 'crypt',
167 'csv',
168 'ctypes',
169 'curses',
170 'curses.ascii',
171 'curses.panel',
172 'curses.textpad',
173 'dataclasses',
174 'datetime',
175 'dbm',
176 'dbm.dumb',
177 'dbm.gnu',
178 'dbm.ndbm',
179 'decimal',
180 'difflib',
181 'dis',
182 'distutils',
183 'distutils.archive_util',
184 'distutils.bcppcompiler',
185 'distutils.ccompiler',
186 'distutils.cmd',
187 'distutils.command',
188 'distutils.command.bdist',
189 'distutils.command.bdist_dumb',
190 'distutils.command.bdist_msi',
191 'distutils.command.bdist_packager',
192 'distutils.command.bdist_rpm',
193 'distutils.command.bdist_wininst',
194 'distutils.command.build',
195 'distutils.command.build_clib',
196 'distutils.command.build_ext',
197 'distutils.command.build_py',
198 'distutils.command.build_scripts',
199 'distutils.command.check',
200 'distutils.command.clean',
201 'distutils.command.config',
202 'distutils.command.install',
203 'distutils.command.install_data',
204 'distutils.command.install_headers',
205 'distutils.command.install_lib',
206 'distutils.command.install_scripts',
207 'distutils.command.register',
208 'distutils.command.sdist',
209 'distutils.core',
210 'distutils.cygwinccompiler',
211 'distutils.debug',
212 'distutils.dep_util',
213 'distutils.dir_util',
214 'distutils.dist',
215 'distutils.errors',
216 'distutils.extension',
217 'distutils.fancy_getopt',
218 'distutils.file_util',
219 'distutils.filelist',
220 'distutils.log',
221 'distutils.msvccompiler',
222 'distutils.spawn',
223 'distutils.sysconfig',
224 'distutils.text_file',
225 'distutils.unixccompiler',
226 'distutils.util',
227 'distutils.version',
228 'doctest',
229 'dummy_threading',
230 'email',
231 'email.charset',
232 'email.contentmanager',
233 'email.encoders',
234 'email.errors',
235 'email.generator',
236 'email.header',
237 'email.headerregistry',
238 'email.iterators',
239 'email.message',
240 'email.mime',
241 'email.parser',
242 'email.policy',
243 'email.utils',
244 'encodings',
245 'encodings.idna',
246 'encodings.mbcs',
247 'encodings.utf_8_sig',
248 'ensurepip',
249 'enum',
250 'errno',
251 'faulthandler',
252 'fcntl',
253 'filecmp',
254 'fileinput',
255 'fnmatch',
256 'formatter',
257 'fractions',
258 'ftplib',
259 'functools',
260 'gc',
261 'getopt',
262 'getpass',
263 'gettext',
264 'glob',
265 'grp',
266 'gzip',
267 'hashlib',
268 'heapq',
269 'hmac',
270 'html',
271 'html.entities',
272 'html.parser',
273 'http',
274 'http.client',
275 'http.cookiejar',
276 'http.cookies',
277 'http.server',
278 'imaplib',
279 'imghdr',
280 'imp',
281 'importlib',
282 'importlib.abc',
283 'importlib.machinery',
284 'importlib.resources',
285 'importlib.util',
286 'inspect',
287 'io',
288 'ipaddress',
289 'itertools',
290 'json',
291 'json.tool',
292 'keyword',
293 'lib2to3',
294 'linecache',
295 'locale',
296 'logging',
297 'logging.config',
298 'logging.handlers',
299 'lzma',
300 'macpath',
301 'mailbox',
302 'mailcap',
303 'marshal',
304 'math',
305 'mimetypes',
306 'mmap',
307 'modulefinder',
308 'msilib',
309 'msvcrt',
310 'multiprocessing',
311 'multiprocessing.connection',
312 'multiprocessing.dummy',
313 'multiprocessing.managers',
314 'multiprocessing.pool',
315 'multiprocessing.sharedctypes',
316 'netrc',
317 'nis',
318 'nntplib',
319 'numbers',
320 'operator',
321 'optparse',
322 'os',
323 'os.path',
324 'ossaudiodev',
325 'parser',
326 'pathlib',
327 'pdb',
328 'pickle',
329 'pickletools',
330 'pipes',
331 'pkgutil',
332 'platform',
333 'plistlib',
334 'poplib',
335 'posix',
336 'pprint',
337 'profile',
338 'pstats',
339 'pty',
340 'pwd',
341 'py_compile',
342 'pyclbr',
343 'pydoc',
344 'queue',
345 'quopri',
346 'random',
347 're',
348 'readline',
349 'reprlib',
350 'resource',
351 'rlcompleter',
352 'runpy',
353 'sched',
354 'secrets',
355 'select',
356 'selectors',
357 'shelve',
358 'shlex',
359 'shutil',
360 'signal',
361 'site',
362 'smtpd',
363 'smtplib',
364 'sndhdr',
365 'socket',
366 'socketserver',
367 'spwd',
368 'sqlite3',
369 'ssl',
370 'stat',
371 'statistics',
372 'string',
373 'stringprep',
374 'struct',
375 'subprocess',
376 'sunau',
377 'symbol',
378 'symtable',
379 'sys',
380 'sysconfig',
381 'syslog',
382 'tabnanny',
383 'tarfile',
384 'telnetlib',
385 'tempfile',
386 'termios',
387 'test',
388 'test.support',
389 'test.support.script_helper',
390 'textwrap',
391 'threading',
392 'time',
393 'timeit',
394 'tkinter',
395 'tkinter.scrolledtext',
396 'tkinter.tix',
397 'tkinter.ttk',
398 'token',
399 'tokenize',
400 'trace',
401 'traceback',
402 'tracemalloc',
403 'tty',
404 'turtle',
405 'turtledemo',
406 'types',
407 'typing',
408 'unicodedata',
409 'unittest',
410 'unittest.mock',
411 'urllib',
412 'urllib.error',
413 'urllib.parse',
414 'urllib.request',
415 'urllib.response',
416 'urllib.robotparser',
417 'uu',
418 'uuid',
419 'venv',
420 'warnings',
421 'wave',
422 'weakref',
423 'webbrowser',
424 'winreg',
425 'winsound',
426 'wsgiref',
427 'wsgiref.handlers',
428 'wsgiref.headers',
429 'wsgiref.simple_server',
430 'wsgiref.util',
431 'wsgiref.validate',
432 'xdrlib',
433 'xml',
434 'xml.dom',
435 'xml.dom.minidom',
436 'xml.dom.pulldom',
437 'xml.etree.ElementTree',
438 'xml.parsers.expat',
439 'xml.parsers.expat.errors',
440 'xml.parsers.expat.model',
441 'xml.sax',
442 'xml.sax.handler',
443 'xml.sax.saxutils',
444 'xml.sax.xmlreader',
445 'xmlrpc',
446 'xmlrpc.client',
447 'xmlrpc.server',
448 'zipapp',
449 'zipfile',
450 'zipimport',
451 'zlib'
452] # type: List[str]