casaconfig 0.0.83__tar.gz → 0.0.85__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.
Files changed (37) hide show
  1. {casaconfig-0.0.83/casaconfig.egg-info → casaconfig-0.0.85}/PKG-INFO +1 -1
  2. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/__init__.py +1 -0
  3. casaconfig-0.0.85/casaconfig/__main__.py +139 -0
  4. casaconfig-0.0.85/casaconfig/private/CasaconfigErrors.py +42 -0
  5. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/config_defaults_static.py +3 -0
  6. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/data_available.py +16 -6
  7. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/data_update.py +91 -75
  8. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/do_auto_updates.py +22 -18
  9. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/do_pull_data.py +8 -8
  10. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/get_config.py +4 -4
  11. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/get_data_info.py +15 -9
  12. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/get_data_lock.py +19 -10
  13. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/measures_available.py +26 -11
  14. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/measures_update.py +90 -62
  15. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/print_log_messages.py +11 -6
  16. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/pull_data.py +71 -50
  17. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/read_readme.py +6 -6
  18. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/set_casacore_path.py +3 -3
  19. casaconfig-0.0.85/casaconfig/private/summary.py +90 -0
  20. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/update_all.py +17 -11
  21. {casaconfig-0.0.83 → casaconfig-0.0.85/casaconfig.egg-info}/PKG-INFO +1 -1
  22. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig.egg-info/SOURCES.txt +2 -0
  23. {casaconfig-0.0.83 → casaconfig-0.0.85}/setup.py +1 -1
  24. casaconfig-0.0.83/casaconfig/__main__.py +0 -104
  25. {casaconfig-0.0.83 → casaconfig-0.0.85}/LICENSE +0 -0
  26. {casaconfig-0.0.83 → casaconfig-0.0.85}/MANIFEST.in +0 -0
  27. {casaconfig-0.0.83 → casaconfig-0.0.85}/README.md +0 -0
  28. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/config.py +0 -0
  29. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/__init__.py +0 -0
  30. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/casasiteconfig_example.py +0 -0
  31. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/config_defaults.py +0 -0
  32. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/get_argparser.py +0 -0
  33. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig/private/io_redirect.py +0 -0
  34. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig.egg-info/dependency_links.txt +0 -0
  35. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig.egg-info/requires.txt +0 -0
  36. {casaconfig-0.0.83 → casaconfig-0.0.85}/casaconfig.egg-info/top_level.txt +0 -0
  37. {casaconfig-0.0.83 → casaconfig-0.0.85}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: casaconfig
3
- Version: 0.0.83
3
+ Version: 0.0.85
4
4
  Summary: CASA Operational Configuration Package
5
5
  Home-page: https://github.com/casangi/casaconfig
6
6
  Author: National Radio Astronomy Observatory
@@ -12,3 +12,4 @@ from .private.update_all import update_all
12
12
  from .private.set_casacore_path import set_casacore_path
13
13
  from .private.get_config import get_config
14
14
  from .private.get_data_info import get_data_info
