p2api 1.0.6__tar.gz → 1.0.8__tar.gz
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-1.0.6 → p2api-1.0.8}/.gitignore +1 -0
- {p2api-1.0.6 → p2api-1.0.8}/PKG-INFO +1 -3
- p2api-1.0.8/p2api/__about__.py +1 -0
- {p2api-1.0.6 → p2api-1.0.8}/p2api/p2api.py +3 -0
- {p2api-1.0.6 → p2api-1.0.8}/p2api/utils/__init__.py +1 -0
- {p2api-1.0.6 → p2api-1.0.8}/p2api/utils/add_absolute_time_intervals.py +111 -34
- p2api-1.0.8/p2api/utils/eso_period.py +149 -0
- {p2api-1.0.6 → p2api-1.0.8}/p2api/utils/generate_finding_charts.py +3 -0
- {p2api-1.0.6 → p2api-1.0.8}/p2api/utils/p2api_utils.py +58 -38
- {p2api-1.0.6 → p2api-1.0.8}/pyproject.toml +5 -3
- p2api-1.0.8/setup.cfg +4 -0
- p2api-1.0.8/setup.py +127 -0
- p2api-1.0.6/p2api/__about__.py +0 -1
- {p2api-1.0.6 → p2api-1.0.8}/LICENSE +0 -0
- {p2api-1.0.6 → p2api-1.0.8}/README.md +0 -0
- {p2api-1.0.6 → p2api-1.0.8}/p2api/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: p2api
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.8
|
|
4
4
|
Summary: Binding for the ESO phase 2 programmatic API
|
|
5
5
|
Project-URL: Homepage, https://www.eso.org/copdemo/apidoc/index.html
|
|
6
6
|
Author-email: Thomas Bierwirth <thomas.bierwirth@eso.org>, John Pritchard <john.pritchard@eso.org>
|
|
@@ -40,8 +40,6 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
40
40
|
Classifier: Programming Language :: Python :: 3.10
|
|
41
41
|
Classifier: Programming Language :: Python :: 3.11
|
|
42
42
|
Classifier: Programming Language :: Python :: 3.12
|
|
43
|
-
Requires-Dist: astroplan
|
|
44
|
-
Requires-Dist: astropy
|
|
45
43
|
Requires-Dist: keyring
|
|
46
44
|
Requires-Dist: requests
|
|
47
45
|
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.8"
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
1
2
|
"""
|
|
2
3
|
This file provides an example binding to ESO's RESTful phase 2 programmatic interface.
|
|
3
4
|
The data required and returned by many of the API calls is instrument-specific.
|
|
@@ -141,6 +142,7 @@ class ApiConnection(object):
|
|
|
141
142
|
raise P2Error(500, 'POST', param_values['environment'], 'environment not supported')
|
|
142
143
|
self.apiUrl = API_URL[param_values['environment']]
|
|
143
144
|
self.loginUrl = LOGIN_URL[param_values['environment']]
|
|
145
|
+
self.p2fc_url = P2FC_URL[param_values['environment']]
|
|
144
146
|
self.session = self.requests_retry_session()
|
|
145
147
|
|
|
146
148
|
r = requests.post(
|
|
@@ -168,6 +170,7 @@ class ApiConnection(object):
|
|
|
168
170
|
raise P2Error(500, 'POST', kwargs['url'], 'Invalid URL')
|
|
169
171
|
self.apiUrl = API_URL[environment]
|
|
170
172
|
self.loginUrl = LOGIN_URL[environment]
|
|
173
|
+
self.p2fc_url = P2FC_URL[param_values['environment']]
|
|
171
174
|
self.access_token = kwargs['access_token']
|
|
172
175
|
self.session = self.requests_retry_session()
|
|
173
176
|
else :
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
#! /usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
2
3
|
|
|
3
4
|
# $Id: generate_finding_charts.py 267033 2021-09-16 11:08:57Z jpritcha $
|
|
4
5
|
from __future__ import print_function
|
|
5
6
|
|
|
6
7
|
_VERSION_ = "$Revision: 267033 $"
|
|
8
|
+
try:
|
|
9
|
+
from ..p2api import __version__
|
|
10
|
+
except:
|
|
11
|
+
from p2api.__about__ import __version__
|
|
12
|
+
_VERSION_ = __version__
|
|
7
13
|
|
|
8
14
|
import sys # interaction with Python interpreter
|
|
9
15
|
from optparse import OptionParser # for parsing command line arguments
|
|
@@ -63,9 +69,24 @@ e.g. yyyy-mm-ddThh:mm,yyyy-mm-ddThh:mm_yyyy-mm-ddThh:mm,yyyy-mm-ddThh:mm{_...}
|
|
|
63
69
|
|
|
64
70
|
group = OptionGroup(parser, "Specify the Absolute Time Intervals using an orbital ephemeris. This functionality is EXPERIMENTAL, please check carefully!!!")
|
|
65
71
|
group.add_option("-E", "--ephem", dest="ephem", metavar="T0,PERIOD", help="Comma separated list of orbital T0[JD] and period[days] [optional]", default=None)
|
|
66
|
-
group.add_option(
|
|
72
|
+
group.add_option(
|
|
73
|
+
"--phase_intervals",
|
|
74
|
+
dest="phase_intervals",
|
|
75
|
+
help="""\
|
|
76
|
+
Comma separated list of phase intervals e.g. 0.1-0.2,0.305-0.375 [optional].
|
|
77
|
+
Remember that ATCs specify the intervals during which the OBs must be started.
|
|
78
|
+
This code however interprets the phase intervals as the intervals during which the OB must start AND finish. \
|
|
79
|
+
Therefore the ending phase intervals of the ATCs that will be added to the OBs will always be \
|
|
80
|
+
less than the phase intervals specified.\
|
|
81
|
+
""",
|
|
82
|
+
default=None
|
|
83
|
+
)
|
|
67
84
|
group.add_option("--phase_target", dest="phase_target", help="Comma separated list of target phase, start_before [mins], min_start_before [mins] e.g. 0.01,120,30 [optional]", default=None)
|
|
68
|
-
group.add_option("--periods", dest="periods", help=
|
|
85
|
+
group.add_option("--periods", dest="periods", help="Comma separated list of periods, default={} [optional]".format(default_eso_period), default=str(default_eso_period))
|
|
86
|
+
parser.add_option_group(group)
|
|
87
|
+
|
|
88
|
+
group = OptionGroup(parser, "Do NOT check ATCs for experimental methods.")
|
|
89
|
+
group.add_option("--NO_checkATCs", dest="NO_checkATCs", help="Do NOT check ATCs for experimental methods.", action="store_true", default=False)
|
|
69
90
|
parser.add_option_group(group)
|
|
70
91
|
|
|
71
92
|
group = OptionGroup(parser, "p2 server selection, options and password management")
|
|
@@ -121,6 +142,8 @@ e.g. yyyy-mm-ddThh:mm,yyyy-mm-ddThh:mm_yyyy-mm-ddThh:mm,yyyy-mm-ddThh:mm{_...}
|
|
|
121
142
|
self.phase_intervals = options.phase_intervals
|
|
122
143
|
self.phase_target = options.phase_target
|
|
123
144
|
|
|
145
|
+
self.NO_checkATCs = options.NO_checkATCs
|
|
146
|
+
|
|
124
147
|
self.user = options.user
|
|
125
148
|
self.env = options.env
|
|
126
149
|
self.pwstore = options.pwstore
|
|
@@ -149,7 +172,7 @@ def get_ob_ATCs(telescope=None, ob_info=None, run_info=None) :
|
|
|
149
172
|
if options.ATCs is not None :
|
|
150
173
|
ATCs=[
|
|
151
174
|
[p2api_utils.decode_datetime(x.split(',')[0]),p2api_utils.decode_datetime(x.split(',')[1])]
|
|
152
|
-
for x in options.ATCs.
|
|
175
|
+
for x in options.ATCs.split('_')
|
|
153
176
|
]
|
|
154
177
|
|
|
155
178
|
elif options.file is not None :
|
|
@@ -214,9 +237,23 @@ def get_ob_ATCs(telescope=None, ob_info=None, run_info=None) :
|
|
|
214
237
|
checked_phase_intervals+=[p_int,]
|
|
215
238
|
else :
|
|
216
239
|
if ob_exec_time < p_int_in_sec :
|
|
217
|
-
logging.warning(
|
|
240
|
+
logging.warning(
|
|
241
|
+
'Phase interval {}--{} == {:3.1f}sec is too short to start and finish this OB with execution time of {}secs.'.format(
|
|
242
|
+
p_int[0],
|
|
243
|
+
p_int[1],
|
|
244
|
+
p_int_in_sec,
|
|
245
|
+
ob_exec_time,
|
|
246
|
+
)
|
|
247
|
+
)
|
|
218
248
|
if p_int_in_sec > min_ATI_length.to_value(u.second) :
|
|
219
|
-
logging.warning(
|
|
249
|
+
logging.warning(
|
|
250
|
+
'Phase interval {}--{} == {:3.1f}sec is shorter than the minimum ATI length time of {}secs.'.format(
|
|
251
|
+
p_int[0],
|
|
252
|
+
p_int[1],
|
|
253
|
+
p_int_in_sec,
|
|
254
|
+
min_ATI_length.to_value(u.second),
|
|
255
|
+
)
|
|
256
|
+
)
|
|
220
257
|
|
|
221
258
|
sf_ints=[]
|
|
222
259
|
for sf_jd in sf_jds :
|
|
@@ -241,22 +278,25 @@ def get_ob_ATCs(telescope=None, ob_info=None, run_info=None) :
|
|
|
241
278
|
int_spans_nighttime=False
|
|
242
279
|
for which in ['previous','next',] :
|
|
243
280
|
sun_set_time=telescope.sun_set_time(Time(sf_int[0], format='jd'), which=which)
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
(
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
281
|
+
if isinstance(sun_set_time.value,np.float64) :
|
|
282
|
+
sun_rise_time=telescope.sun_rise_time(sun_set_time, which='next')
|
|
283
|
+
sssr+=[[sun_set_time,sun_rise_time],]
|
|
284
|
+
if (
|
|
285
|
+
(sf_int[0] > sun_set_time.jd and sf_int[0] < sun_rise_time.jd-ob_exec_time/24./60./60. )
|
|
286
|
+
or
|
|
287
|
+
(sf_int[1] > sun_set_time.jd and sf_int[1] < sun_rise_time.jd-ob_exec_time/24./60./60. )
|
|
288
|
+
or
|
|
289
|
+
(sf_int[0] < sun_set_time.jd and sf_int[1] > sun_rise_time.jd-ob_exec_time/24./60./60. )
|
|
290
|
+
) :
|
|
291
|
+
sf_int=[
|
|
292
|
+
np.max([sf_int[0],sun_set_time.jd]),
|
|
293
|
+
np.min([sf_int[1],sun_rise_time.jd-ob_exec_time/24./60./60.,sun_rise_time.jd-post_ob_exec_time/24./60./60.]),
|
|
294
|
+
]
|
|
295
|
+
if sf_int[1] > sf_int[0]+min_start_before/24./60. :
|
|
296
|
+
int_spans_nighttime=True
|
|
297
|
+
break
|
|
298
|
+
else :
|
|
299
|
+
logging.error(f"telescope.sun_set_time(Time({sf_int[0]}, format='jd'), which={which}) did not return np.float64 ")
|
|
260
300
|
if (
|
|
261
301
|
int_spans_nighttime
|
|
262
302
|
and
|
|
@@ -267,11 +307,33 @@ def get_ob_ATCs(telescope=None, ob_info=None, run_info=None) :
|
|
|
267
307
|
sf_ints+=[sf_int,]
|
|
268
308
|
else :
|
|
269
309
|
if not int_spans_nighttime :
|
|
270
|
-
logging.debug(
|
|
310
|
+
logging.debug(
|
|
311
|
+
'Interval does not span any part of the night, original interval = {}, SSSR of previous and next nights {}--{} and {}--{}'.format(
|
|
312
|
+
original_sf_int,
|
|
313
|
+
sssr[0][0].jd,
|
|
314
|
+
sssr[0][1].jd,
|
|
315
|
+
sssr[1][0].jd,
|
|
316
|
+
sssr[1][1].jd,
|
|
317
|
+
)
|
|
318
|
+
)
|
|
271
319
|
if ((sf_int[1]-sf_int[0])*24*60.*60. < ob_exec_time) :
|
|
272
|
-
logging.debug(
|
|
320
|
+
logging.debug(
|
|
321
|
+
'Checked Interval shorter [{:3.1f}sec] than OB execution time [{:3.1f}sec], original interval = {}, checked interval = {}'.format(
|
|
322
|
+
(sf_int[1]-sf_int[0])*24*60.*60.,
|
|
323
|
+
ob_exec_time,
|
|
324
|
+
original_sf_int,
|
|
325
|
+
sf_int,
|
|
326
|
+
)
|
|
327
|
+
)
|
|
273
328
|
if ((sf_int[1]-sf_int[0])*24*60.*60. < min_ATI_length.to_value(u.second)) :
|
|
274
|
-
logging.debug(
|
|
329
|
+
logging.debug(
|
|
330
|
+
'Checked Interval shorter [{:3.1f}sec] than minimum ATI length time [{:3.1f}sec], original interval = {}, checked interval = {}'.format(
|
|
331
|
+
(sf_int[1]-sf_int[0])*24*60.*60.,
|
|
332
|
+
min_ATI_length.to_value(u.second),
|
|
333
|
+
original_sf_int,
|
|
334
|
+
sf_int,
|
|
335
|
+
)
|
|
336
|
+
)
|
|
275
337
|
pass
|
|
276
338
|
ATCs=[Time(sf_int, format='jd') for sf_int in sf_ints]
|
|
277
339
|
check_ATCs=True
|
|
@@ -290,8 +352,18 @@ def get_ob_ATCs(telescope=None, ob_info=None, run_info=None) :
|
|
|
290
352
|
if check_ATCs :
|
|
291
353
|
phase_range=''
|
|
292
354
|
if options.ephem is not None :
|
|
293
|
-
phase_range=
|
|
294
|
-
|
|
355
|
+
phase_range=" [Phases: {:5.3f} -- {:5.3f}]".format(
|
|
356
|
+
(((t[0]-Time(T0,format='jd'))/P).to_value(u.day)%1),
|
|
357
|
+
(((t[1]-Time(T0,format='jd'))/P).to_value(u.day)%1),
|
|
358
|
+
)
|
|
359
|
+
print("{:3d} {} -- {} [OB_exectime={}, Int.duration={}]{}".format(
|
|
360
|
+
i+1,
|
|
361
|
+
ob_ATCs[-1]['from'],
|
|
362
|
+
ob_ATCs[-1]['to'],
|
|
363
|
+
datetime.timedelta(seconds=ob_exec_time),
|
|
364
|
+
((t[1]-t[0]).to_datetime()),
|
|
365
|
+
phase_range,
|
|
366
|
+
))
|
|
295
367
|
if check_ATCs :
|
|
296
368
|
'''
|
|
297
369
|
logging.warning("****************************************************************************************")
|
|
@@ -306,14 +378,19 @@ def get_ob_ATCs(telescope=None, ob_info=None, run_info=None) :
|
|
|
306
378
|
print("****************************************************************************************")
|
|
307
379
|
print("Intervals via Orbital Ephemeris functionality is EXPERIMENTAL")
|
|
308
380
|
print("Please check the above intervals carefully and only continue if you are sure they are what YOU require.")
|
|
309
|
-
print("
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
381
|
+
print("Remember that ATCs specify the intervals during which the OBs must be started.")
|
|
382
|
+
print("While this code interprets the phase intervals as the intervals during which the OB must start AND finish.")
|
|
383
|
+
print("Therefore the ending phase intervals of the ATCs listed above will always be")
|
|
384
|
+
print("less than the phase intervals specified.")
|
|
385
|
+
print("Ultimately YOU, and YOU ALONE, are responsible for the accuracy of these intervals.")
|
|
386
|
+
if not options.NO_checkATCs :
|
|
387
|
+
yorn = input("Continue [y/N] ")
|
|
388
|
+
if yorn.lower() not in ['y',] :
|
|
389
|
+
print("Please contact ESO User Support via a ticket at https://support.eso.org/tickets")
|
|
390
|
+
print("to report/discuss the errors/problems in the above calculations.")
|
|
391
|
+
print("Please include in the description the EXACT command line used to run the script.")
|
|
392
|
+
sys.exit(0)
|
|
393
|
+
#raise Exception("Aborted.")
|
|
317
394
|
return ob_ATCs
|
|
318
395
|
# ------------------------------------------------------------------------------
|
|
319
396
|
def oneOB( api, obId ) :
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import datetime
|
|
3
|
+
import copy
|
|
4
|
+
|
|
5
|
+
# ---------------------------------------------------------------------------------------
|
|
6
|
+
## From https://stackoverflow.com/questions/51913210/python-script-with-timezone-fails-when-back-ported-to-python-2-7
|
|
7
|
+
ZERO = datetime.timedelta(0)
|
|
8
|
+
HOUR = datetime.timedelta(hours=1)
|
|
9
|
+
|
|
10
|
+
class UTC(datetime.tzinfo):
|
|
11
|
+
"""UTC"""
|
|
12
|
+
|
|
13
|
+
def utcoffset(self, dt):
|
|
14
|
+
return ZERO
|
|
15
|
+
|
|
16
|
+
def tzname(self, dt):
|
|
17
|
+
return "UTC"
|
|
18
|
+
|
|
19
|
+
def dst(self, dt):
|
|
20
|
+
return ZERO
|
|
21
|
+
|
|
22
|
+
tz_utc=UTC()
|
|
23
|
+
if hasattr(datetime,'timezone') :
|
|
24
|
+
if hasattr(datetime.timezone,'utc') :
|
|
25
|
+
tz_utc=datetime.timezone.utc
|
|
26
|
+
# ---------------------------------------------------------------------------------------
|
|
27
|
+
# ---------------------------------------------------------------------------------------
|
|
28
|
+
def get_ESO_period( d ):
|
|
29
|
+
"""
|
|
30
|
+
Return the (int) ESO period for a specified datetime.date or datetime.datetime
|
|
31
|
+
If d is naive (no timezone), UTC is assumed
|
|
32
|
+
"""
|
|
33
|
+
## ToDo: Update this method when we go to yearly cycle!
|
|
34
|
+
## 2024-07: currently planned for P117, with P116 lasting 7 months...
|
|
35
|
+
# 113 2024-04 -- 2024-09
|
|
36
|
+
# 114 2024-10 -- 2025-03
|
|
37
|
+
# 115 2025-04 -- 2026-09
|
|
38
|
+
# 116 2025-10 -- 2026-04
|
|
39
|
+
# 117 2026-05 -- 2027-04
|
|
40
|
+
# 118 2027-05 -- 2028-04
|
|
41
|
+
# ...
|
|
42
|
+
if isinstance(d,datetime.date) :
|
|
43
|
+
d=datetime.datetime(
|
|
44
|
+
year=d.year,
|
|
45
|
+
month=d.month,
|
|
46
|
+
day=d.day,
|
|
47
|
+
hour=0,
|
|
48
|
+
minute=0,
|
|
49
|
+
second=0,
|
|
50
|
+
microsecond=0,
|
|
51
|
+
tzinfo=tz_utc,
|
|
52
|
+
)
|
|
53
|
+
if d.tzinfo is None :
|
|
54
|
+
d=d.replace(tzinfo=tz_utc)
|
|
55
|
+
if d < datetime.datetime(2025,10,1,0,0,tzinfo=tz_utc) :
|
|
56
|
+
# P < 116...
|
|
57
|
+
return ((d.year-2012)+44)*2+int(float(d.month+2)/6.)
|
|
58
|
+
elif d > datetime.datetime(2026,5,1,0,0,tzinfo=tz_utc) :
|
|
59
|
+
# P > 116...
|
|
60
|
+
return ((d.year-2026)+116)+int(float(d.month+7)/12.)
|
|
61
|
+
elif d > datetime.datetime(2026,4,1,0,0,tzinfo=tz_utc) :
|
|
62
|
+
## Special case for 7month long P116
|
|
63
|
+
return ((d.year-2012)+44)*2+int(float(d.month+2)/7.)
|
|
64
|
+
return ((d.year-2012)+44)*2+int(float(d.month+2)/6.)
|
|
65
|
+
# ---------------------------------------------------------------------------------------
|
|
66
|
+
def current_ESO_period( days_from_now=0, dt=None ):
|
|
67
|
+
d=datetime.datetime.now(tz_utc) + datetime.timedelta(days=days_from_now)
|
|
68
|
+
return get_ESO_period(d)
|
|
69
|
+
# ---------------------------------------------------------------------------------------
|
|
70
|
+
def ESO_period_datetime_start( eso_period=current_ESO_period() ):
|
|
71
|
+
## ToDo: Update this method when we go to yearly cycle!
|
|
72
|
+
## 2024-07: currently planned for P117, with P116 lasting 7 months...
|
|
73
|
+
## i.e.
|
|
74
|
+
## P115 starts
|
|
75
|
+
if eso_period < 116 :
|
|
76
|
+
y=2024+(eso_period-113)//2
|
|
77
|
+
m=4+6*((eso_period-113)%2)
|
|
78
|
+
elif eso_period > 116 :
|
|
79
|
+
y=2026+(eso_period-117)
|
|
80
|
+
m=5
|
|
81
|
+
else :
|
|
82
|
+
y=2025
|
|
83
|
+
m=10
|
|
84
|
+
return datetime.datetime(y,m,1,0,0,0,0,tzinfo=tz_utc)
|
|
85
|
+
# ---------------------------------------------------------------------------------------
|
|
86
|
+
def ESO_period_datetime_end( eso_period=current_ESO_period() ):
|
|
87
|
+
return ESO_period_datetime_start((eso_period or current_ESO_period())+1)-datetime.timedelta(days=1)
|
|
88
|
+
# ---------------------------------------------------------------------------------------
|
|
89
|
+
def ESO_period_date_start( eso_period=current_ESO_period() ):
|
|
90
|
+
return ESO_period_datetime_start( eso_period ).date()
|
|
91
|
+
# ---------------------------------------------------------------------------------------
|
|
92
|
+
def ESO_period_date_end( eso_period=current_ESO_period() ):
|
|
93
|
+
return ESO_period_datetime_end( eso_period ).date()
|
|
94
|
+
# ---------------------------------------------------------------------------------------
|
|
95
|
+
# -----------------------------------------------------------------------------
|
|
96
|
+
if __name__ == '__main__' :
|
|
97
|
+
## ToDo: These tests, should be moved to proper tests...
|
|
98
|
+
|
|
99
|
+
## Testing get_ESO_period
|
|
100
|
+
## verify input date type is not changed
|
|
101
|
+
d=datetime.date(2024,4,1)
|
|
102
|
+
get_ESO_period(d)
|
|
103
|
+
assert isinstance(d,datetime.date)
|
|
104
|
+
|
|
105
|
+
# verify input datetime tzinfo is not modified
|
|
106
|
+
d=datetime.datetime(2024,4,1,0,0)
|
|
107
|
+
get_ESO_period(d)
|
|
108
|
+
assert d.tzinfo is None
|
|
109
|
+
|
|
110
|
+
# P113
|
|
111
|
+
assert get_ESO_period(datetime.date(2024,4,1)) == 113
|
|
112
|
+
assert get_ESO_period(datetime.datetime(2024,4,1,0,0)) == 113
|
|
113
|
+
assert get_ESO_period(datetime.datetime(2024,9,30,23,59,59)) == 113
|
|
114
|
+
# P114
|
|
115
|
+
assert get_ESO_period(datetime.datetime(2024,10,1,0,0)) == 114
|
|
116
|
+
assert get_ESO_period(datetime.datetime(2025,3,31,23,59,59)) == 114
|
|
117
|
+
# P115
|
|
118
|
+
assert get_ESO_period(datetime.datetime(2025,4,1,0,0)) == 115
|
|
119
|
+
assert get_ESO_period(datetime.datetime(2025,9,30,23,59,59)) == 115
|
|
120
|
+
# P116
|
|
121
|
+
assert get_ESO_period(datetime.datetime(2025,10,1,0,0)) == 116
|
|
122
|
+
assert get_ESO_period(datetime.datetime(2026,3,31,23,59,59)) == 116
|
|
123
|
+
assert get_ESO_period(datetime.datetime(2026,4,30,23,59,59)) == 116
|
|
124
|
+
# P117
|
|
125
|
+
assert get_ESO_period(datetime.datetime(2026,5,1,0,0)) == 117
|
|
126
|
+
assert get_ESO_period(datetime.datetime(2027,4,30,23,59,59)) == 117
|
|
127
|
+
# P118
|
|
128
|
+
assert get_ESO_period(datetime.datetime(2027,5,1,0,0)) == 118
|
|
129
|
+
assert get_ESO_period(datetime.datetime(2028,4,30,23,59,59)) == 118
|
|
130
|
+
|
|
131
|
+
## testing ESO_period_date_start() & ESO_period_date_end()
|
|
132
|
+
# P113
|
|
133
|
+
assert ESO_period_date_start(113) == datetime.date(2024,4,1)
|
|
134
|
+
assert ESO_period_date_end(113) == datetime.date(2024,9,30)
|
|
135
|
+
# P114
|
|
136
|
+
assert ESO_period_date_start(114) == datetime.date(2024,10,1)
|
|
137
|
+
assert ESO_period_date_end(114) == datetime.date(2025,3,31)
|
|
138
|
+
# P115
|
|
139
|
+
assert ESO_period_date_start(115) == datetime.date(2025,4,1)
|
|
140
|
+
assert ESO_period_date_end(115) == datetime.date(2025,9,30)
|
|
141
|
+
# P116
|
|
142
|
+
assert ESO_period_date_start(116) == datetime.date(2025,10,1)
|
|
143
|
+
assert ESO_period_date_end(116) == datetime.date(2026,4,30)
|
|
144
|
+
# P117
|
|
145
|
+
assert ESO_period_date_start(117) == datetime.date(2026,5,1)
|
|
146
|
+
assert ESO_period_date_end(117) == datetime.date(2027,4,30)
|
|
147
|
+
# P118
|
|
148
|
+
assert ESO_period_date_start(118) == datetime.date(2027,5,1)
|
|
149
|
+
assert ESO_period_date_end(118) == datetime.date(2028,4,30)
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
#! /usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
2
3
|
|
|
3
4
|
# $Id: generate_finding_charts.py 267033 2021-09-16 11:08:57Z jpritcha $
|
|
4
5
|
from __future__ import print_function
|
|
5
6
|
|
|
6
7
|
_VERSION_ = "$Revision: 267033 $"
|
|
8
|
+
from ..p2api import __version__
|
|
9
|
+
_VERSION_ = __version__
|
|
7
10
|
|
|
8
11
|
import sys # interaction with Python interpreter
|
|
9
12
|
from optparse import OptionParser # for parsing command line arguments
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
1
2
|
import datetime
|
|
2
3
|
import logging
|
|
3
4
|
import p2api
|
|
@@ -7,44 +8,50 @@ import getpass
|
|
|
7
8
|
import keyring
|
|
8
9
|
import re
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
from astropy.coordinates import EarthLocation
|
|
11
|
+
from p2api.utils.eso_period import *
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
try:
|
|
14
|
+
import astropy.units as u
|
|
15
|
+
from astropy.coordinates import EarthLocation
|
|
16
|
+
# The GPS coordinates of the UTs
|
|
17
|
+
# https://www.eso.org/sci/facilities/paranal/astroclimate/site.html
|
|
18
|
+
UT1_loc = EarthLocation.from_geodetic('-70d24m18.27s', '-24d37m39.44s', (2635.43+13.044)*u.m)
|
|
19
|
+
UT2_loc = EarthLocation.from_geodetic('-70d24m17.39s', '-24d37m37.80s', (2635.43+13.044)*u.m)
|
|
20
|
+
UT3_loc = EarthLocation.from_geodetic('-70d24m16.32s', '-24d37m36.64s', (2635.43+13.044)*u.m)
|
|
21
|
+
UT4_loc = EarthLocation.from_geodetic('-70d24m14.25s', '-24d37m37.36s', (2635.43+13.044)*u.m)
|
|
22
|
+
VST_loc = EarthLocation.from_geodetic('-70d24m14.27s', '-24d37m34.79s', (2635.43+4.5399)*u.m)
|
|
23
|
+
VISTA_loc = EarthLocation.from_geodetic('-70d23m51.36s', '-24d36m56.52s', (2530.)*u.m)
|
|
21
24
|
|
|
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)
|
|
25
|
+
# https://www.eso.org/sci/facilities/lasilla/telescopes/3p6/overview.html
|
|
26
|
+
## The telescope is at a geographical location of:
|
|
27
|
+
## 70° 43' 54.1" W -29° 15' 39.5" S (WGS84), 2400 metres above sea level
|
|
28
|
+
LS3p6_loc = EarthLocation.from_geodetic('-70d43m54.1s', '-29d15m39.5s', (2400.)*u.m)
|
|
26
29
|
|
|
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
|
+
# https://www.eso.org/sci/facilities/lasilla/telescopes/ntt/overview.html
|
|
31
|
+
## 70° 44' 01.5" W -29° 15' 32.1" S (WGS84), 2375m
|
|
32
|
+
LSntt_loc = EarthLocation.from_geodetic('-70d44m01.5s', '-29d15m32.1s', (2375.)*u.m)
|
|
30
33
|
|
|
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
|
-
}
|
|
34
|
+
# https://www.eso.org/sci/facilities/lasilla/telescopes/national/2p2.html
|
|
35
|
+
# 2p2 70°44'4"543 W 29°15'15"433 S
|
|
36
|
+
LS2p2_loc = EarthLocation.from_geodetic('-70d44m04.543s', '-29d15m15.433s', (2335.)*u.m)
|
|
47
37
|
|
|
38
|
+
## All together as a dictionary:
|
|
39
|
+
telescope_locations={
|
|
40
|
+
'UT1': UT1_loc,
|
|
41
|
+
'UT2': UT2_loc,
|
|
42
|
+
'UT3': UT3_loc,
|
|
43
|
+
'UT4': UT4_loc,
|
|
44
|
+
'VST': VST_loc,
|
|
45
|
+
'VISTA': VISTA_loc,
|
|
46
|
+
'LS3p6': LS3p6_loc,
|
|
47
|
+
'LSntt': LSntt_loc,
|
|
48
|
+
'LS2p2': LS2p2_loc,
|
|
49
|
+
}
|
|
50
|
+
except:
|
|
51
|
+
pass
|
|
52
|
+
'''
|
|
53
|
+
## ToDo: make usd_config module public...
|
|
54
|
+
## use local copy (for now) of usd_config.eso_period
|
|
48
55
|
# ---------------------------------------------------------------------------------------
|
|
49
56
|
def current_ESO_period():
|
|
50
57
|
d=datetime.datetime.utcnow()
|
|
@@ -59,7 +66,7 @@ def ESO_period_start_end_dates(P):
|
|
|
59
66
|
md1=ESO_period_first_last_dates[P%2][0]
|
|
60
67
|
y2=1967+(P+2)//2
|
|
61
68
|
md2=ESO_period_first_last_dates[P%2][1]
|
|
62
|
-
return [
|
|
69
|
+
return ["{}{}".format(y1,md1),"{y2}{md2}.format(y2,md2)"]
|
|
63
70
|
# ---------------------------------------------------------------------------------------
|
|
64
71
|
def ESO_period_start_end_datetimes(P):
|
|
65
72
|
ESO_period_first_last_dates=[
|
|
@@ -70,7 +77,20 @@ def ESO_period_start_end_datetimes(P):
|
|
|
70
77
|
md1=ESO_period_first_last_dates[P%2][0]
|
|
71
78
|
y2=1967+(P+2)//2
|
|
72
79
|
md2=ESO_period_first_last_dates[P%2][1]
|
|
73
|
-
return [
|
|
80
|
+
return ["{}{}".format(y1,md1),"{y2}{md2}.format(y2,md2)"]
|
|
81
|
+
'''
|
|
82
|
+
# ---------------------------------------------------------------------------------------
|
|
83
|
+
def ESO_period_start_end_dates(P):
|
|
84
|
+
return [
|
|
85
|
+
ESO_period_date_start(P),
|
|
86
|
+
ESO_period_date_end(P),
|
|
87
|
+
]
|
|
88
|
+
# ---------------------------------------------------------------------------------------
|
|
89
|
+
def ESO_period_start_end_datetimes(P):
|
|
90
|
+
return [
|
|
91
|
+
ESO_period_datetime_start(P),
|
|
92
|
+
ESO_period_datetime_end(P),
|
|
93
|
+
]
|
|
74
94
|
# ---------------------------------------------------------------------------------------
|
|
75
95
|
def get_attrs(klass):
|
|
76
96
|
return [k for k in klass.__dict__.keys()
|
|
@@ -280,8 +300,8 @@ def decode_datetime( d ) :
|
|
|
280
300
|
d_tz=d
|
|
281
301
|
for tz in tz_info :
|
|
282
302
|
d_tz=re.sub(
|
|
283
|
-
|
|
284
|
-
|
|
303
|
+
'{}.format(tz)',
|
|
304
|
+
'{}.format(tz_info[tz])',
|
|
285
305
|
d_tz,
|
|
286
306
|
)
|
|
287
307
|
for s in [d_tz,d] :
|
|
@@ -300,5 +320,5 @@ def decode_datetime( d ) :
|
|
|
300
320
|
return dt
|
|
301
321
|
except :
|
|
302
322
|
pass
|
|
303
|
-
raise Exception(
|
|
323
|
+
raise Exception("Could not decode date '{}'.".format(d))
|
|
304
324
|
# ---------------------------------------------------------------------------------------
|
|
@@ -36,14 +36,14 @@ classifiers = [
|
|
|
36
36
|
"Programming Language :: Python :: 3.12",
|
|
37
37
|
]
|
|
38
38
|
dependencies = [
|
|
39
|
-
"astroplan",
|
|
40
|
-
"astropy",
|
|
39
|
+
#"astroplan",
|
|
40
|
+
#"astropy",
|
|
41
41
|
"keyring",
|
|
42
42
|
"requests",
|
|
43
43
|
]
|
|
44
44
|
|
|
45
45
|
[project.scripts]
|
|
46
|
-
p2api_add_absolute_time_intervals = "p2api.utils.add_absolute_time_intervals:main"
|
|
46
|
+
#p2api_add_absolute_time_intervals = "p2api.utils.add_absolute_time_intervals:main"
|
|
47
47
|
p2api_generate_finding_charts = "p2api.utils.generate_finding_charts:main"
|
|
48
48
|
|
|
49
49
|
[project.urls]
|
|
@@ -55,4 +55,6 @@ path = "p2api/__about__.py"
|
|
|
55
55
|
[tool.hatch.build.targets.sdist]
|
|
56
56
|
include = [
|
|
57
57
|
"/p2api",
|
|
58
|
+
"/setup.py",
|
|
59
|
+
"/setup.cfg",
|
|
58
60
|
]
|
p2api-1.0.8/setup.cfg
ADDED
p2api-1.0.8/setup.py
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
import os
|
|
3
|
+
import io
|
|
4
|
+
|
|
5
|
+
'''
|
|
6
|
+
Restored setup.py & setup.cfg following instructions at:
|
|
7
|
+
Follow instructions at https://stackoverflow.com/questions/42287533/restore-deleted-file-with-history-in-git
|
|
8
|
+
|
|
9
|
+
git config --get remote.origin.url
|
|
10
|
+
git checkout a53fb714b8b48cd0112ae175a179e4a2c6859de1 -b restore_setuptools_build_support
|
|
11
|
+
git mv setup.py setup_1.py
|
|
12
|
+
git mv setup.cfg setup_1.cfg
|
|
13
|
+
git commit -m "Move file (1)"
|
|
14
|
+
SAVED=`git rev-parse HEAD`
|
|
15
|
+
git reset --hard "HEAD^"
|
|
16
|
+
git mv setup.py setup_2.py
|
|
17
|
+
git mv setup.cfg setup_2.cfg
|
|
18
|
+
git commit -m "Move file (2)"
|
|
19
|
+
git merge $SAVED
|
|
20
|
+
git commit -a -n
|
|
21
|
+
git checkout master
|
|
22
|
+
git merge restore_setuptools_build_support
|
|
23
|
+
git commit -a -n
|
|
24
|
+
git rm setup_1.py setup_1.cfg
|
|
25
|
+
git mv setup_2.py setup.py
|
|
26
|
+
git mv setup_2.cfg setup.cfg
|
|
27
|
+
git commit -m "recovery finished"
|
|
28
|
+
'''
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# ----------------------------------------------------
|
|
32
|
+
def read(*paths, **kwargs):
|
|
33
|
+
"""Read the contents of a text file safely.
|
|
34
|
+
>>> read("p2api", "VERSION")
|
|
35
|
+
'0.1.0'
|
|
36
|
+
>>> read("README.md")
|
|
37
|
+
...
|
|
38
|
+
"""
|
|
39
|
+
content = ""
|
|
40
|
+
with io.open(
|
|
41
|
+
os.path.join(os.path.dirname(__file__), *paths),
|
|
42
|
+
encoding=kwargs.get("encoding", "utf8"),
|
|
43
|
+
) as open_file:
|
|
44
|
+
content = open_file.read().strip()
|
|
45
|
+
return content
|
|
46
|
+
# ----------------------------------------------------
|
|
47
|
+
from p2api import __about__
|
|
48
|
+
setup(
|
|
49
|
+
name='p2api',
|
|
50
|
+
#version=read('p2api', 'VERSION'),
|
|
51
|
+
version=__about__.__version__,
|
|
52
|
+
description='Binding for the ESO phase 2 programmatic API',
|
|
53
|
+
long_description=read('README.md'),
|
|
54
|
+
long_description_content_type='text/markdown',
|
|
55
|
+
url='https://www.eso.org/copdemo/apidoc/index.html',
|
|
56
|
+
author='Thomas Bierwirth',
|
|
57
|
+
author_email='thomas.bierwirth@eso.org',
|
|
58
|
+
|
|
59
|
+
packages=['p2api', 'p2api/utils',],
|
|
60
|
+
include_package_data=True,
|
|
61
|
+
entry_points={
|
|
62
|
+
'console_scripts' : [
|
|
63
|
+
#'p2api_add_absolute_time_intervals = p2api.utils.add_absolute_time_intervals:main',
|
|
64
|
+
'p2api_generate_finding_charts = p2api.utils.generate_finding_charts:main',
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
# Classifiers help users find your project by categorizing it.
|
|
69
|
+
#
|
|
70
|
+
# For a list of valid classifiers, see
|
|
71
|
+
# https://pypi.python.org/pypi?%3Aaction=list_classifiers
|
|
72
|
+
classifiers=[ # Optional
|
|
73
|
+
# How mature is this project? Common values are
|
|
74
|
+
# 3 - Alpha
|
|
75
|
+
# 4 - Beta
|
|
76
|
+
# 5 - Production/Stable
|
|
77
|
+
'Development Status :: 5 - Production/Stable',
|
|
78
|
+
|
|
79
|
+
# Indicate who your project is intended for
|
|
80
|
+
'Intended Audience :: Developers',
|
|
81
|
+
|
|
82
|
+
# Pick your license as you wish
|
|
83
|
+
'License :: OSI Approved :: MIT License',
|
|
84
|
+
|
|
85
|
+
# Specify the Python versions you support here. In particular, ensure
|
|
86
|
+
# that you indicate whether you support Python 2, Python 3 or both.
|
|
87
|
+
'Programming Language :: Python :: 2',
|
|
88
|
+
'Programming Language :: Python :: 2.7',
|
|
89
|
+
'Programming Language :: Python :: 3',
|
|
90
|
+
'Programming Language :: Python :: 3.4',
|
|
91
|
+
'Programming Language :: Python :: 3.5',
|
|
92
|
+
'Programming Language :: Python :: 3.6',
|
|
93
|
+
'Programming Language :: Python :: 3.7',
|
|
94
|
+
'Programming Language :: Python :: 3.8',
|
|
95
|
+
'Programming Language :: Python :: 3.9',
|
|
96
|
+
'Programming Language :: Python :: 3.10',
|
|
97
|
+
],
|
|
98
|
+
|
|
99
|
+
# This field adds keywords for your project which will appear on the
|
|
100
|
+
# project page. What does your project relate to?
|
|
101
|
+
#
|
|
102
|
+
# Note that this is a string of words separated by whitespace, not a list.
|
|
103
|
+
keywords='ESO Phase2 Observation Preparation Programmatic API',
|
|
104
|
+
|
|
105
|
+
# You can just specify package directories manually here if your project is
|
|
106
|
+
# simple. Or you can use find_packages().
|
|
107
|
+
#
|
|
108
|
+
# Alternatively, if you just want to distribute a single Python file, use
|
|
109
|
+
# the `py_modules` argument instead as follows, which will expect a file
|
|
110
|
+
# called `my_module.py` to exist:
|
|
111
|
+
#
|
|
112
|
+
py_modules=["p2api"],
|
|
113
|
+
|
|
114
|
+
# This field lists other packages that your project depends on to run.
|
|
115
|
+
# Any package you put here will be installed by pip when your project is
|
|
116
|
+
# installed, so they must be valid existing projects.
|
|
117
|
+
#
|
|
118
|
+
# For an analysis of "install_requires" vs pip's requirements files see:
|
|
119
|
+
# https://packaging.python.org/en/latest/requirements.html
|
|
120
|
+
install_requires=[
|
|
121
|
+
'requests',
|
|
122
|
+
'keyring',
|
|
123
|
+
#'astropy', ## needed for add_absolute_time_intervals
|
|
124
|
+
#'astroplan', ## needed for add_absolute_time_intervals
|
|
125
|
+
],
|
|
126
|
+
license='MIT'
|
|
127
|
+
)
|
p2api-1.0.6/p2api/__about__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.0.6"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|