-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.py
171 lines (132 loc) · 4.89 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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/env python
# -*- coding: utf-8; -*-
'''A random selection of general purpose functions'''
__author__ = "Pedro Inácio"
__copyright__ = "Copyright 2015"
__version__ = "1.0"
__maintainer__ = "Pedro Inácio"
__email__ = "pedro@inacio.space"
__status__ = "Development"
import calendar
from datetime import date, timedelta
import subprocess
def parse_date_range(dstr):
"""This function parses a date range with the format:
YYYY[MM[DD]][:YYYY[MM[DD]]]
and returns a tuple with the initial and final dates.
Possible '-'' and '/'' characters on the input string are stripped.
"""
# Remove - and / and split into lower and upper date bounds
date_range = dstr.replace('-', '').replace('/', '').split(':')
# Check length
if len(date_range) == 0 or len(date_range) >= 3:
raise ValueError("Incorrectly specified date range")
# Parse lower bound of data range
date_start = parse_date(date_range[0])
# Parse optional upper bound of date range
if len(date_range) == 1:
date_end = parse_date(date_range[0], round_up=True)
else:
date_end = parse_date(date_range[1], round_up=True)
# Check valid range
if date_start > date_end:
raise ValueError("Incorrect date range. Upper bound of date range " +
"must be later than lower bound.")
# Return tuple
return (date_start, date_end)
def parse_date(dstr, round_up=False):
"""This function recieves a string with the format YYYY[MM[DD]] and returns
the corresponding date object.
Missing elements are assumed to be 1, i.e., 2006 corresponds to 2006/01/01
Optional argument round_up specifies whether to round the date up instead,
i.e., 2006 corresponds to 2006/12/31
"""
year = int(dstr[0:4])
if round_up:
month = int(dstr[4:6]) if dstr[4:6] != '' else 12
# get last day of the month
aux = calendar.monthrange(year, month)
day = int(dstr[6:8]) if dstr[6:8] != '' else aux[1]
else:
month = int(dstr[4:6]) if dstr[4:6] != '' else 1
day = int(dstr[6:8]) if dstr[6:8] != '' else 1
return date(year, month, day)
def range_date(date_start, date_end, delta=timedelta(1)):
"""Similar to the range function, return a list of dates"""
list_dates = list()
d = date_start
while d <= date_end:
list_dates.append(d)
d += delta
return list_dates
def call(cmd, live=False):
"""Execute a command in the shell and returns stdout as string.
Optional argument live directly prints stdout trought pythons terminal
If the command fails, an exception is raised with stderr
"""
if live:
# call command
return_code = subprocess.call(cmd, shell=True)
# output already printed to the terminal
output = ["", ""]
else:
# create call object
callObj = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=True)
# wait for execution to finish and get (stdout,stderr) tuple
output = callObj.communicate()
# collect return code
return_code = callObj.returncode
# check return code
if return_code != 0:
# return stderr
raise RuntimeError(output[1])
else:
# return stdout
return output[0]
def check_utilities_in_system(list_utils):
"""Check if the requested list of programs is available in the system."""
# Handle non-list elements
if not isinstance(list_utils, list):
list_utils = [list_utils]
# Loop and check it exists
for x in list_utils:
try:
call("type "+x)
except RuntimeError, e:
raise Exception("Could not find '"+x+"' available in this system")
def confirm(prompt=None, resp=False):
"""Prompts for 'yes' or 'no' response from the user. Returns True for 'yes'
and False for 'no'.
'resp' should be set to the default value assumed by the caller when
user simply types ENTER.
>>> confirm(prompt='Create Directory?', resp=True)
Create Directory? [y]|n:
True
>>> confirm(prompt='Create Directory?', resp=False)
Create Directory? [n]|y:
False
>>> confirm(prompt='Create Directory?', resp=False)
Create Directory? [n]|y: y
True
"""
# Created by Raghuram Devarakonda
# Obtained from:
# http://code.activestate.com/recipes/541096-prompt-the-user-for-confirmation/
if prompt is None:
prompt = 'Confirm'
if resp:
prompt = '%s [%s]|%s: ' % (prompt, 'y', 'n')
else:
prompt = '%s [%s]|%s: ' % (prompt, 'n', 'y')
while True:
ans = raw_input(prompt)
if not ans:
return resp
if ans not in ['y', 'Y', 'n', 'N']:
print 'please enter y or n.'
continue
if ans == 'y' or ans == 'Y':
return True
if ans == 'n' or ans == 'N':
return False