Skip to content

Commit edab71b

Browse files
committed
Added new tests and updated some functions
1 parent 2ded3a5 commit edab71b

File tree

9 files changed

+672
-84
lines changed

9 files changed

+672
-84
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ python:
55
- '3.7'
66
- "3.8"
77
install:
8-
- pip install -U coveralls pytest
8+
- pip install -U coveralls pytest pytz
99
script:
1010
- coverage run --source=domdf_python_tools -m pytest
1111
after_success:

domdf_python_tools/dates.py

+75-19
Original file line numberDiff line numberDiff line change
@@ -38,32 +38,92 @@
3838
try:
3939
import pytz
4040

41-
def current_tzinfo():
41+
42+
def get_utc_offset(tz, date=None):
4243
"""
43-
Returns a tzinfo object for the current timezone
44+
Returns the offset between UTC and the requested timezone on the given date.
45+
If ``date`` is ``None`` then the current date is used.
4446
45-
:rtype: :class:`~python:datetime.tzinfo`
47+
:param tz: :class:`pytz.timezone` or a string representing the timezone
48+
:type tz:
49+
:param date:
50+
:type date: :class:`python:datetime.datetime` or None, optional
51+
:return:
52+
:rtype: :class:`python:datetime.timedelta`
4653
"""
4754

48-
return datetime.datetime.now().astimezone().tzinfo
55+
if date is None:
56+
date = datetime.datetime.utcnow()
57+
58+
if isinstance(tz, str):
59+
tz = get_timezone(tz, date)
60+
61+
return date.replace(tzinfo=pytz.utc).astimezone(tz).utcoffset()
4962

5063

51-
def datetime_to_utc_timestamp(datetime, current_tzinfo=None):
64+
def get_timezone(tz, date=None):
65+
"""
66+
Returns a localized :class:`pytz.timezone` object for the given date.
67+
If ``date`` is ``None`` then the current date is used.
68+
69+
:param tz: A string representing a pytz timezone
70+
:type tz:
71+
:param date:
72+
:type date: :class:`python:datetime.datetime` or None, optional
73+
:return:
74+
:rtype: :class:`python:datetime.timedelta`
5275
"""
53-
Convert a :class:`datetime.datetime` object to seconds since UNIX epoch, in UTC time
5476

55-
:param datetime:
56-
:type datetime: :class:`datetime.datetime`
57-
:param current_tzinfo: A tzinfo object representing the current timezone.
58-
If None it will be inferred.
59-
:type current_tzinfo: :class:`~python:datetime.tzinfo`
77+
if date is None:
78+
date = datetime.datetime.utcnow()
79+
80+
d = date.replace(tzinfo=None)
81+
82+
return pytz.timezone(tz).localize(d).tzinfo
83+
84+
85+
def current_tzinfo():
86+
"""
87+
Returns a tzinfo object for the current timezone
6088
61-
:return: Timestamp in UTC timezone
62-
:rtype: float
89+
:rtype: :class:`python:datetime.tzinfo`
6390
"""
6491

65-
return datetime.astimezone(current_tzinfo).replace(tzinfo=pytz.UTC).timestamp()
92+
return datetime.datetime.now().astimezone().tzinfo
6693

94+
#
95+
# def datetime_to_utc_timestamp(datetime, current_tzinfo=None):
96+
# """
97+
# Convert a :class:`datetime.datetime` object to seconds since UNIX epoch, in UTC time
98+
#
99+
# :param datetime:
100+
# :type datetime: :class:`datetime.datetime`
101+
# :param current_tzinfo: A tzinfo object representing the current timezone.
102+
# If None it will be inferred.
103+
# :type current_tzinfo: :class:`~python:datetime.tzinfo`
104+
#
105+
# :return: Timestamp in UTC timezone
106+
# :rtype: float
107+
# """
108+
#
109+
# return datetime.astimezone(current_tzinfo).timestamp()
110+
#
111+
112+
def set_timezone(obj, tzinfo):
113+
"""
114+
Sets the timezone / tzinfo of the given :class:`datetime.datetime` object.
115+
This will not convert the time (i.e. the hours will stay the same).
116+
Use :func:`python:datetime.datetime.astimezone` to accomplish that
117+
:param obj:
118+
:type obj:
119+
:param tzinfo:
120+
:type tzinfo:
121+
:return:
122+
:rtype:
123+
"""
124+
125+
return obj.replace(tzinfo=tzinfo)
126+
67127