15
+ from .private.CasaconfigErrors import *
@@ -0,0 +1,139 @@
1
+ import sys
2
+ import os
3
+ from casaconfig.private.get_argparser import get_argparser
4
+
5
+ parser = get_argparser(add_help=True)
6
+
7
+ # get_argparser supplies configfile, noconfig, nositeconfig
8
+ # add measurespath, pull-data, data-update, measures-update, update-all, reference-testing, current-data
9
+
10
+ parser.prog = "casaconfig"
11
+
12
+ # measurespath will default to the value in config if not set here
13
+ parser.add_argument( "--measurespath", dest='measurespath', default=None,
14
+ help="location of casarundata")
15
+
16
+ parser.add_argument( "--pull-data", dest='pulldata', action='store_const', const=True, default=False,
17
+ help="invoke pull_data() to populate measurespath with latest casarundata")
18
+ parser.add_argument( "--data-update", dest='dataupdate', action='store_const', const=True, default=False,
19
+ help="invoke data_update() to update measurespath to the latest casarundata")
20
+ parser.add_argument( "--measures-update", dest='measuresupdate', action='store_const', const=True, default=False,
21
+ help="invoke measures_update() to update measurespath to the latest measures data")
22
+ parser.add_argument( "--update-all", dest='updateall', action='store_const', const=True, default=False,
23
+ help="invoke update_all() to populate (update) measurespath with the latest casarundata and measures data")
24
+ parser.add_argument( "--reference-testing", action='store_const', const=True, dest='referencetesting', default=False,
25
+ help="set measurespath to the casarundata when this version was produced, used for testing purposes")
26
+ parser.add_argument( "--current-data", dest='currentdata', action='store_const', const=True, default=False,
27
+ help="print out a summary of the current casarundata and measures data installed in measurespath and then exit")
28
+ parser.add_argument( "--summary", dest='summary', action='store_const', const=True, default=False,
29
+ help="print out a summary of casaconfig data handling and the exit")
30
+ parser.add_argument("--force", dest='force', action='store_const', const=True, default=False,
31
+ help="force an update using the force=True option to update_all, data_update, and measures_update")
32
+
33
+ # initialize the configuration to be used
34
+ flags,args = parser.parse_known_args(sys.argv)
35
+ from casaconfig import config
36
+
37
+ # import the casaconfig module
38
+ import casaconfig
39
+
40
+ # make sure measurespath reflects any command line value
41
+ if flags.measurespath is None:
42
+ flags.measurespath = config.measurespath
43
+ else:
44
+ config.measurespath = flags.measurespath
45
+
46
+ # watch for measurespath of None, that likely means that casasiteconfig.py is in use and this has not been set. It can't be used then.
47
+ try:
48
+ if flags.measurespath is None:
49
+ print("measurespath has been set to None in the user or site config file.")
50
+ print("Either provide a measurespath on the casaconfig command line or edit the user or site config file to set measurespath to a location.")
51
+ sys.exit(1)
52
+
53
+ # do any expanduser and abspath - this is what should be used
54
+ measurespath = os.path.abspath(os.path.expanduser(flags.measurespath))
55
+
56
+ if flags.currentdata:
57
+ if not os.path.exists(measurespath) or not os.path.isdir(measurespath):
58
+ print("No data installed at %s. The measurespath does not exist or is not a directory." % measurespath)
59
+ else:
60
+ print("current data installed at %s" % measurespath)
61
+ dataInfo = casaconfig.get_data_info(measurespath)
62
+
63
+ # casarundata
64
+ casarunInfo = dataInfo['casarundata']
65
+ if casarunInfo is None or casarunInfo['version'] == "invalid":
66
+ print("No casarundata found (missing readme.txt and not obviously legacy casa data).")
67
+ if casarunInfo['version'] == "error":
68
+ print("Unexpected casarundata readme.txt content; casarundata should be reinstalled.")
69
+ elif casarunInfo['version'] == "unknown":
70
+ print("casarundata version is unknown (probably legacy casa data not maintained by casaconfig).")
71
+ else:
72
+ currentVersion = casarunInfo['version']
73
+ currentDate = casarunInfo['date']
74
+ print('casarundata version %s installed on %s' % (currentVersion, currentDate))
75
+
76
+ # measures
77
+ measuresInfo = dataInfo['measures']
78
+ if measuresInfo is None or measuresInfo['version'] == "invalid":
79
+ print("No measures data found (missing readme.txt and not obviously legacy measures data).")
80
+ if measuresInfo['version'] == "error":
81
+ print("Unexpected measures readme.txt content; measures should be reinstalled.")
82
+ elif measuresInfo['version'] == "unknown":
83
+ print("measures version is unknown (probably legacy measures data not maintained by casaconfig).")
84
+ else:
85
+ currentVersion = measuresInfo['version']
86
+ currentDate = measuresInfo['date']
87
+ print('measures version %s installed on %s' % (currentVersion, currentDate))
88
+
89
+ # ignore any other arguments
90
+ elif flags.summary:
91
+ from casaconfig.private.summary import summary
92
+ summary(config)
93
+ # ignore any other arguments
94
+ else:
95
+ if flags.referencetesting:
96
+ print("reference testing using pull_data and 'release' version into %s" % measurespath)
97
+ casaconfig.pull_data(measurespath,'release')
98
+ # ignore all other options
99
+ else:
100
+ # the update options, update all does everything, no need to invoke anything else
101
+ print("Checking for updates into %s" % measurespath)
102
+ if flags.updateall:
103
+ casaconfig.update_all(measurespath,force=flags.force)
104
+ else:
105
+ # do any pull_update first
106
+ if flags.pulldata:
107
+ casaconfig.pull_data(measurespath)
108
+ # then data_update, not necessary if pull_data just happened
109
+ if flags.dataupdate and not flags.pulldata:
110
+ casaconfig.data_update(measurespath, force=flags.force)
111
+ # then measures_update
112
+ if flags.measuresupdate:
113
+ casaconfig.measures_update(measurespath, force=flags.force)
114
+
115
+ except casaconfig.UnsetMeasurespath as exc:
116
+ # UnsetMeasurespath should not happen because measurespath is checked to not be None above, but just in case
117
+ print(str(exc))
118
+ print("This exception should not happen, check the previous messages for additional information and try a different path")
119
+ sys.exit(1)
120
+
121
+ except casaconfig.BadReadme as exc:
122
+ print(str(exc))
123
+ sys.exit(1)
124
+
125
+ except casaconfig.RemoteError as exc:
126
+ print(str(exc))
127
+ print("This is likely due to no network connection or bad connectivity to a remote site, wait and try again")
128
+ sys.exit(1)
129
+
130
+ except casaconfig.BadLock as exc:
131
+ # the output produced by the update functions is sufficient, just re-echo the exception text itself
132
+ print(str(exc))
133
+ sys.exit(1)
134
+
135
+ except casaconfig.NotWritable as exc:
136
+ print(str(exc))
137
+ sys.exit(1)
138
+
139
+ sys.exit(0)
@@ -0,0 +1,42 @@
1
+ # Copyright 2024 AUI, Inc. Washington DC, USA
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """
15
+ this module will be included in the api
16
+ """
17
+
18
+ class AutoUpdatesNotAllowed(Exception):
19
+ """Raised when a path does not exist or is not owned by the user"""
20
+ pass
21
+
22
+ class BadLock(Exception):
23
+ """Raised when the lock file is not empty and a lock attempt was made"""
24
+ pass
25
+
26
+ class BadReadme(Exception):
27
+ """Raised when a readme.txt file does not contain the expected contents"""
28
+ pass
29
+
30
+ class NoReadme(Exception):
31
+ """Raised when the readme.txt file is not found at path (path also may not exist)"""
32
+
33
+ class RemoteError(Exception):
34
+ """Raised when there is an error fetching some remote content"""
35
+ pass
36
+
37
+ class NotWritable(Exception):
38
+ """Raised when the path is not writable by the user"""
39
+
40
+ class UnsetMeasurespath(Exception):
41
+ """Raised when a path argument is None"""
42
+ pass
@@ -51,3 +51,6 @@ iplogfile='ipython-%s.log' % _time.strftime("%Y%m%d-%H%M%S", _time.gmtime())
51
51
 
