p2api 1.0.6__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- p2api/__about__.py +1 -0
- p2api/__init__.py +5 -0
- p2api/p2api.py +1808 -0
- p2api/utils/__init__.py +1 -0
- p2api/utils/add_absolute_time_intervals.py +399 -0
- p2api/utils/generate_finding_charts.py +260 -0
- p2api/utils/p2api_utils.py +304 -0
- p2api-1.0.6.dist-info/METADATA +61 -0
- p2api-1.0.6.dist-info/RECORD +12 -0
- p2api-1.0.6.dist-info/WHEEL +5 -0
- p2api-1.0.6.dist-info/entry_points.txt +3 -0
- p2api-1.0.6.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import logging
|
|
3
|
+
import p2api
|
|
4
|
+
import sys
|
|
5
|
+
import time
|
|
6
|
+
import getpass
|
|
7
|
+
import keyring
|
|
8
|
+
import re
|
|
9
|
+
|
|
10
|
+
import astropy.units as u
|
|
11
|
+
from astropy.coordinates import EarthLocation
|
|
12
|
+
|
|
13
|
+
# The GPS coordinates of the UTs
|
|
14
|
+
# https://www.eso.org/sci/facilities/paranal/astroclimate/site.html
|
|
15
|
+
UT1_loc = EarthLocation.from_geodetic('-70d24m18.27s', '-24d37m39.44s', (2635.43+13.044)*u.m)
|
|
16
|
+
UT2_loc = EarthLocation.from_geodetic('-70d24m17.39s', '-24d37m37.80s', (2635.43+13.044)*u.m)
|
|
17
|
+
UT3_loc = EarthLocation.from_geodetic('-70d24m16.32s', '-24d37m36.64s', (2635.43+13.044)*u.m)
|
|
18
|
+
UT4_loc = EarthLocation.from_geodetic('-70d24m14.25s', '-24d37m37.36s', (2635.43+13.044)*u.m)
|
|
19
|
+
VST_loc = EarthLocation.from_geodetic('-70d24m14.27s', '-24d37m34.79s', (2635.43+4.5399)*u.m)
|
|
20
|
+
VISTA_loc = EarthLocation.from_geodetic('-70d23m51.36s', '-24d36m56.52s', (2530.)*u.m)
|
|
21
|
+
|
|
22
|
+
# https://www.eso.org/sci/facilities/lasilla/telescopes/3p6/overview.html
|
|
23
|
+
## The telescope is at a geographical location of:
|
|
24
|
+
## 70° 43' 54.1" W -29° 15' 39.5" S (WGS84), 2400 metres above sea level
|
|
25
|
+
LS3p6_loc = EarthLocation.from_geodetic('-70d43m54.1s', '-29d15m39.5s', (2400.)*u.m)
|
|
26
|
+
|
|
27
|
+
# https://www.eso.org/sci/facilities/lasilla/telescopes/ntt/overview.html
|
|
28
|
+
## 70° 44' 01.5" W -29° 15' 32.1" S (WGS84), 2375m
|
|
29
|
+
LSntt_loc = EarthLocation.from_geodetic('-70d44m01.5s', '-29d15m32.1s', (2375.)*u.m)
|
|
30
|
+
|
|
31
|
+
# https://www.eso.org/sci/facilities/lasilla/telescopes/national/2p2.html
|
|
32
|
+
# 2p2 70°44'4"543 W 29°15'15"433 S
|
|
33
|
+
LS2p2_loc = EarthLocation.from_geodetic('-70d44m04.543s', '-29d15m15.433s', (2335.)*u.m)
|
|
34
|
+
|
|
35
|
+
## All together as a dictionary:
|
|
36
|
+
telescope_locations={
|
|
37
|
+
'UT1': UT1_loc,
|
|
38
|
+
'UT2': UT2_loc,
|
|
39
|
+
'UT3': UT3_loc,
|
|
40
|
+
'UT4': UT4_loc,
|
|
41
|
+
'VST': VST_loc,
|
|
42
|
+
'VISTA': VISTA_loc,
|
|
43
|
+
'LS3p6': LS3p6_loc,
|
|
44
|
+
'LSntt': LSntt_loc,
|
|
45
|
+
'LS2p2': LS2p2_loc,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# ---------------------------------------------------------------------------------------
|
|
49
|
+
def current_ESO_period():
|
|
50
|
+
d=datetime.datetime.utcnow()
|
|
51
|
+
return ((d.year-2012)+44)*2+int(float(d.month+2)/6.)
|
|
52
|
+
# ---------------------------------------------------------------------------------------
|
|
53
|
+
def ESO_period_start_end_dates(P):
|
|
54
|
+
ESO_period_first_last_dates=[
|
|
55
|
+
['-10-01','-03-31'],
|
|
56
|
+
['-04-01','-09-30'],
|
|
57
|
+
]
|
|
58
|
+
y1=1967+(P+1)//2
|
|
59
|
+
md1=ESO_period_first_last_dates[P%2][0]
|
|
60
|
+
y2=1967+(P+2)//2
|
|
61
|
+
md2=ESO_period_first_last_dates[P%2][1]
|
|
62
|
+
return [f"{y1}{md1}",f"{y2}{md2}"]
|
|
63
|
+
# ---------------------------------------------------------------------------------------
|
|
64
|
+
def ESO_period_start_end_datetimes(P):
|
|
65
|
+
ESO_period_first_last_dates=[
|
|
66
|
+
['-10-01T12:00:00','-04-01T12:00:00'],
|
|
67
|
+
['-04-01T12:00:00','-10-01T12:00:00'],
|
|
68
|
+
]
|
|
69
|
+
y1=1967+(P+1)//2
|
|
70
|
+
md1=ESO_period_first_last_dates[P%2][0]
|
|
71
|
+
y2=1967+(P+2)//2
|
|
72
|
+
md2=ESO_period_first_last_dates[P%2][1]
|
|
73
|
+
return [f"{y1}{md1}",f"{y2}{md2}"]
|
|
74
|
+
# ---------------------------------------------------------------------------------------
|
|
75
|
+
def get_attrs(klass):
|
|
76
|
+
return [k for k in klass.__dict__.keys()
|
|
77
|
+
if not k.startswith('__')
|
|
78
|
+
and not k.endswith('__')]
|
|
79
|
+
|
|
80
|
+
# ---------------------------------------------------------------------------------------
|
|
81
|
+
# https://gist.github.com/cynici/4084518
|
|
82
|
+
'''
|
|
83
|
+
optparse offers IndentedHelpFormatter() and TitledHelpFormatter() but they don't honor the newlines embedded in the description string.
|
|
84
|
+
author: Tim Chase
|
|
85
|
+
source: https://groups.google.com/forum/?fromgroups=#!topic/comp.lang.python/bfbmtUGhW8I
|
|
86
|
+
usage: parser = OptionParser(description=help_text, formatter=IndentedHelpFormatterWithNL())
|
|
87
|
+
'''
|
|
88
|
+
|
|
89
|
+
from optparse import OptionParser, IndentedHelpFormatter, textwrap
|
|
90
|
+
|
|
91
|
+
class IndentedHelpFormatterWithNL(IndentedHelpFormatter):
|
|
92
|
+
def format_description(self, description):
|
|
93
|
+
if not description: return ""
|
|
94
|
+
desc_width = self.width - self.current_indent
|
|
95
|
+
indent = " "*self.current_indent
|
|
96
|
+
# the above is still the same
|
|
97
|
+
bits = description.split('\n')
|
|
98
|
+
formatted_bits = [
|
|
99
|
+
textwrap.fill(bit,
|
|
100
|
+
desc_width,
|
|
101
|
+
initial_indent=indent,
|
|
102
|
+
subsequent_indent=indent)
|
|
103
|
+
for bit in bits]
|
|
104
|
+
result = "\n".join(formatted_bits) + "\n"
|
|
105
|
+
return result
|
|
106
|
+
|
|
107
|
+
def format_option(self, option):
|
|
108
|
+
# The help for each option consists of two parts:
|
|
109
|
+
# * the opt strings and metavars
|
|
110
|
+
# eg. ("-x", or "-fFILENAME, --file=FILENAME")
|
|
111
|
+
# * the user-supplied help string
|
|
112
|
+
# eg. ("turn on expert mode", "read data from FILENAME")
|
|
113
|
+
#
|
|
114
|
+
# If possible, we write both of these on the same line:
|
|
115
|
+
# -x turn on expert mode
|
|
116
|
+
#
|
|
117
|
+
# But if the opt string list is too long, we put the help
|
|
118
|
+
# string on a second line, indented to the same column it would
|
|
119
|
+
# start in if it fit on the first line.
|
|
120
|
+
# -fFILENAME, --file=FILENAME
|
|
121
|
+
# read data from FILENAME
|
|
122
|
+
result = []
|
|
123
|
+
opts = self.option_strings[option]
|
|
124
|
+
opt_width = self.help_position - self.current_indent - 2
|
|
125
|
+
if len(opts) > opt_width:
|
|
126
|
+
opts = "%*s%s\n" % (self.current_indent, "", opts)
|
|
127
|
+
indent_first = self.help_position
|
|
128
|
+
else: # start help on same line as opts
|
|
129
|
+
opts = "%*s%-*s " % (self.current_indent, "", opt_width, opts)
|
|
130
|
+
indent_first = 0
|
|
131
|
+
result.append(opts)
|
|
132
|
+
if option.help:
|
|
133
|
+
help_text = self.expand_default(option)
|
|
134
|
+
# Everything is the same up through here
|
|
135
|
+
help_lines = []
|
|
136
|
+
for para in help_text.split("\n"):
|
|
137
|
+
help_lines.extend(textwrap.wrap(para, self.help_width))
|
|
138
|
+
# Everything is the same after here
|
|
139
|
+
result.append("%*s%s\n" % (
|
|
140
|
+
indent_first, "", help_lines[0]))
|
|
141
|
+
result.extend(["%*s%s\n" % (self.help_position, "", line)
|
|
142
|
+
for line in help_lines[1:]])
|
|
143
|
+
elif opts[-1] != "\n":
|
|
144
|
+
result.append("\n")
|
|
145
|
+
return "".join(result)
|
|
146
|
+
# ---------------------------------------------------------------------------------------
|
|
147
|
+
def rgetFolderIds( api, cIds ):
|
|
148
|
+
|
|
149
|
+
ids = []
|
|
150
|
+
for cId in cIds :
|
|
151
|
+
rItems, _ = api.get('/containers/'+str(cId)+'/items')
|
|
152
|
+
logging.debug(rItems)
|
|
153
|
+
for r in rItems :
|
|
154
|
+
if r['itemType'] == 'Folder' :
|
|
155
|
+
logging.debug('Adding %d to folder list' %(r['containerId']))
|
|
156
|
+
ids.extend([r['containerId'],])
|
|
157
|
+
ids.extend(rgetFolderIds(api, [r['containerId'],]))
|
|
158
|
+
return ids
|
|
159
|
+
# ---------------------------------------------------------------------------------------
|
|
160
|
+
def rgetContainerIds( api, cIds, status=None ):
|
|
161
|
+
ids = []
|
|
162
|
+
for cId in cIds :
|
|
163
|
+
rItems, _ = api.get('/containers/'+str(cId)+'/items')
|
|
164
|
+
logging.debug(rItems)
|
|
165
|
+
for r in rItems :
|
|
166
|
+
if r['itemType'] == 'TimeLink' or r['itemType'] == 'Group' or r['itemType'] == 'Concatenation' :
|
|
167
|
+
if status is None or r['containerStatus'] in list(status) :
|
|
168
|
+
logging.debug('Adding %d to container list' %(r['containerId']))
|
|
169
|
+
ids.extend([r['containerId'],])
|
|
170
|
+
return ids
|
|
171
|
+
# ---------------------------------------------------------------------------------------
|
|
172
|
+
def rgetOBIds( api, cIds, status=None ):
|
|
173
|
+
ids = []
|
|
174
|
+
for cId in cIds :
|
|
175
|
+
logging.debug('Checking container %d' %(cId))
|
|
176
|
+
rItems, _ = api.get('/containers/'+str(cId)+'/items')
|
|
177
|
+
logging.debug(rItems)
|
|
178
|
+
for r in rItems :
|
|
179
|
+
if r['itemType'] == 'OB' or r['itemType'] == 'CB' :
|
|
180
|
+
if status is None or r['obStatus'] in list(status) :
|
|
181
|
+
logging.debug('Adding %d to OB list' %(r['obId']))
|
|
182
|
+
ids.extend([r['obId'],])
|
|
183
|
+
return ids
|
|
184
|
+
# ---------------------------------------------------------------------------------------
|
|
185
|
+
def r_get_all_OBIds( api, obj_list ) :
|
|
186
|
+
obIds=[]
|
|
187
|
+
for ID in obj_list :
|
|
188
|
+
nID=int(ID)
|
|
189
|
+
logging.info("Processing OB/Container ID = %d" %(nID))
|
|
190
|
+
# The containes and OBs
|
|
191
|
+
try:
|
|
192
|
+
container, containerVersion = api.getContainer(nID)
|
|
193
|
+
fIds = [nID,]
|
|
194
|
+
fIds.extend(rgetFolderIds(api, [nID,]))
|
|
195
|
+
logging.info('================================================================================')
|
|
196
|
+
cIds=rgetContainerIds(api, fIds )
|
|
197
|
+
fcIds = fIds+cIds
|
|
198
|
+
if cIds is not None :
|
|
199
|
+
logging.info("containerId list = %s" %(str(cIds)))
|
|
200
|
+
else :
|
|
201
|
+
logging.error("No containers found")
|
|
202
|
+
logging.info('================================================================================')
|
|
203
|
+
obIds=obIds+rgetOBIds(api, fcIds )
|
|
204
|
+
logging.info("obId list = %s" %(str(obIds)))
|
|
205
|
+
if obIds is None :
|
|
206
|
+
logging.error("No OBs found")
|
|
207
|
+
|
|
208
|
+
except p2api.P2Error as e :
|
|
209
|
+
## Looks like this ID is not a container, assume it is an OB, below...
|
|
210
|
+
obIds.append(nID)
|
|
211
|
+
except:
|
|
212
|
+
raise
|
|
213
|
+
return obIds
|
|
214
|
+
# ---------------------------------------------------------------------------------------
|
|
215
|
+
def get_api( options ) :
|
|
216
|
+
password_from_keyring = None
|
|
217
|
+
# Login...
|
|
218
|
+
if options.env in ['demo',]:
|
|
219
|
+
user='52052'
|
|
220
|
+
pwstream='tutorial'
|
|
221
|
+
else:
|
|
222
|
+
user=options.user
|
|
223
|
+
## from astroquery.eso
|
|
224
|
+
# Get password from keyring or prompt
|
|
225
|
+
if options.pwreenter is False:
|
|
226
|
+
password_from_keyring = keyring.get_password(
|
|
227
|
+
"usd_p2api_interactive:www.eso.org", user)
|
|
228
|
+
|
|
229
|
+
if password_from_keyring is None:
|
|
230
|
+
#if system_tools.in_ipynb():
|
|
231
|
+
# log.warning("You may be using an ipython notebook:"
|
|
232
|
+
# " the password form will appear in your terminal.")
|
|
233
|
+
# see https://pymotw.com/2/getpass/
|
|
234
|
+
if sys.stdin.isatty():
|
|
235
|
+
pwstream = getpass.getpass(user+"@<"+options.env+"> password : ", stream=sys.stderr)
|
|
236
|
+
else:
|
|
237
|
+
pwstream = sys.stdin.readline().rstrip()
|
|
238
|
+
else:
|
|
239
|
+
pwstream = password_from_keyring
|
|
240
|
+
|
|
241
|
+
i=0
|
|
242
|
+
api = None
|
|
243
|
+
while api is None and i < 10 :
|
|
244
|
+
try:
|
|
245
|
+
api = p2api.ApiConnection(options.env, user, pwstream)
|
|
246
|
+
except p2api.P2Error as e :
|
|
247
|
+
logging.error(e)
|
|
248
|
+
time.sleep(2)
|
|
249
|
+
except :
|
|
250
|
+
pass
|
|
251
|
+
i+=1
|
|
252
|
+
if api is None :
|
|
253
|
+
logging.error('Ooops, login failed...')
|
|
254
|
+
sys.exit(1)
|
|
255
|
+
|
|
256
|
+
## from astroquery.eso
|
|
257
|
+
# When authenticated, save password in keyring if needed
|
|
258
|
+
if options.env not in ['demo','defidev7',] and password_from_keyring is None and options.pwstore:
|
|
259
|
+
keyring.set_password("usd_p2api_interactive:www.eso.org", user, pwstream)
|
|
260
|
+
|
|
261
|
+
return api
|
|
262
|
+
# ---------------------------------------------------------------------------------------
|
|
263
|
+
def decode_datetime( d ) :
|
|
264
|
+
if d is None :
|
|
265
|
+
return None
|
|
266
|
+
if isinstance(d,datetime.date) :
|
|
267
|
+
return d
|
|
268
|
+
if isinstance(d,datetime.datetime) :
|
|
269
|
+
return d.date()
|
|
270
|
+
|
|
271
|
+
# Python can't actually handle TimeZones by name, except the one that
|
|
272
|
+
# time.tzname is currently set to:
|
|
273
|
+
# see https://docs.python.org/3/library/time.html
|
|
274
|
+
# So we replace as needed TZ names (%Z) with the %z format...
|
|
275
|
+
tz_info={
|
|
276
|
+
'UTC': '+0000',
|
|
277
|
+
'CET': '+0100',
|
|
278
|
+
'CEST': '+0200',
|
|
279
|
+
}
|
|
280
|
+
d_tz=d
|
|
281
|
+
for tz in tz_info :
|
|
282
|
+
d_tz=re.sub(
|
|
283
|
+
f'{tz}',
|
|
284
|
+
f'{tz_info[tz]}',
|
|
285
|
+
d_tz,
|
|
286
|
+
)
|
|
287
|
+
for s in [d_tz,d] :
|
|
288
|
+
for df in [
|
|
289
|
+
'%a, %d %b %Y %H:%M:%S %z', # 'Wed, 8 Feb 2023 21:43:40 +0000'
|
|
290
|
+
'%A, %d %B %Y at %H:%M %Z', # 'Thursday, 22 February 2024 at 12:00 CET'
|
|
291
|
+
'%A, %d %B %Y at %H:%M %z', # 'Thursday, 22 February 2024 at 12:00 +0100'
|
|
292
|
+
'%d %b %Y',
|
|
293
|
+
'%Y.%m.%d',
|
|
294
|
+
'%Y-%m-%d',
|
|
295
|
+
'%Y-%m-%dT%H:%M:%S', # 2023-04-01T16:45:59
|
|
296
|
+
'%Y-%m-%dT%H:%M', # 2023-04-01T16:45
|
|
297
|
+
] :
|
|
298
|
+
try :
|
|
299
|
+
dt=datetime.datetime.strptime(s, df)
|
|
300
|
+
return dt
|
|
301
|
+
except :
|
|
302
|
+
pass
|
|
303
|
+
raise Exception(f"Could not decode date '{d}'.")
|
|
304
|
+
# ---------------------------------------------------------------------------------------
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: p2api
|
|
3
|
+
Version: 1.0.6
|
|
4
|
+
Summary: Binding for the ESO phase 2 programmatic API
|
|
5
|
+
Project-URL: Homepage, https://www.eso.org/copdemo/apidoc/index.html
|
|
6
|
+
Author-email: Thomas Bierwirth <thomas.bierwirth@eso.org>, John Pritchard <john.pritchard@eso.org>
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2018-present Thomas Bierwirth and other contributors
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Keywords: API,ESO,Observation,Phase2,Preparation,Programmatic
|
|
30
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
31
|
+
Classifier: Intended Audience :: Developers
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Programming Language :: Python :: 3
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.4
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.5
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
43
|
+
Requires-Dist: astroplan
|
|
44
|
+
Requires-Dist: astropy
|
|
45
|
+
Requires-Dist: keyring
|
|
46
|
+
Requires-Dist: requests
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
|
+
|
|
49
|
+
# p2api
|
|
50
|
+
|
|
51
|
+
The [ESO](https://www.eso.org/public/) [Phase 2](https://www.eso.org/sci/observing/phase2.html) Application Programming Interface (API) uses the lightweight [JSON](<https://en.wikipedia.org/wiki/JSON>) standard as data format to exchange information between your application and the Phase 2 server at ESO. In order to program more conveniently against the API, it is helpful to create small, [language-specific bindings](<https://en.wikipedia.org/wiki/Language_binding>) to the API. We provide a simple example binding for Python, i.e. p2api.
|
|
52
|
+
|
|
53
|
+
As of version 1.0.6: Added script p2api_add_absolute_time_intervals.
|
|
54
|
+
|
|
55
|
+
As of version 1.0.3: support for \<url\>,\<access_token\> constructor.
|
|
56
|
+
|
|
57
|
+
As of version 0.97.2: support for La Silla.
|
|
58
|
+
|
|
59
|
+
Please see the [ESO-USD p2api](<http://eso.org/sci/observing/phase2/p2intro/Phase2API.html>) page for more details.
|
|
60
|
+
|
|
61
|
+
Phase 2 programmatic API documentation can be found [here](<https://www.eso.org/copdemo/apidoc/>).
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
p2api/__about__.py,sha256=mqMuQB3aqJVPrHHqJMLjqiMKUiJjozc7EPLcX5DpKHg,22
|
|
2
|
+
p2api/__init__.py,sha256=0wYyt-RvVjGdZPImG2MEk2BiZuWK8FiXBTMTw9BxRGk,146
|
|
3
|
+
p2api/p2api.py,sha256=xBUINJ_D1LcRI725foc0xo277wvDRaS5W5epJ1oNGRo,63571
|
|
4
|
+
p2api/utils/__init__.py,sha256=KkOGTFI0lZhjNLF2yRy-OtSfay7KUfU1ZZBVtC4Y0U8,58
|
|
5
|
+
p2api/utils/add_absolute_time_intervals.py,sha256=vvoHzCcdaR9ohNehGOZpOW6mlONW8xbqYYPg9uz60VY,18757
|
|
6
|
+
p2api/utils/generate_finding_charts.py,sha256=4xccJZxzLbdBBvpImANlkS2NCzSP-dAbeQlGCCmSB50,11951
|
|
7
|
+
p2api/utils/p2api_utils.py,sha256=5U91EGTOqw2u793mhxmwmjDQJPhMubt5mo56X8EopN0,11930
|
|
8
|
+
p2api-1.0.6.dist-info/METADATA,sha256=s-YOwjfLK7iuWXdXvzJT6hrXCBXQNf2oWINwNgNpFX4,3372
|
|
9
|
+
p2api-1.0.6.dist-info/WHEEL,sha256=fl6v0VwpzfGBVsGtkAkhILUlJxROXbA3HvRL6Fe3140,105
|
|
10
|
+
p2api-1.0.6.dist-info/entry_points.txt,sha256=_Wh1hYyvJwkEMARyhDA5iGeNDt-tMs4nqlDW_D4huXg,172
|
|
11
|
+
p2api-1.0.6.dist-info/licenses/LICENSE,sha256=ooEtWLrYbubUHqsABQYrj8uOfE4CMVgkb7WQDgZVyDw,1103
|
|
12
|
+
p2api-1.0.6.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018-present Thomas Bierwirth and other contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|