68128
def utc_timestamp_to_datetime(utc_timestamp, output_tz=None):
69129
"""
@@ -92,11 +152,7 @@ def utc_timestamp_to_datetime(utc_timestamp, output_tz=None):
92152
"""
93153

94154
new_datetime = datetime.datetime.fromtimestamp(utc_timestamp, output_tz)
95-
96-
if output_tz is None:
97-
return new_datetime.astimezone()
98-
else:
99-
return new_datetime
155+
return new_datetime.astimezone(output_tz)
100156

101157
except ImportError:
102158
import warnings

domdf_python_tools/doctools.py

+56-41
Original file line numberDiff line numberDiff line change
@@ -30,33 +30,36 @@
3030
import builtins
3131

3232

33-
def document_object_from_another(target, original):
33+
def deindent_string(string):
3434
"""
35-
Sets the docstring of the `target` function to that of the `original` function.
35+
Removes all indentation from the given string
3636
37-
This may be useful for subclasses or wrappers that use the same arguments.
37+
:param string:
38+
:type string: str
3839
39-
:param target: The object to set the docstring for
40-
:type target: any
41-
:param original: The object to copy the docstring from
42-
:type original: any
40+
:return:
41+
:rtype: str
4342
"""
4443

45-
target.__doc__ = original.__doc__
44+
split_string = string.split("\n")
45+
deindented_string = [line.lstrip("\t ") for line in split_string]
46+
return "\n".join(deindented_string)
4647

4748

48-
def is_documented_by(original):
49+
# Functions that do the work
50+
def document_object_from_another(target, original):
4951
"""
5052
Sets the docstring of the `target` function to that of the `original` function.
5153
5254
This may be useful for subclasses or wrappers that use the same arguments.
55+
56+
:param target: The object to set the docstring for
57+
:type target: any
58+
:param original: The object to copy the docstring from
59+
:type original: any
5360
"""
5461

55-
def wrapper(target):
56-
document_object_from_another(target, original)
57-
return target
58-
59-
return wrapper
62+
target.__doc__ = original.__doc__
6063

6164