52
52
  # include the user's local site-packages in the python path if True. May conflict with CASA modules
53
53
  user_site = False
54
+
55
+ # verbosity level for casaconfig
56
+ casaconfig_verbose = 1
@@ -29,18 +29,25 @@ def data_available():
29
29
  changing casaconfig functions that use those tarballs). The full filename is
30
30
  the casarundata version expected in casaconfig functions.
31
31
 
32
- Parameters
32
+ Parameters:
33
33
  None
34
34
 
35
- Returns
36
- list - version names returned as list of strings
35
+ Returns:
36
+ list: version names returned as list of strings
37
+
38
+ Raises:
39
+ casaconfig.RemoteError: Raised when there is an error fetching some remote content
40
+ Exception: Unexpected exception while getting list of available casarundata versions
37
41
 
38
42
  """
39
43
 
40
44
  import html.parser
41
45
  import urllib.request
46
+ import urllib.error
42
47
  import ssl
43
48
  import certifi
49
+
50
+ from casaconfig import RemoteError
44
51
 
45
52
  class LinkParser(html.parser.HTMLParser):
46
53
  def reset(self):
@@ -67,10 +74,13 @@ def data_available():
67
74
 
68
75
  # return the sorted list, earliest versions are first, newest is last
69
76
  return sorted(parser.rundataList)
70
-
77
+
78
+ except urllib.error.URLError as urlerr:
79
+ raise RemoteError("Unable to retrieve list of available casarundata versions : " + str(urlerr)) from None
80
+
71
81
  except Exception as exc:
72
- print("ERROR! : unexpected exception while getting list of available casarundata versions")
73
- print("ERROR! : %s" % exc)
82
+ msg = "Unexpected exception while getting list of available casarundata versions : " + str(exc)
83
+ raise Exception(msg)
74
84
 
75
85
  # nothing to return if it got here, must have been an exception
76
86
  return []
@@ -15,12 +15,14 @@
15
15
  this module will be included in the api
16
16
  """
