-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.py
102 lines (79 loc) · 2.6 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
# -*- coding: utf-8 -*-
"""
chemdataextractor.utils
~~~~~~~~~~~~~~~~~~~~~~~
Miscellaneous utility functions.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import errno
import functools
import logging
import os
import six
log = logging.getLogger(__name__)
def memoized_property(fget):
"""Decorator to create memoized properties."""
attr_name = '_{}'.format(fget.__name__)
@functools.wraps(fget)
def fget_memoized(self):
if not hasattr(self, attr_name):
setattr(self, attr_name, fget(self))
return getattr(self, attr_name)
return property(fget_memoized)
def memoize(obj):
"""Decorator to create memoized functions, methods or classes."""
cache = obj.cache = {}
@functools.wraps(obj)
def memoizer(*args, **kwargs):
if args not in cache:
cache[args] = obj(*args, **kwargs)
return cache[args]
return memoizer
def python_2_unicode_compatible(klass):
"""Fix __str__, __unicode__ and __repr__ methods under Python 2."""
if six.PY2:
if '__str__' not in klass.__dict__:
raise ValueError("Define __str__() on %s to use @python_2_unicode_compatible" % klass.__name__)
if '__repr__' not in klass.__dict__:
raise ValueError("Define __repr__() on %s to use @python_2_unicode_compatible" % klass.__name__)
klass.__unicode__ = klass.__str__
klass._unicode_repr = klass.__repr__
klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
klass.__repr__ = lambda self: self._unicode_repr().encode('ascii', errors='backslashreplace')
return klass
class Singleton(type):
"""Singleton metaclass."""
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
def flatten(x):
"""Return a single flat list containing elements from nested lists."""
result = []
for el in x:
if hasattr(el, '__iter__') and not isinstance(el, six.string_types):
result.extend(flatten(el))
else:
result.append(el)
return result
def first(el):
if len(el) > 0:
return el[0]
else:
return None
def last(el):
if len(el) > 0:
return el[-1]
else:
return None
def ensure_dir(path):
"""Ensure a directory exists."""
try:
os.makedirs(path)
except OSError as e:
if e.errno != errno.EEXIST:
raise