6265
def append_doctring_from_another(target, original):
@@ -75,43 +78,22 @@ def append_doctring_from_another(target, original):
7578
:type original: any
7679
"""
7780

78-
split_target_doc = target.__doc__.split("\n")
79-
deindented_target_doc = [line.lstrip("\t ") for line in split_target_doc]
80-
81-
split_original_doc = original.__doc__.split("\n")
82-
deindented_original_doc = [line.lstrip("\t ") for line in split_original_doc]
81+
deindented_target_doc = deindent_string(target.__doc__)
82+
deindented_original_doc = deindent_string(original.__doc__)
8383

84-
target.__doc__ = f"\n".join(deindented_target_doc + deindented_original_doc)
85-
86-
87-
def append_docstring_from(original):
88-
"""
89-
Appends the docstring from the `original` function to the `target` function.
90-
91-
This may be useful for subclasses or wrappers that use the same arguments.
92-
93-
Any indentation in either docstring is removed to
94-
ensure consistent indentation between the two docstrings.
95-
Bear this in mind if additional indentation is used in the docstring.
96-
"""
97-
98-
def wrapper(target):
99-
append_doctring_from_another(target, original)
100-
return target
101-
102-
return wrapper
84+
target.__doc__ = deindented_target_doc + "\n" + deindented_original_doc
10385

10486

10587
def make_sphinx_links(input_string, builtins_list=None):
10688
"""
10789
Make proper sphinx links out of double-backticked strings in docstring.
10890
10991
i.e. \`\`str\`\` becomes \:class\:\`~python:str\`
110-
111-
92+
93+
11294
Make sure to have `'python': ('https://docs.python.org/3/', None),` in the
11395
`intersphinx_mapping` dict of your conf.py for sphinx.
114-
96+
11597
:param input_string: The string to process
11698
:type input_string: str
11799
:param builtins_list: A list of builtins to make links for
@@ -132,6 +114,39 @@ def make_sphinx_links(input_string, builtins_list=None):
132114
return working_string
133115

134116

117+
# Decorators that call the above functions
118+
def is_documented_by(original):
119+
"""
120+
Sets the docstring of the `target` function to that of the `original` function.
121+
122+
This may be useful for subclasses or wrappers that use the same arguments.
123+
"""
124+
125+
def wrapper(target):
126+
document_object_from_another(target, original)
127+
return target
128+
129+
return wrapper
130+
131+
132+
def append_docstring_from(original):
133+
"""
134+
Appends the docstring from the `original` function to the `target` function.
135+
136+
This may be useful for subclasses or wrappers that use the same arguments.
137+
138+
Any indentation in either docstring is removed to
139+
ensure consistent indentation between the two docstrings.
140+
Bear this in mind if additional indentation is used in the docstring.
141+
"""
142+
143+
def wrapper(target):
144+
append_doctring_from_another(target, original)
145+
return target
146+
147+
return wrapper
148+
149+
135150
def sphinxify_docstring():
136151
"""
137152
Make proper sphinx links out of double-backticked strings in docstring.

domdf_python_tools/paths.py

+14-7
Original file line numberDiff line numberDiff line change
@@ -85,27 +85,34 @@ def maybe_make(directory):
8585
Makes a directory only if it doesn't already exist
8686
8787
:param directory: Directory to create
88-
:type directory: str
88+
:type directory: str or pathlib.Path
8989
9090
"""
9191

92-
if not os.path.exists(directory):
93-
os.makedirs(directory)
92+
if not isinstance(directory, pathlib.Path):
93+
directory = pathlib.Path(directory)
94+
95+
if not directory.exists():
96+
directory.mkdir()
9497

9598

9699
def parent_path(path):
97100
"""
98101
Returns the path of the parent directory for the given file or directory
99102
100103
:param path: Path to find the parent for
101-
:type path: str
104+
:type path: str or pathlib.Path
102105
103-
:return:
106+
:return: The parent directory
107+
:rtype: pathlib.Path
104108
"""
105109

106-
return os.path.abspath(os.path.join(path,os.pardir))
107-
110+
if not isinstance(path, pathlib.Path):
111+
path = pathlib.Path(path)
112+
113+
return path.parent
108114

115+
109116
def relpath(path, relative_to=None):
110117
"""
111118
Returns the path for the given file or directory relative to the given directory

domdf_python_tools/utils.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ def list2str(the_list, sep=","):
148148
return sep.join([str(x) for x in the_list])
149149

150150

151-
def splitLen(string, n):
151+
def split_len(string, n):
152152
"""
153153
Split a string every x characters
154154
@@ -161,9 +161,13 @@ def splitLen(string, n):
161161
return [string[i:i + n] for i in range(0, len(string), n)]
162162

163163

164+
splitLen = split_len
165+
166+
164167
def permutations(data, n=2):
165168
"""
166-
Return permutations containing `n` items from `data` without any reverse duplicates
169+
Return permutations containing `n` items from `data` without any reverse duplicates.
170+
If ``n`` is equal to or greater than the length of the data an empty list of returned
167171
168172
:type data: list or string
169173
:type n: int
@@ -172,6 +176,10 @@ def permutations(data, n=2):
172176
"""
173177

174178
import itertools
179+
180+
if n == 0:
181+
raise ValueError("`n` cannot be 0")
182+
175183
perms = []
176184
for i in itertools.permutations(data, n):
177185
"""from https://stackoverflow.com/questions/10201977/how-to-reverse-tuples-in-python"""

0 commit comments

Comments
 (0)