17
17
 
18
- def data_update(path=None, version=None, force=False, logger=None, auto_update_rules=False):
18
+ def data_update(path=None, version=None, force=False, logger=None, auto_update_rules=False, verbose=None):
19
19
  """
20
20
  Check for updates to the installed casarundata and install the update or change to
21
21
  the requested version when appropriate.
22
22
 
23
- If no update is necessary then this function will silently return.
23
+ The verbose argument controls the level of information provided when this function when the data
24
+ are unchanged for expected reasons. A level of 0 prints and logs nothing. A
25
+ value of 1 logs the information and a value of 2 logs and prints the information.
24
26
 
25
27
  The path must contain a previously installed version of casarundata.
26
28
  Use pull_data to install casarundata into a new path (empty or does not exist).
@@ -92,36 +94,51 @@ def data_update(path=None, version=None, force=False, logger=None, auto_update_r
92
94
  **Note:** the most recent casarundata may not include the most recent measures data. A data_update
93
95
  is typically followed by a measures_update.
94
96
 
95
- Parameters
96
- - path (str=None) - Folder path to update. Must contain a valid readme.txt. If not set then config.measurespath is used.
97
- - version (str=None) - Version of casarundata to retrieve (usually in the form of casarundata-x.y.z.tar.gz, see data_available()). Default None retrieves the latest.
98
- - force (bool=False) - If True, always re-download the casarundata. Default False will not download casarundata if updated within the past day unless the version parameter is specified and different from what was last downloaded.
99
- - logger (casatools.logsink=None) - Instance of the casalogger to use for writing messages. Default None writes messages to the terminal.
100
- - auto_update_rules (bool=False) - If True then the user must be the owner of path, version must be None, and force must be False.
97
+ Parameters:
98
+ path (str=None): Folder path to update. Must contain a valid readme.txt. If not set then config.measurespath is used.
99
+ version (str=None): Version of casarundata to retrieve (usually in the form of casarundata-x.y.z.tar.gz, see data_available()). Default None retrieves the latest.
100
+ force (bool=False): If True, always re-download the casarundata. Default False will not download casarundata if updated within the past day unless the version parameter is specified and different from what was last downloaded.
101
+ logger (casatools.logsink=None): Instance of the casalogger to use for writing messages. Default None writes messages to the terminal.
102
+ auto_update_rules (bool=False): If True then the user must be the owner of path, version must be None, and force must be False.
103
+ verbose (int): Level of output, 0 is none, 1 is to logger, 2 is to logger and terminal, defaults to casaconfig_verbose in the config dictionary.
101
104
 
102
- Returns
105
+ Returns:
103
106
  None
104
107
 
108
+ Raises:
109
+ AutoUpdatesNotAllowed : raised when path does not exist as a directory or is not owned by the user
110
+ BadLock : raised when the lock file was not empty when an attempt was made to obtain the lock
111
+ BadReadme : raised when the readme.txt file at path did not contain the expected list of installed files or was incorrectly formatted
112
+ NoReadme : raised when the readme.txt file is not found at path (path also may not exist)
113
+ NotWritable : raised when the user does not have permission to write to path
114
+ RemoteError : raised by data_available when the list of available data versions could not be fetched
115
+ UnsetMeasurespath : raised when path is None and measurespath has not been set in config.
116
+ Exception: raised when there was an unexpected exception while populating path
117
+
105
118
  """
106
119
 
107
120
  import os
108
- from datetime import datetime
109
121
 
110
- from .data_available import data_available
122
+ from casaconfig import data_available
123
+ from casaconfig import pull_data
124
+ from casaconfig import get_data_info
125
+ from casaconfig import AutoUpdatesNotAllowed, BadReadme, BadLock, NoReadme, RemoteError, UnsetMeasurespath, NotWritable
111
126
  from .print_log_messages import print_log_messages
