skycalc-cli 1.5__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.
File without changes
skycalc_cli/skycalc.py ADDED
@@ -0,0 +1,398 @@
1
+ # -*- coding: utf-8 -*-
2
+ """skycalc Module"""
3
+
4
+ from __future__ import print_function
5
+ import os
6
+ import sys
7
+ import json
8
+ from datetime import datetime
9
+ import requests
10
+
11
+ # Base URL of the SkyCalc service (an ETC web installation). The CLI uses its
12
+ # CGI scripts under bin/script and the result directory tmp. This is the only
13
+ # place a server name appears; the backend is planned to move to a stable
14
+ # name under etc.eso.org, at which point only this constant changes.
15
+ # Override with the environment variable SKYCALC_CLI_BASE_URL or the base_url
16
+ # argument of SkyModel and AlmanacQuery, e.g.
17
+ # 'http://localhost:8080/observing/etc' for a local etc1 container.
18
+ DEFAULT_BASE_URL = 'https://etimecalret-002.eso.org/observing/etc'
19
+
20
+
21
+ def get_base_url(base_url=None):
22
+ """Return the base URL to use, without a trailing slash."""
23
+ url = base_url or os.environ.get('SKYCALC_CLI_BASE_URL') or DEFAULT_BASE_URL
24
+ return url.rstrip('/')
25
+
26
+
27
+ class AlmanacQuery:
28
+ """AlmanacQuery for Querying the SkyCalc Almanac"""
29
+
30
+ def __init__(self, indic, base_url=None):
31
+
32
+ self.almdata = None
33
+ self.almurl = get_base_url(base_url) + '/bin/script/skycalc_almanac.py'
34
+
35
+ # Left: users keyword (skycalc_cli),
36
+ # Right: skycalc Almanac output keywords
37
+ self.alm_parameters = {}
38
+ self.alm_parameters['airmass'] = 'target_airmass'
39
+ self.alm_parameters['msolflux'] = 'sun_aveflux'
40
+ self.alm_parameters['moon_sun_sep'] = 'moon_sun_sep'
41
+ self.alm_parameters['moon_target_sep'] = 'moon_target_sep'
42
+ self.alm_parameters['moon_alt'] = 'moon_alt'
43
+ self.alm_parameters['moon_earth_dist'] = 'moon_earth_dist'
44
+ self.alm_parameters['ecl_lon'] = 'ecl_lon'
45
+ self.alm_parameters['ecl_lat'] = 'ecl_lat'
46
+ self.alm_parameters['observatory'] = 'observatory'
47
+
48
+ self.almindic = {}
49
+ # The Almanac needs:
50
+ # coord_ra : float [deg]
51
+ # coord_dec : float [deg]
52
+ # input_type : ut_time | local_civil_time | mjd
53
+ # mjd : float
54
+ # coord_year : int
55
+ # coord_month : int
56
+ # coord_day : int
57
+ # coord_ut_hour : int
58
+ # coord_ut_min : int
59
+ # coord_ut_sec : float
60
+
61
+ if 'date' in indic:
62
+ self.almindic['input_type'] = 'ut_time'
63
+ isotime = None
64
+ try:
65
+ isotime = datetime.strptime(indic['date'],
66
+ '%Y-%m-%dT%H:%M:%S')
67
+ except ValueError:
68
+ print('Error: wrong date format for the Almanac.')
69
+ raise
70
+ self.almindic['coord_year'] = isotime.year
71
+ self.almindic['coord_month'] = isotime.month
72
+ self.almindic['coord_day'] = isotime.day
73
+ self.almindic['coord_ut_hour'] = isotime.hour
74
+ self.almindic['coord_ut_min'] = isotime.minute
75
+ self.almindic['coord_ut_sec'] = isotime.second
76
+
77
+ elif 'mjd' in indic:
78
+ self.almindic['input_type'] = 'mjd'
79
+ mjd = None
80
+ try:
81
+ mjd = float(indic['mjd'])
82
+ except ValueError:
83
+ print('Error: wrong mjd format for the Almanac.')
84
+ raise
85
+ self.almindic['mjd'] = mjd
86
+
87
+ else:
88
+ raise ValueError('Error: no date or mjd given for the Almanac')
89
+
90
+ if 'ra' not in indic:
91
+ raise ValueError('Error: ra coordinate not given for the Almanac.')
92
+
93
+ if 'dec' not in indic:
94
+ raise ValueError('Error: dec coordinate '
95
+ 'not given for the Almanac.')
96
+
97
+ ra = None
98
+ try:
99
+ ra = float(indic['ra'])
100
+ except ValueError:
101
+ print('Error: wrong ra format for the Almanac.')
102
+ raise
103
+ self.almindic['coord_ra'] = ra
104
+
105
+ dec = None
106
+ try:
107
+ dec = float(indic['dec'])
108
+ except ValueError:
109
+ print('Error: wrong dec format for the Almanac.')
110
+ raise
111
+ self.almindic['coord_dec'] = dec
112
+
113
+ if 'observatory' in indic:
114
+ self.almindic['observatory'] = indic['observatory']
115
+
116
+ def query(self):
117
+
118
+ rawdata = None
119
+ try:
120
+ response = requests.post(self.almurl, data=json.dumps(self.almindic))
121
+ rawdata = response.text
122
+ except requests.exceptions.RequestException as e:
123
+ print('Error: Almanac query failed.')
124
+ raise
125
+
126
+ # Process rawdata
127
+ jsondata = None
128
+ try:
129
+ jsondata = json.loads(rawdata)
130
+ jsondata = jsondata['output']
131
+ except (KeyError, ValueError):
132
+ print('Error: invalid Almanac response.')
133
+ raise
134
+
135
+ # Find the relevant (key, value)
136
+ almdata = {}
137
+ for key, value in self.alm_parameters.items():
138
+ subsection = 'nothing'
139
+ prefix = value.split('_')[0]
140
+ if prefix == 'sun' or prefix == 'moon' or prefix == 'target':
141
+ subsection = prefix
142
+ elif prefix == 'ecl':
143
+ subsection = 'target'
144
+ else:
145
+ subsection = 'observation'
146
+ try:
147
+ almdata[key] = jsondata[subsection][value]
148
+ except (KeyError, ValueError):
149
+ print('Warning: key "' + subsection + '/' + value +
150
+ '" not found in the Almanac response.')
151
+
152
+ return almdata
153
+
154
+
155
+ class bcolors:
156
+ HEADER = '\033[95m'
157
+ OKBLUE = '\033[94m'
158
+ OKGREEN = '\033[92m'
159
+ WARNING = '\033[93m'
160
+ FAIL = '\033[91m'
161
+ ENDC = '\033[0m'
162
+ BOLD = '\033[1m'
163
+ UNDERLINE = '\033[4m'
164
+
165
+
166
+ class SkyModel:
167
+ """SkyModel for querying the Advanced SkyModel"""
168
+
169
+ def __init__(self, base_url=None):
170
+
171
+ self.stop_on_errors_and_exceptions = True
172
+ self.data = None
173
+ self.base_url = get_base_url(base_url)
174
+ self.url = self.base_url + '/bin/script/skycalc_api.py'
175
+ self.deleter_script_url = self.base_url + '/bin/script/rmtmp.py'
176
+ self.bugreport_text = ''
177
+ self.tmpdir = ''
178
+ self.params = {
179
+ # Airmass. Alt and airmass are coupled through the plane parallel
180
+ # approximation airmass=sec(z), z being the zenith distance
181
+ # z=90°−Alt
182
+ 'airmass': 1.0, # float range [1.0,3.0]
183
+
184
+ # Season and Period of Night
185
+ 'pwv_mode': 'pwv', # string grid ['pwv','season']
186
+ # integer grid [0,1,2,3,4,5,6] (0=all year, 1=dec/jan,2=feb/mar...)
187
+ 'season': 0,
188
+ # third of night integer grid [0,1,2,3] (0=all year, 1,2,3 = third
189
+ # of night)
190
+ 'time': 0,
191
+
192
+ # Precipitable Water Vapor PWV
193
+ # mm float grid [-1.0,0.5,1.0,1.5,2.5,3.5,5.0,7.5,10.0,20.0]
194
+ 'pwv': 3.5,
195
+
196
+ # Monthly Averaged Solar Flux
197
+ 'msolflux': 130.0, # s.f.u float > 0
198
+
199
+ # Scattered Moon Light
200
+ # Moon coordinate constraints: |z – zmoon| ≤ ρ ≤ |z + zmoon| where
201
+ # ρ=moon/target separation, z=90°−target altitude and
202
+ # zmoon=90°−moon altitude.
203
+ # string grid ['Y','N'] flag for inclusion of scattered moonlight.
204
+ 'incl_moon': 'Y',
205
+ # degrees float range [0.0,360.0] Separation of Sun and Moon as
206
+ # seen from Earth ("moon phase")
207
+ 'moon_sun_sep': 90.0,
208
+ # degrees float range [0.0,180.0] Moon-Target Separation ( ρ )
209
+ 'moon_target_sep': 45.0,
210
+ # degrees float range [-90.0,90.0] Moon Altitude over Horizon
211
+ 'moon_alt': 45.0,
212
+ # float range [0.91,1.08] Moon-Earth Distance (mean=1)
213
+ 'moon_earth_dist': 1.0,
214
+
215
+ # Starlight
216
+ # string grid ['Y','N'] flag for inclusion of scattered starlight
217
+ 'incl_starlight': 'Y',
218
+
219
+ # Zodiacal light
220
+ # string grid ['Y','N'] flag for inclusion of zodiacal light
221
+ 'incl_zodiacal': 'Y',
222
+ # degrees float range [-180.0,180.0] Heliocentric ecliptic
223
+ # longitude
224
+ 'ecl_lon': 135.0,
225
+ # degrees float range [-90.0,90.0] Ecliptic latitude
226
+ 'ecl_lat': 90.0,
227
+
228
+ # Molecular Emission of Lower Atmosphere
229
+ # string grid ['Y','N'] flag for inclusion of lower atmosphere
230
+ 'incl_loweratm': 'Y',
231
+ # Emission Lines of Upper Atmosphere
232
+ # string grid ['Y','N'] flag for inclusion of upper stmosphere
233
+ 'incl_upperatm': 'Y',
234
+ # Airglow Continuum (Residual Continuum)
235
+ # string grid ['Y','N'] flag for inclusion of airglow
236
+ 'incl_airglow': 'Y',
237
+
238
+ # Instrumental Thermal Emission This radiance component represents
239
+ # an instrumental effect. The emission is provided relative to the
240
+ # other model components. To obtain the correct absolute flux, an
241
+ # instrumental response curve must be applied to the resulting
242
+ # model spectrum See section 6.2.4 in the documentation
243
+ # http://localhost/observing/etc/doc/skycalc/
244
+ # The_Cerro_Paranal_Advanced_Sky_Model.pdf
245
+ # string grid ['Y','N'] flag for inclusion of instrumental thermal
246
+ # radiation
247
+ 'incl_therm': 'N',
248
+ 'therm_t1': 0.0, # K float > 0
249
+ 'therm_e1': 0.0, # float range [0,1]
250
+ 'therm_t2': 0.0, # K float > 0
251
+ 'therm_e2': 0.0, # float range [0,1]
252
+ 'therm_t3': 0.0, # float > 0
253
+ 'therm_e3': 0.0, # K float range [0,1]
254
+
255
+ # Wavelength Grid
256
+ 'vacair': 'vac', # vac or air
257
+ 'wmin': 300.0, # nm float range [300.0,30000.0] < wmax
258
+ 'wmax': 2000.0, # nm float range [300.0,30000.0] > wmin
259
+ # string grid ['fixed_spectral_resolution','fixed_wavelength_step',
260
+ # 'user']
261
+ 'wgrid_mode': 'fixed_wavelength_step',
262
+ # nm/step float range [0,30000.0] wavelength sampling step dlam
263
+ # (not the res.element)
264
+ 'wdelta': 0.1,
265
+ # float range [0,1.0e6] RESOLUTION is misleading, it is rather
266
+ # lam/dlam where dlam is wavelength step (not the res.element)
267
+ 'wres': 20000,
268
+ 'wgrid_user': [500.0, 510.0, 520.0, 530.0, 540.0, 550.0],
269
+ # convolve by Line Spread Function
270
+ 'lsf_type': 'none', # string grid ['none','Gaussian','Boxcar']
271
+ 'lsf_gauss_fwhm': 5.0, # wavelength bins float > 0
272
+ 'lsf_boxcar_fwhm': 5.0, # wavelength bins float > 0
273
+ 'observatory': 'paranal', # paranal
274
+ # compute temperature and bolometric radiance
275
+ 'temp_flag': 1
276
+ }
277
+
278
+ def handle_exception(self, e, msg):
279
+ print(msg)
280
+ print(e)
281
+ print(self.bugreport_text)
282
+ if(self.stop_on_errors_and_exceptions):
283
+ sys.exit()
284
+
285
+ # handle the kind of errors we issue ourselves.
286
+ def handle_error(self, msg, stop=True):
287
+ print(msg)
288
+ print(self.bugreport_text)
289
+ if(self.stop_on_errors_and_exceptions):
290
+ sys.exit()
291
+
292
+ def retrieve_data(self, url):
293
+ try:
294
+ response = requests.get(url, stream=True)
295
+ self.data = response.content
296
+ except requests.exceptions.RequestException as e:
297
+ self.handle_exception(
298
+ e, 'Exception raised trying to get FITS data from ' + url)
299
+
300
+ def write(self, local_filename):
301
+ try:
302
+ with open(local_filename, 'wb') as f:
303
+ f.write(self.data)
304
+ except IOError as e:
305
+ self.handle_exception(
306
+ e, 'Exception raised trying to write fits file ')
307
+
308
+ def getdata(self):
309
+ return self.data
310
+
311
+ def delete_server_tmpdir(self, tmpdir):
312
+ try:
313
+ response = requests.get(self.deleter_script_url + '?d=' + tmpdir)
314
+ deleter_response = response.text.strip()
315
+ if(deleter_response != 'ok'):
316
+ self.handle_error('Could not delete server tmpdir ' + tmpdir)
317
+ except requests.exceptions.RequestException as e:
318
+ pass # ignore the exception
319
+
320
+ def call(self, test=False):
321
+ # print 'self.url=',self.url
322
+ # print 'self.params=',self.params
323
+ try:
324
+ response = requests.post(self.url, data=json.dumps(self.params))
325
+ except requests.exceptions.RequestException as e:
326
+ self.handle_exception(
327
+ e, 'Exception raised trying to POST request ' + self.url)
328
+ try:
329
+ res = json.loads(response.text)
330
+ status = res['status']
331
+ tmpdir = res['tmpdir']
332
+ except (KeyError, ValueError) as e:
333
+ self.handle_exception(
334
+ e, 'Exception raised trying to decode server response ')
335
+
336
+ tmpurl = self.base_url + '/tmp/' + tmpdir + '/skytable.fits'
337
+
338
+ if(status == 'success'):
339
+ try:
340
+ # retrive and save FITS data (in memory)
341
+ self.retrieve_data(tmpurl)
342
+ except requests.exceptions.RequestException as e:
343
+ self.handle_exception(
344
+ e, 'could not retrieve FITS data from server')
345
+
346
+ self.delete_server_tmpdir(tmpdir)
347
+
348
+ else: # print why validation failed
349
+ self.handle_error('parameter validation error: ' +
350
+ res['error'])
351
+
352
+ if(test):
353
+ # print 'call() returning status:',status
354
+ return status
355
+
356
+ def callwith(self, newparams):
357
+ for key, val in newparams.items():
358
+ self.params[key] = val
359
+ self.call()
360
+
361
+ def printparams(self, keys=None):
362
+ if keys is None:
363
+ p = self.params
364
+ else:
365
+ p = dict((k, self.params[k]) for k in keys)
366
+ for k in p:
367
+ print(k, p[k])
368
+
369
+ def test(self, label, overwite_params):
370
+ from cStringIO import StringIO
371
+
372
+ # capture stdout for a while
373
+ old_stdout = sys.stdout
374
+ sys.stdout = mystdout = StringIO()
375
+
376
+ sm = SkyModel()
377
+ str_params = ''
378
+ # replace all matching keywords with the values in the newdict
379
+ for key, val in overwite_params.items():
380
+ if key in sm.params:
381
+ sm.params[key] = val
382
+ str_params = str_params + str(key) + ' : ' + str(val) + ', '
383
+ status = sm.call(True) # set True for test
384
+
385
+ # restore original stdout
386
+ sys.stdout = old_stdout
387
+ toprint = label + '\t'
388
+ # print str_params
389
+ if(status == 'success'):
390
+ toprint += bcolors.OKGREEN + ' *** pass *** ' + bcolors.ENDC
391
+ else:
392
+ toprint += bcolors.FAIL + ' *** fail *** ' + bcolors.ENDC
393
+ print(toprint)
394
+
395
+ print(mystdout.getvalue())
396
+
397
+ def reset(self):
398
+ self.__init__()
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ # European Southern Observatory
5
+ # For any scientific or technical question,
6
+ # please contact usd-help@eso.org
7
+
8
+ from __future__ import print_function
9
+ import sys
10
+ import json
11
+ import getopt
12
+ from .skycalc import SkyModel
13
+ from .skycalc import AlmanacQuery
14
+
15
+
16
+ def loadTxt(inputFile):
17
+
18
+ result = {}
19
+
20
+ lineN = 0
21
+ for line in inputFile.readlines():
22
+
23
+ lineN += 1
24
+
25
+ originalLine = line
26
+ line = line.strip()
27
+ if len(line) == 0 or line[0] == '#':
28
+ continue
29
+ line = line.split(':')
30
+ if len(line) > 2 and line[0].strip() == 'date':
31
+ line = [line[0], ':'.join(line[1::])]
32
+ elif len(line) != 2 or (len(line) == 2 and (line[0].strip() == '' or
33
+ line[1].strip() == '')):
34
+ print('WARNING: input file line ' + str(lineN) +
35
+ ': wrong format: ignored.')
36
+ print(originalLine.rstrip())
37
+ continue
38
+ key = line[0].strip()
39
+ value = line[1].strip()
40
+
41
+ # Is it an integer?
42
+ try:
43
+ value = int(value)
44
+ except ValueError:
45
+ # Is it an float?
46
+ try:
47
+ value = float(value)
48
+ except ValueError:
49
+ pass
50
+
51
+ result[key] = value
52
+
53
+ return result
54
+
55
+
56
+ def fixObservatory(indic):
57
+
58
+ if 'observatory' in indic:
59
+ if indic['observatory'] == 'lasilla':
60
+ indic['observatory'] = '2400'
61
+ elif indic['observatory'] == 'paranal':
62
+ indic['observatory'] = '2640'
63
+ elif (indic['observatory'] == '3060m' or
64
+ indic['observatory'] == 'armazones'):
65
+ indic['observatory'] = '3060'
66
+ # elif indic['observatory'] == '5000m':
67
+ # indic['observatory'] = '5000'
68
+ else:
69
+ raise ValueError('Wrong Observatory name, please refer to the '
70
+ 'documentation.')
71
+ return indic
72
+
73
+
74
+ def usage():
75
+
76
+ print('usage: skycalc_cli -i|--in inputfile -o|--out file.fits ' +
77
+ '[-a|--alm almanacparameterfile] [-v|--verbose] [--version]')
78
+
79
+
80
+ def main():
81
+
82
+ argv = sys.argv[1:]
83
+
84
+ almFilename = None
85
+ inputFilename = None
86
+ outputFilename = None
87
+ isVerbose = False
88
+
89
+ # Read command line arguments
90
+ try:
91
+ opts, args = getopt.getopt(argv, "hva:i:o:", ["help", "verbose",
92
+ "version",
93
+ "alm=", "in=", "out="])
94
+ except getopt.GetoptError:
95
+ usage()
96
+ sys.exit(1)
97
+
98
+ for opt, arg in opts:
99
+ if opt in ("-h", "--help"):
100
+ usage()
101
+ sys.exit()
102
+ elif opt == "--version":
103
+ from importlib.metadata import version as pkg_version
104
+ print('skycalc_cli version ' + pkg_version('skycalc_cli'))
105
+ sys.exit(0)
106
+ elif opt in ("-v", "--verbose"):
107
+ isVerbose = True
108
+ elif opt in ("-a", "--alm"):
109
+ almFilename = arg
110
+ elif opt in ("-i", "--in"):
111
+ inputFilename = arg
112
+ elif opt in ("-o", "--out"):
113
+ outputFilename = arg
114
+
115
+ if not ((inputFilename or almFilename) and outputFilename):
116
+ usage()
117
+ sys.exit(1)
118
+
119
+ dic = {}
120
+
121
+ # Query the Almanac if alm option is enabled
122
+ if almFilename:
123
+
124
+ # Read the input parameters
125
+ inputalmdic = None
126
+ try:
127
+ with open(almFilename, 'r') as f:
128
+ inputalmdic = json.load(f)
129
+ except ValueError:
130
+ with open(almFilename, 'r') as f:
131
+ inputalmdic = loadTxt(f)
132
+
133
+ if not inputalmdic:
134
+ raise ValueError('Error: cannot read' + almFilename)
135
+
136
+ alm = AlmanacQuery(inputalmdic)
137
+ dic = alm.query()
138
+
139
+ if isVerbose:
140
+ print('Data retrieved from the Almanac:')
141
+ for key, value in dic.items():
142
+ print('\t' + str(key) + ': ' + str(value))
143
+
144
+ if inputFilename:
145
+
146
+ # Read input parameters
147
+ inputdic = None
148
+ try:
149
+ with open(inputFilename, 'r') as f:
150
+ inputdic = json.load(f)
151
+ except ValueError:
152
+ with open(inputFilename, 'r') as f:
153
+ inputdic = loadTxt(f)
154
+
155
+ if not inputdic:
156
+ raise ValueError('Error: cannot read ' + inputFilename)
157
+
158
+ # Override input parameters
159
+ if isVerbose:
160
+ print('Data overridden by the user\'s input file:')
161
+ for key, value in inputdic.items():
162
+ if isVerbose and key in dic:
163
+ print('\t' + str(key) + ': ' + str(value))
164
+ dic[key] = value
165
+
166
+ # Fix the observatory to fit the backend
167
+ try:
168
+ dic = fixObservatory(dic)
169
+ except ValueError:
170
+ raise
171
+
172
+ if isVerbose:
173
+ print('Data submitted to SkyCalc:')
174
+ for key, value in dic.items():
175
+ print('\t' + str(key) + ': ' + str(value))
176
+
177
+ # Get the Sky
178
+ skyModel = SkyModel()
179
+ skyModel.callwith(dic)
180
+ skyModel.write(outputFilename)
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2016 The Python Packaging Authority (PyPA)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,40 @@
1
+ Metadata-Version: 2.1
2
+ Name: skycalc_cli
3
+ Version: 1.5
4
+ Summary: ESO SkyCalc Command Line Interface
5
+ Home-page: http://www.eso.org/observing/etc/bin/gen/form?INS.MODE=swspectr+INS.NAME=SKYCALC
6
+ Author: European Southern Observatory
7
+ Author-email: usd-help@eso.org
8
+ License: MIT
9
+ Keywords: sky model observatory telescope astronomy ephemeris sun moon
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Topic :: Scientific/Engineering :: Astronomy
15
+ Requires-Python: >=3.8
16
+ License-File: LICENSE.txt
17
+ Requires-Dist: requests
18
+
19
+ ######################################
20
+ SkyCalc Command Line Interface (CLI)
21
+ ######################################
22
+
23
+ ============
24
+ Installation
25
+ ============
26
+
27
+ The SkyCalc CLI requires Python 3.8 or later (Python 2 users: pip installs
28
+ the last compatible release, 1.4). Install the SkyCalc CLI
29
+ on your computer using the command: ::
30
+
31
+ pip install --user skycalc_cli
32
+
33
+ This will also install skycalc_cli's dependency, i.e. the requests package for
34
+ making HTTP calls.
35
+
36
+ =============
37
+ Documentation
38
+ =============
39
+
40
+ Documentation can be found on the `ESO SkyCalc Web Page <https://www.eso.org/observing/etc/doc/skycalc/helpskycalccli.html>`_.
@@ -0,0 +1,9 @@
1
+ skycalc_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ skycalc_cli/skycalc.py,sha256=WJcah0qF3vwB-eeQlX3mdXthCKVM_uL8fpok7O-0TKc,14834
3
+ skycalc_cli/skycalc_cli.py,sha256=ITKOzYwEP8IMG24yu2VIA_v3bLgOWEoXHRNPgVUVPYo,5029
4
+ skycalc_cli-1.5.dist-info/LICENSE.txt,sha256=ceC9ZJOV9H6CtQDcYmHOS46NA3dHJ_WD4J9blH513pc,1081
5
+ skycalc_cli-1.5.dist-info/METADATA,sha256=J7N9RyEF1C9xMSSJjqwUO3sb6FvrkrArudTuJeOambI,1320
6
+ skycalc_cli-1.5.dist-info/WHEEL,sha256=Wyh-_nZ0DJYolHNn1_hMa4lM7uDedD_RGVwbmTjyItk,91
7
+ skycalc_cli-1.5.dist-info/entry_points.txt,sha256=hD1h_Z4cdfhVu7__PZP_a_3mBcvMB3nt8aqIAqsbkw8,61
8
+ skycalc_cli-1.5.dist-info/top_level.txt,sha256=m2M2VsOhj1sg5gsn6gm0UXHDaW_5-rLrJ_CkHUGbj2Q,12
9
+ skycalc_cli-1.5.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (71.1.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ skycalc_cli = skycalc_cli.skycalc_cli:main
@@ -0,0 +1 @@
1
+ skycalc_cli