112
127
  from .get_data_lock import get_data_lock
113
- from .pull_data import pull_data
114
128
  from .do_pull_data import do_pull_data
115
- from .get_data_info import get_data_info
116
129
 
117
130
  if path is None:
118
131
  from .. import config as _config
119
132
  path = _config.measurespath
120
133
 
121
134
  if path is None:
122
- print_log_messages('path is None and has not been set in config.measurespath. Provide a valid path and retry.', logger, True)
135
+ raise UnsetMeasurespath('data_update: path is None and has not been set in config.measurespath. Provide a valid path and retry.')
123
136
  return
124
137
 
138
+ if verbose is None:
139
+ from .. import config as _config
140
+ verbose = _config.casaconfig_verbose
141
+
125
142
  # when a specific version is requested then the measures readme.txt that is part of that version
126
143
  # will get a timestamp of now so that default measures updates won't happen for a day unless the
127
144
  # force argument is used for measures_update
@@ -132,30 +149,24 @@ def data_update(path=None, version=None, force=False, logger=None, auto_update_r
132
149
 
133
150
  if auto_update_rules:
134
151
  if version is not None:
135
- print_log_messages('auto_update_rules requires that version be None', logger, True)
152
+ print_log_messages('data_update: auto_update_rules requires that version be None', logger, True)
136
153
  return
137
154
  if force:
138
- print_log_messages('force must be False when auto_update_rules is True', logger, True)
155
+ print_log_messages('data_update: force must be False when auto_update_rules is True', logger, True)
139
156
  return
140
157
  if (not os.path.isdir(path)) or (os.stat(path).st_uid != os.getuid()):
141
- msgs = []
142
- msgs.append("Warning: path must exist as a directory and it must be owned by the user, path = %s" % path)
143
- msgs.append("Warning: no data updates are possible on this path by this user.")
144
- print_log_messages(msgs, logger, False)
145
- return
158
+ raise AutoUpdatesNotAllowed("data_update: path must exist as a directory and it must be owned by the user, path = %s" % path)
146
159
 
147
160
  if not os.path.exists(readme_path):
148
161
  # path must exist and it must be empty in order to continue
149
162
  if not os.path.exists(path) or (len(os.listdir(path)) > 0):
150
- print_log_messages('No readme.txt file found at path. Nothing updated or checked.', logger, True);
151
- return
163
+ raise NoReadme('data_update: no casarundata readme.txt file found at %s. Nothing updated or checked.' % path);
152
164
  # ok to install a fresh copy, use pull_data directly
153
- return pull_data(path,version,force,logger)
165
+ return pull_data(path,version,force,logger,verbose)
154
166
 
155
167
  # path must be writable with execute bit set
156
168
  if (not os.access(path, os.W_OK | os.X_OK)) :
157
- print_log_messages('No permission to write to path, cannot update : %s' % path, logger, True)
158
- return
169
+ raise NotWritable('data_update: No permission to write to %s, cannot update.' % path)
159
170
 
160
171
  # try and digest the readme file
161
172
 
@@ -163,7 +174,8 @@ def data_update(path=None, version=None, force=False, logger=None, auto_update_r
163
174
  currentVersion = []
164
175
  currentDate = []
165
176
  ageRecent = False
166
-
177
+
178
+ # already checked that path is OK, type is OK here, no need to trap for exceptions here
167
179
  dataReadmeInfo = get_data_info(path, logger, type='casarundata')
168
180
 
169
181
  if dataReadmeInfo is None or dataReadmeInfo['version'] == 'invalid':
@@ -180,7 +192,7 @@ def data_update(path=None, version=None, force=False, logger=None, auto_update_r
180
192
  if dataReadmeInfo['age'] is not None:
181
193
  ageRecent = dataReadmeInfo['age'] < 1.0
182
194
 
183
- if currentVersion is 'unknown':
195
+ if currentVersion == 'unknown':
184
196
  msgs = []
185
197
  msgs.append('The data update path appears to be casarundata but no readme.txt file was found')
186
198
  msgs.append('A data update is not possible but CASA use of this data may be OK.')
@@ -189,20 +201,17 @@ def data_update(path=None, version=None, force=False, logger=None, auto_update_r
189
201
 
190
202
  if (len(installed_files) == 0):
191
203
  # this shouldn't happen
192
- msgs = []
193
- msgs.append('The readme.txt file at path did not contain the expected list of installed files')
194
- msgs.append('choose a different path or empty this path and try again using pull_data')
195
- print_log_messages(msgs, logger, True)
196
- # no lock has been set yet, safe to simply return here
197
- return
204
+ # no lock has been set yet, safe to raise this exception without worrying about the lock
205
+ raise BadReadme('data_update: the readme.txt file at path did not contain the expected list of installed files')
198
206
 
199
207
  if version is None and force is False and ageRecent:
200
208
  # if version is None, the readme is less than 1 day old and force is False then return without checking for any newer versions
201
- # normal use is silent, this line is useful during debugging
202
- # print_log_messages('data_update latest version checked recently in %s, using version %s' % (path, currentVersion), logger)
209
+ if verbose > 0:
210
+ print_log_messages('data_update: version installed or checked less than 1 day ago, nothing updated or checked', logger, verbose=verbose)
203
211
  # no lock has been set yet, safe to simply return here
204
212
  return
205
213
 
214
+ # this may raise a RemoteError, no need to catch that here but it may need to be caught upstream
206
215
  available_data = data_available()
207
216
  requestedVersion = version
208
217
  latestVersion = False
@@ -239,19 +248,20 @@ def data_update(path=None, version=None, force=False, logger=None, auto_update_r
239
248
  force = False
240
249
  # if measuresReadmeInfo is None then that's a problem and force remains True, this also catches 'invalid' and 'unknown' measures versions, which should not happen here
241
250
  if not force:
242
- # normal use is silent, this line is useful during debugging
243
- # print_log_messages('data_update requested "release" version of casarundata and measures are already installed.', logger)
251
+ if verbose > 0:
252
+ print_log_messages('data_update: requested "release" version of casarundata and measures are already installed.', logger, verbose=verbose)
244
253
  # no lock has been set yet, safe to simply return here
245
254
  return
246
255
  else:
247
256
  # normal usage, ok to return now
248
- # normal use is silent, commented out lines are useful during debugging
249
257
  if latestVersion:
250
- # print_log_messages('The latest version is already installed in %s, using version %s' % (path, currentVersion), logger)
258
+ if verbose > 0:
259
+ print_log_messages('The latest version is already installed in %s' % path, logger, verbose=verbose)
251
260
  # touch the dates of the readme to prevent a future check on available data for the next 24 hours
252
261
  os.utime(readme_path)
253
- #else:
254
- # print_log_messages('Requested casarundata is installed in %s, using version %s' % (path, currentVersion), logger)
262
+ else:
263
+ if verbose > 0:
264
+ print_log_messages('Requested casarundata version is already installed in %s, %s' % (path, currentVersion), logger, verbose=verbose)
255
265
 
256
266
  # no lock has been set yet, safe to simply return here
257
267
  return
@@ -259,19 +269,12 @@ def data_update(path=None, version=None, force=False, logger=None, auto_update_r
259
269
  # an update appears necessary
260
270
 
261
271
  lock_fd = None
272
+ clean_lock = True # set to False if the contents are actively being update and the lock file should not be cleaned on exception
262
273
  try:
263
274
  print_log_messages('data_update using version %s, acquiring the lock ... ' % requestedVersion, logger)
264
275
 
265
276
  lock_fd = get_data_lock(path, 'data_update')
266
- # if lock_fd is None it means the lock file was not empty - because we know that path exists at this point
267
- if lock_fd is None:
268
- msgs = []
269
- msgs.append('The lock file at %s is not empty.' % path)
270
- msgs.append('A previous attempt to update path may have failed or exited prematurely.')
271
- msgs.append('Remove the lock file and set force to True with the desired version (default to most recent).')
272
- msgs.append('It may be best to completely repopulate path using pull_data and measures_update.')
273
- print_log_messages(msgs, logger, True)
274
- return
277
+ # the BadLock exception that may happen here is caught below
275
278
 
276
279
  do_update = True
277
280
  # it's possible that another process had path locked and updated the readme with new information, re-read it
@@ -291,58 +294,71 @@ def data_update(path=None, version=None, force=False, logger=None, auto_update_r
291
294
  do_update = False
292
295
  # if measuresReadmeInfo is None there was a problem which requires a full update so do_update remains True
293
296
  if not do_update:
297
+ # always verbose here because the lock file is in use
294
298
  print_log_messages('data update requested "release" version of casarundata and measures are already installed.', logger)
295
299
  else:
296
300
  # nothing to do here, already at the expected version and an update is not being forced
297
301
  if latestVersion:
302
+ # always verbose here because the lock file is in use
298
303
  print_log_messages('The latest version is already installed, using version %s' % currentVersion, logger)
299
304
  # touch the dates of the readme to prevent a future check on available data for the next 24 hours
300
305
  os.utime(readme_path)
301
306
  else:
307
+ # always verbose here because the lock file is in use
302
308
  print_log_messages('requested version is already installed.', logger)
303
309
  do_update = False
304
310
 
305
311
  if do_update:
306
312
  # update is still on, check the manifest
307
313
  if len(installed_files) == 0:
308
- # this shouldn't happen, do not do an update
309
- do_update = False
310
- msgs = []
311
- msgs.append('The readme.txt file read at path did not contain the expected list of installed files')
312
- msgs.append('This should not happen unless multiple sessions are trying to update data at the same time and one experienced problems or was done out of sequence')
313
- msgs.append('Check for other updates in process or choose a different path or clear out this path and try again using pull_data or update_all')
314
- print_log_messages(msgs, logger, True)
314
+ # this shouldn't happen, do not do an update, raise the BadReadme exception, caught below and the lock cleaned up then
315
+ raise BadReadme('data_update: the readme.txt file at path did not contain the expected list of installed files')
315
316
  else:
316
- # this shouldn't happen, do not do an update
317
- do_update = False
318
- msgs = []
319
- msgs.append('Unexpected problem reading readme.txt file during data_update, can not safely update to the requested version')
320
- msgs.append('This should not happen unless multiple sessions are trying to update at the same time and one experienced problems or was done out of sequence')
321
- msgs.append('Check for other updates in process or choose a different path or clear out this path and try again using pull_data or update_all')
322
- print_log_messages(msgs, logger, True)
317
+ # this shouldn't happen
318
+ raise BadReadme('data_update: unexpected problem reading readme.txt file during data update, can not safely update to the requested version')
323
319
 
324
320
  if do_update:
321
+ # do not clean the lock file contents at this point unless do_pull_data returns normally
322
+ clean_lock = False
325
323
  do_pull_data(path, requestedVersion, installed_files, currentVersion, currentDate, logger)
326
- if namedVersion is not None:
324
+ clean_lock = True
325
+ if namedVersion:
327
326
  # a specific version has been requested, set the times on the measures readme.txt to now to avoid
328
327
  # a default update of the measures data without using the force argument
329
328
  measuresReadmePath = os.path.join(path,'geodetic/readme.txt')
330
329
  os.utime(measuresReadmePath)
331
330
 
332
- # truncate the lock file
333
- lock_fd.truncate(0)
331
+ except BadLock as exc:
332
+ # the path is known to exist so this means that the lock file was not empty and it's not locked
333
+ msgs = str(exc)
334
+ msgs.append('data_update: the lock file at %s is not empty.' % path)
335
+ msgs.append('A previous attempt to update path may have failed or exited prematurely.')
336
+ msgs.append('Remove the lock file and set force to True with the desired version (default to most recent).')
337
+ msgs.append('It may be best to completely re-populate path using pull_data and measures_update.')
338
+ print_log_messages(msgs, logger, True)
339
+ # reraise this
340
+ raise
341
+
342
+ except BadReadme as exc:
343
+ # something is wrong in the readme after an update was triggered, this shouldn't happen, print more context reraise this
344
+ msgs = str(exc)
345
+ msgs.append('This should not happen unless multiple sessions are trying to update data at the same time and one experienced problems or was done out of sequence')
346
+ msgs.append('Check for other updates in progress or choose a different path or clear out this path and try again using pull_data or update_all')
347
+ print_log_messages(msgs, logger, True)
348
+ raise
334
349
 
335
350
  except Exception as exc:
336
351
  msgs = []
337
352
  msgs.append('ERROR! : Unexpected exception while populating casarundata version %s to %s' % (requestedVersion, path))
338
353
  msgs.append('ERROR! : %s' % exc)
339
354
  print_log_messages(msgs, logger, True)
340
- # leave the contents of the lock file as is to aid in debugging
341
- # import traceback
342
- # traceback.print_exc()
343
-
344
- # if the lock file is not closed, do that now to release the lock
345
- if lock_fd is not None and not lock_fd.closed:
346
- lock_fd.close()
355
+ raise
356
+
357
+ finally:
358
+ # make sure the lock file is closed and also clean the lock file if safe to do so, this is always executed
359
+ if lock_fd is not None and not lock_fd.closed:
360
+ if clean_lock:
361
+ lock_fd.truncate(0)
362
+ lock_fd.close()
347
363
 
348
364
  return
@@ -15,7 +15,7 @@
15
15
  this module will be included in the api
16
16
  """
17
17
 
18
- def do_auto_updates(configDict, logger=None):
18
+ def do_auto_updates(configDict, logger=None, verbose=None):
19
19
  """
20
20
  Use measurespath, data_auto_update, and measures_auto_update from configDict to
21
21
  do any auto updates as necessary.
@@ -33,41 +33,45 @@ def do_auto_updates(configDict, logger=None):
33
33
  See the documentation for data_update and measures_update for additional details
34
34
  about the auto update rules.
35
35
 
36
- Paramters
37
- - configDict (dict) - A config dictionary previously set.
38
- - logger (casatools.logsink=None) - Instance of the casalogger to use for writing messages. Default None writes messages to the terminal.
36
+ The verbose argument controls the level of information provided when this function when the data
37
+ are unchanged for expected reasons. A level of 0 prints and logs nothing. A
38
+ value of 1 logs the information and a value of 2 logs and prints the information.
39
39
 
40
- Returns
40
+ See data_update and measures_update for additional details about exceptions
41
+
42
+ Paramters:
43
+ configDict (dict): A config dictionary previously set.
44
+ logger (casatools.logsink=None): Instance of the casalogger to use for writing messages. Default None writes messages to the terminal.
45
+ verbose (int): Level of output, 0 is none, 1 is to logger, 2 is to logger and terminal, defaults to casaconfig_verbose in the config dictionary.
46
+
47
+ Returns:
41
48
  None
42
49
 
50
+ Raises:
51
+ UnsetMeasurespath: raised when measurespath is None in config
52
+
43
53
  """
44
54
 
45
55
  from .print_log_messages import print_log_messages
46
56
  from .data_update import data_update
47
57
  from .measures_update import measures_update
48
58
 
59
+ from casaconfig import UnsetMeasurespath
60
+
49
61
  if configDict.measurespath is None:
50
62
  # continue, because things still might work if there are measures in datapath
51
- msgs = []
52
- msgs.append('measurespath is None in config')
53
- msgs.append('set measurespath in your config file at ~/.casa/config.py')
54
- msgs.append('or ask the site manager to set that in a casasiteconfig.py')
55
- msgs.append('visit https://casadocs.readthedocs.io/en/stable/notebooks/external-data.html for more information')
56
-
57
- if (configDict.measures_auto_update or configDict.data_auto_update):
58
- msgs.append('Auto updates of measures path are not possible because measurespath is not set, skipping auto updates')
59
-
60
- print_log_messages(msgs, logger, True)
63
+ raise UnsetMeasurespath('do_auto_updates: measurespath is None in configDict. Provide a valid path and retry.')
61
64
 
62
- return
65
+ if verbose is None:
66
+ verbose = configDict.casaconfig_verbose
63
67
 
64
68
  if (configDict.measures_auto_update or configDict.data_auto_update):
65
69
  if (configDict.data_auto_update and (not configDict.measures_auto_update)):
66
70
  print_log_messages('measures_auto_update must be True when data_auto_update is True, skipping auto updates', logger, True)
67
71
  else:
68
72
  if configDict.data_auto_update:
69
- data_update(configDict.measurespath, logger=logger, auto_update_rules=True)
73
+ data_update(configDict.measurespath, logger=logger, auto_update_rules=True, verbose=verbose)
70
74
  if configDict.data_auto_update or configDict.measures_auto_update:
71
- measures_update(configDict.measurespath, logger=logger, auto_update_rules=True)
75
+ measures_update(configDict.measurespath, logger=logger, auto_update_rules=True, verbose=verbose)
72
76
 
73
77
  return