casaconfig 1.2.0__py3-none-any.whl → 1.4.0__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.
@@ -16,45 +16,89 @@ def read_readme(path):
16
16
  """
17
17
  Read and parse the contents of a readme.txt file used by casaconfig.
18
18
 
19
- A dictionary containing the 'version', 'date', and 'extra' (containing
19
+ A dictionary containing the 'version', 'date', 'site', and 'extra' (containing
20
20
  a list of optional extra lines found). On error, the return values is None.
21
21
 
22
22
  The extra lines are stripped and do not include lines begining with '#'
23
23
 
24
24
  The format is assumed to be:
25
25
  a line begining with #, which is ignored.
26
+ a line "site: the site url string"
26
27
  a line "version : the versions string"
27
28
  a line "date : the date"
28
29
  optional extra lines (the manifest of installed files for the main readme)
29
30
 
30
- The version string and date are stripped of leading and trailing whitespace.
31
+ The version, site and date strings are stripped of leading and trailing whitespace.
32
+
33
+ The site string only appears in measures data and is missing is early readme
34
+ files for measures data. If no site string is seen the value in the dictionary
35
+ is None.
36
+
37
+ The version and date strings are required. If they are not found a BadReadme
38
+ exception is raised.
31
39
 
32
40
  Parameters
33
41
  - path (str) - the path to the file to be read
34
42
 
35
43
  Returns
36
- Dictionary of 'version' (the version string), 'date' (the date string),
37
- 'extra' (a list of any extra lines found). The return value is None on error.
44
+ Dictionary of 'site' ( the site URL or None), 'version' (the version string),
45
+ 'date' (the date string), 'extra' (a list of any extra lines found).
46
+ The return value is None on error except that format errors raise
47
+ a BadReadme exception.
48
+
49
+ Raises
50
+ - casaconfig.BadReadme - raised when there is a format error in the file at path
38
51
  """
39
52
 
40
53
  import os
54
+ from casaconfig import BadReadme
41
55
 
56
+ site = None
42
57
  version = ""
43
58
  date = ""
44
59
  extra = []
45
60
  result = None
46
-
61
+
47
62
  try:
48
63
  with open(path, 'r') as fid:
49
64
  readmeLines = fid.readlines()
50
- version = readmeLines[1].split(':')[1].strip()
51
- date = readmeLines[2].split(':')[1].strip()
52
- if len(readmeLines) > 3:
53
- for extraLine in readmeLines[3:]:
54
- if (extraLine[0] != '#'):
55
- extra.append(extraLine.strip())
56
- result = {'version':version, 'date':date, 'extra':extra}
57
- except:
65
+ # order is unimportant except the first line must start with
66
+ # an "#" and the second line starting with "#" indicates the
67
+ # start of the "extra" lines
68
+ # duplicate instances of the same key in key : value lines are accepted
69
+ # the last value associated with key is used, that should never happen.
70
+ inExtraLines = False
71
+ if readmeLines[0][0] != '#':
72
+ raise BadReadme('Readme file missing required "#" at start of first line, %s' % path)
73
+ for line in readmeLines[1:]:
74
+ if inExtraLines and not (line[0] == '#'):
75
+ extra.append(line.strip())
76
+ elif line[0] == '#':
77
+ inExtraLines = True
78
+ else:
79
+ splitLine = line.split(':')
80
+ if len(splitLine) < 2:
81
+ raise BadReadme('A line did not have an expected ":" separating into at least two parts, %s' % path)
82
+ key = splitLine[0].strip()
83
+ if key == 'site':
84
+ # the URL likely also has a ":" so rejoin the second part and then strip that
85
+ siteURL = ":".join(splitLine[1:])
86
+ site = siteURL.strip()
87
+ elif key == 'version':
88
+ version = splitLine[1].strip()
89
+ elif key == 'date':
90
+ date = splitLine[1].strip()
91
+ # anything else is OK and silently ignored
92
+ result = {'site':site, 'version':version, 'date':date, 'extra':extra}
93
+ except BadReadme as exc:
94
+ # reraise it
95
+ raise
96
+ except Exception as exc:
97
+ # silently return None, handled elsewhere
58
98
  result = None
59
99
 
100
+ # require that date and version are now set in result
101
+ if result is not None and ((len(result['version'])==0) or (len(result['date'])==0)):
102
+ raise BadReadme('Readme file missing required version or date fields, %s' % path)
103
+
60
104
  return result
@@ -32,12 +32,12 @@ def set_casacore_path(path=None):
32
32
  None
33
33
 
34
34
  """
35
- import pkg_resources
35
+ import importlib.resources
36
36
  import os
37
37
  import re
38
38
  import sys
39
39
 
40
- if path is None: path = pkg_resources.resource_filename('casaconfig', 'data/')
40
+ if path is None: path = str(importlib.resources.files('casaconfig').joinpath('data/'))
41
41
  path = os.path.abspath(os.path.expanduser(path))
42
42
 
43
43
  rctext = 'measures.directory: %s\n' % path
@@ -80,6 +80,9 @@ def summary(configDict = None):
80
80
  msg += "; legacy data not maintained by casaconfig"
81
81
  elif measVers == "error":
82
82
  msg += "; unexpected readme.txt file, measures should be reinstalled"
83
+ measSite = dataInfo['measures']['site']
84
+ if measSite is not None and len(measSite) > 0:
85
+ msg = msg + " site : " + measSite
83
86
  print(msg)
84
87
 
85
88
  if (dataInfo['release'] is None):
@@ -87,7 +87,8 @@ def update_all(path=None, logger=None, force=False, verbose=None):
87
87
  msgs = []
88
88
  msgs.append("Warning: path must exist as a directory and it must be owned by the user, path = %s" % path)
89
89
  msgs.append("Warning: no updates are possible on this path by this user.")
90
- print_log_messages(msgs, logger, False)
90
+ # always print and log this although it's only a warning
91
+ print_log_messages(msgs, logger, False, 2)
91
92
  return
92
93
 
93
94
  # if path is empty, first use pull_data
@@ -95,7 +96,7 @@ def update_all(path=None, logger=None, force=False, verbose=None):
95
96
  pull_data(path, logger, verbose=verbose)
96
97
  # double check that it's not empty
97
98
  if len(os.listdir(path))==0:
98
- print_log_messages("pull_data failed, see the error messages for more details. update_all can not continue")
99
+ print_log_messages("pull_data failed, see the error messages for more details. update_all can not continue", logger, True)
99
100
  return
100
101
 
101
102
  # readme.txt must exist in path at this point, using get_data_info provides more possible feedback
@@ -105,15 +106,15 @@ def update_all(path=None, logger=None, force=False, verbose=None):
105
106
  print_log_messages('could not find any data information about %s, can not continue with update_all' % path, logger, True)
106
107
 
107
108
  if dataInfo['casarundata'] is None:
108
- print_log_messages('readme.txt not found at path, update_all can not continue, path = %s' % path, logger)
109
+ print_log_messages('readme.txt not found at path, update_all can not continue, path = %s' % path, logger, True)
109
110
  return
110
111
 
111
112
  if dataInfo['casarundata'] == 'invalid':
112
- print_log_messages('readme.txt is invalid at path, update_all can not continue, path = %s' % path, logger)
113
+ print_log_messages('readme.txt is invalid at path, update_all can not continue, path = %s' % path, logger, True)
113
114
  return
114
115
 
115
116
  if dataInfo['casarundata'] == 'unknown':
116
- print_log_messages('contents at path appear to be casarundata but no readme.txt was found, casaconfig did not populate this data and update_all can not continue, path = %s', path, logger)
117
+ print_log_messages('contents at path appear to be casarundata but no readme.txt was found, casaconfig did not populate this data and update_all can not continue, path = %s', path, logger, True)
117
118
  return
118
119
 
119
120
  # the updates should work now
@@ -0,0 +1,92 @@
1
+ Metadata-Version: 2.4
2
+ Name: casaconfig
3
+ Version: 1.4.0
4
+ Summary: CASA Operational Configuration Package
5
+ Author-email: National Radio Astronomy Observatory <casa-feedback@nrao.edu>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://casa.nrao.edu/
8
+ Project-URL: Documentation, https://casadocs.readthedocs.io/
9
+ Project-URL: Repository, https://github.com/casangi/casaconfig.git
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: certifi>=2023.5.7
14
+ Dynamic: license-file
15
+
16
+ # casaconfig
17
+ Runtime data necessary for CASA operation.
18
+
19
+ - [latest casaconfig API on casadocs](https://casadocs.readthedocs.io/en/latest/api/casaconfig.html)
20
+ - [stable casaconfig API on casadocs](https://casadocs.readthedocs.io/en/stable/api/casaconfig.html)
21
+
22
+
23
+ ## Release Instructions
24
+ 1. Create a release branch with a version name (ie v1.6.2)
25
+ 2. Ensure the version number in pyproject.toml on the branch is set correctly
26
+ 3. Create a tag of the release branch (ie v1.6.2-1)
27
+ 4. Github Action runs automatically to publish a pip package to pypi
28
+
29
+ ## Installation
30
+
31
+ ```
32
+ $: pip install casaconfig
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ See the casaconfig API documentation on casadocs (links above).
38
+
39
+ Also see the External Data section of casadocs for additional details
40
+
41
+ - [latest External Data section on casadocs](https://casadocs.readthedocs.io/en/latest/notebooks/external-data.html)
42
+ - [stable External Data section on casadocs](https://casadocs.readthedocs.io/en/stable/notebooks/external-data.html)
43
+
44
+ ## Developers Instructions
45
+ 1. every push to the casaconfig repository will push a new wheel to [test pypi](https://test.pypi.org/project/casaconfig/#history)
46
+ 2. the version in pyproject.toml must be updated before each push so that the wheel has a unique name (e.g. "1.2.3dev2", where "dev?" could be incremented during development; see the [specification](https://packaging.python.org/en/latest/specifications/version-specifiers/#version-specifiers) for more information about valid version signifiers)
47
+ 3. When testing with a casatools build, "pip install" the development casaconfig wheel before running any tests - it may be installed before casatools is installed or after since the casatools build does not depend on casasconfig (uninstall any already installed casaconfig if necessary).
48
+ 4. For release, follow the above instructions.
49
+
50
+ Wheels can be built locally following the same process used by the CI actions. To install the build-system dependencies as defined in pyproject.toml and then generate a source distribution and wheel:
51
+ ```
52
+ python3 -m pip install build setuptools --user
53
+ python3 -m build
54
+ ```
55
+ This will create:
56
+ ```
57
+ casaconfig.egg-info
58
+ ├── PKG-INFO
59
+ ├── SOURCES.txt
60
+ ├── dependency_links.txt
61
+ ├── requires.txt
62
+ └── top_level.txt
63
+ dist
64
+ ├── casaconfig-[VERSION]-py3-none-any.whl
65
+ └── casaconfig-[VERSION].tar.gz
66
+ ```
67
+
68
+ ### Setting up CASA branches for casaconfig development
69
+
70
+ The casaconfig build process publishes test wheels to test.pypi.org
71
+
72
+ In order to test these with Casa packages, two changes are needed in the casa6 repository branch.
73
+
74
+ 1) Add a line to casa6/build.conf with the appropriate wheel version. For example:
75
+
76
+ ```
77
+ casaconfig==1.0.3.dev2
78
+ ```
79
+ 2) Add the following line with the apppropriate branch name to casa6/casatools/setup.py
80
+
81
+ ```
82
+ META_DATA["install_requires"] = "casaconfig@git+https://github.com/casangi/casaconfig@CAS-14512"
83
+ ```
84
+
85
+ This adds the casaconfig branch as a casatools install time dependency. It will not use the wheel, but rather build the branch in place. This is required in order to avoid adding test.pypi.org as a pip extra-index-url, which might cause other development packages to be installed inadvertently. Note that casaconfig dependency is typically defined in setup.cfg, but the syntax above does not work with setup.cfg.
86
+
87
+
88
+ ### Preparing the casa6 branch for merge
89
+
90
+ 1) Merge the casaconfig branch to main and create a wheel
91
+ 2) Update casa6/build.conf to use that wheel
92
+ 3) Comment out the extra "install_requires" line from setup.py
@@ -0,0 +1,34 @@
1
+ casaconfig/__init__.py,sha256=1PgCLSWtmkHm8kZ0O01RUaDdkPodfpl2VKX5h3rjotY,787
2
+ casaconfig/__main__.py,sha256=rmkK1hRFQSwNoVDJ3AV8Ht_36VY4DAceglevbcBNHcA,7541
3
+ casaconfig/config.py,sha256=LtDCEvRVo8PS-sNv2QHBF9N19_VoaQEj3LzjkiioWcQ,7711
4
+ casaconfig/private/CasaconfigErrors.py,sha256=5jgBGiFSussmC7tUAA-w0awYx-7hC6Dhv_OXNihJkkY,1519
5
+ casaconfig/private/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ casaconfig/private/casasiteconfig_example.py,sha256=J5C9an1iVhxqSbtYT_FiopDXx8SZDcVQkLWKufA_fnc,653
7
+ casaconfig/private/config_defaults.py,sha256=Qa105jNlH_k28kob_qFW7dTm0KtDMuxwnziPlQxxLFk,2127
8
+ casaconfig/private/config_defaults_static.py,sha256=MOm3xyqEXZZNisqcZY1b6QmBjJas1ol-ccMePT0v8MI,3459
9
+ casaconfig/private/data_available.py,sha256=osjljEt4RMwFd62PsYNh8Nsiw0FjLIBWolUuqqPO-3g,3108
10
+ casaconfig/private/data_update.py,sha256=7qQVrkmtsq9vGYtB-dL2egWx85E0zbt4aUW4wadGFOA,20575
11
+ casaconfig/private/do_auto_updates.py,sha256=GaPx9_Dt1kAUlcsA-cACV2-OTl19EDIf1pHDkVLPIdY,3551
12
+ casaconfig/private/do_pull_data.py,sha256=6CKFjX1qOdYFPexXXiLMal70gNoM36rcdZY-OfrfAuA,5705
13
+ casaconfig/private/do_untar_url.py,sha256=EWpwNGPcm6-G1TIhBjdlhS0j2YrQR3BSS7pWZv5W66w,4359
14
+ casaconfig/private/get_argparser.py,sha256=-pwPMplwBJssSiEOVte89MqBRuxbZ3jLNVluQrv_eGc,1670
15
+ casaconfig/private/get_available_files.py,sha256=iV7XBrhrJGD2iOQIancvcJJDWypeHftV_ICuGsCf0MQ,3733
16
+ casaconfig/private/get_config.py,sha256=R_6lZ3hp9NNbfBBhrOBBieXDFhR6Q3MdGHSgUwICbzk,1590
17
+ casaconfig/private/get_data_info.py,sha256=hZ6yBcJm--lRBzE2jLwhjKF3497aHtWtGrta7rec7Cc,13543
18
+ casaconfig/private/get_data_lock.py,sha256=JysF75EHwP2FErjffMkfeV-9wy5wJJ9irPDrMvVzSIo,3809
19
+ casaconfig/private/have_network.py,sha256=zCIbABTG_9ew9Ac3eb8ggNaZ_H61m_G4LCXkFZe7q5M,1410
20
+ casaconfig/private/io_redirect.py,sha256=9mwl2siS3fFYCEi_u9Mojg7cBtBgzW00mc8H7V1NSEs,2879
21
+ casaconfig/private/measures_available.py,sha256=SiGLDhr_nKQaXWVrKhiRPGeUOOL1C5LT5T1VtnIJ3dQ,12331
22
+ casaconfig/private/measures_update.py,sha256=jNTYsX5U6E-DD769oiImstB2dvJDy4E9GSertZrx4aU,25641
23
+ casaconfig/private/print_log_messages.py,sha256=zF8qRReNBk2I0biyG5OnlZCbXYIXhNnNF-vA7gYoyr8,2202
24
+ casaconfig/private/pull_data.py,sha256=7vIv0j1luhSdQ6jFF5USrGU2wQ4829iSqh2NDPO3NuQ,17594
25
+ casaconfig/private/read_readme.py,sha256=4fF5yy3HynkrFwhF6JUcc0DFQ-DP-WZEddrPpog8znI,4354
26
+ casaconfig/private/set_casacore_path.py,sha256=C6BON-qx1mjrFizUWHYDPzOXubRNEX-wjUJqOeu-ezw,2254
27
+ casaconfig/private/summary.py,sha256=xHpS9g3ZNv4ASNc_W05chKbZhHE-caeVnWhV9zsfvrY,3597
28
+ casaconfig/private/update_all.py,sha256=xCxNTHSPQHoqW1Cs237WNDhgUBrOvTXKpXAFbCbYK6E,5601
29
+ casaconfig-1.4.0.dist-info/licenses/LICENSE,sha256=OMpzmn2zUn6I4jmVqs1Coa_0NJcoJC9eweZ2gx-u0oI,11358
30
+ tests/test_casaconfig.py,sha256=Zitmb-bmAGQDYAilQvfODgZQViGpYRPNgtMnstCd-O4,53611
31
+ casaconfig-1.4.0.dist-info/METADATA,sha256=KSPNYf4Wf2gK2mGds-hF8bVDTAZw14res3GGYg4xDuQ,4037
32
+ casaconfig-1.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
33
+ casaconfig-1.4.0.dist-info/top_level.txt,sha256=Uay9WTPz644aHfLbmj47WXzue19HtKRueFFCXu1N1Co,17
34
+ casaconfig-1.4.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
tests/test_casaconfig.py CHANGED
@@ -1,11 +1,18 @@
1
1
  import unittest
2
- import os, shutil, stat, sys, subprocess, time
2
+ import os, shutil, stat, sys, subprocess, time, re
3
+ import copy
3
4
  from datetime import date, timedelta
4
5
  import site
5
6
  sitepackages = site.getsitepackages()[0]
6
7
 
7
8
  import casaconfig
8
9
 
10
+ def setDefaultConfig():
11
+ '''sets config to the default values'''
12
+ from casaconfig import config
13
+ for k in config.__defaults:
14
+ config.__dict__[k] = copy.deepcopy(config._config_defaults.__dict__[k])
15
+
9
16
  class casaconfig_test(unittest.TestCase):
10
17
 
11
18
  def setUp(self):
@@ -15,6 +22,8 @@ class casaconfig_test(unittest.TestCase):
15
22
  self.test_configpath = os.path.join(os.path.expanduser("~/.casa/"),"config.py")
16
23
  self.test_siteconfigpath = os.path.join(os.getcwd(),'testsiteconfig.py')
17
24
 
25
+ setDefaultConfig()
26
+
18
27
  # testmeasures is used for measures-only tests
19
28
  # testrundata is used for full data install tests (at least casarundata is installed, which includes measures)
20
29
  # emptymeasures is used to test failure modes
@@ -38,7 +47,7 @@ class casaconfig_test(unittest.TestCase):
38
47
 
39
48
  if os.path.isfile(os.path.expanduser("~/.casa/config.py.user")):
40
49
  os.replace(os.path.expanduser("~/.casa/config.py.user"), os.path.expanduser("~/.casa/config.py"))
41
-
50
+
42
51
  def rmTestDirs(self):
43
52
  if os.path.exists(self.testMeasPath):
44
53
  shutil.rmtree(self.testMeasPath)
@@ -85,12 +94,12 @@ class casaconfig_test(unittest.TestCase):
85
94
  self.assertTrue(dataInfo['version']==measVers,"unexpected version installed by populate_testmeasures at %s : %s != %s" % (self.testMeasPath, dataInfo['version'], measVers))
86
95
 
87
96
  def populate_testrundata(self):
88
- # ensures that there's some casaconfig populated casarundata at self.testMeasPath
97
+ # ensures that there's some casaconfig populated casarundata at self.testRundataPath
89
98
  # if there's a known version there it leave it as is
90
99
  # if the data info is None then it populates it with the most recent casarundata
91
100
  # the data info version can not be illegal or unknown (something unexpected is already there)
92
101
  # this function works as a test, but it happens on demand in an attempt to limit the calls to pull_data
93
-
102
+
94
103
  dataInfo = casaconfig.get_data_info(self.testRundataPath, type='casarundata')
95
104
  if dataInfo is not None:
96
105
  version = dataInfo['version']
@@ -230,7 +239,7 @@ class casaconfig_test(unittest.TestCase):
230
239
  # final check that the expected version is now installed
231
240
  installedVers = casaconfig.get_data_info(path=self.testRundataPath,type='measures')['version']
232
241
  self.assertTrue(installedVers == vers, "expected version was not installed : %s != %s" % (installedVers, vers))
233
-
242
+
234
243
  @unittest.skipIf(not os.path.exists(os.path.join(sitepackages,'casatools')), "casatools not found")
235
244
  def test_auto_update_measures(self):
236
245
  '''Test Automatic Measures Updates to measurespath'''
@@ -258,6 +267,7 @@ class casaconfig_test(unittest.TestCase):
258
267
  f.write('measurespath = "{}"\n'.format(self.testRundataPath))
259
268
  f.write('measures_auto_update = True\n')
260
269
  f.write('data_auto_update = False\n')
270
+ f.write('casaconfig_verbose = 2\n')
261
271
  f.close()
262
272
 
263
273
  # start a new casatools, which should update the measures to the most recent version
@@ -270,7 +280,7 @@ class casaconfig_test(unittest.TestCase):
270
280
  # output should contain the latest version string
271
281
  ref = self.get_meas_avail()[-1] in str(output)
272
282
  self.assertTrue(ref, "Update Failed")
273
-
283
+
274
284
  @unittest.skipIf(not os.path.exists(os.path.join(sitepackages,'casatools')), "casatools not found")
275
285
  def test_auto_install_data(self):
276
286
  '''Test auto install of all data to measurespath on casatools startup'''
@@ -625,6 +635,14 @@ class casaconfig_test(unittest.TestCase):
625
635
  # This should work on any non-open path that isn't a measurespath. I think the cwd will
626
636
  # work just fine for that purposes.
627
637
 
638
+ # it needs something there to trigger the NoReadme
639
+ junkFileCreated = False
640
+ junkFilePath = os.path.join(os.getcwd(),"_junk_")
641
+ if not os.path.exists(junkFilePath):
642
+ with open(junkFilePath,'x') as f:
643
+ pass
644
+ junkFileCreated = True
645
+
628
646
  # data_update NoReadme
629
647
  try:
630
648
  exceptionSeen = False
@@ -648,6 +666,10 @@ class casaconfig_test(unittest.TestCase):
648
666
  print("unexpected exception seen when testing for NoReadme in measures_update")
649
667
  print(str(exc))
650
668
  self.assertTrue(exceptionSeen, "NoReadme not seen from measures_update")
669
+
670
+ # clean up, remove junk
671
+ if junkFileCreated:
672
+ os.remove(junkFilePath)
651
673
 
652
674
  # NotWritable : path is not writable by the user
653
675
  # use the emptyPath
@@ -743,15 +765,13 @@ class casaconfig_test(unittest.TestCase):
743
765
  ref = True if "UnsetMeasurespath" in str(output) else False
744
766
  self.assertTrue(ref, "UnsetMeasurespath not seen in output for do_auto_updates and measurespath=None")
745
767
 
746
-
747
768
  def test_exceptions_with_data(self):
748
769
  '''test that exceptions that require data happen when expected'''
749
770
 
750
771
  # these tests requires an already installed set of data
751
772
  self.populate_testrundata()
752
-
773
+
753
774
  # BadLock
754
- print("\nTesting for BadLock in test_exceptions_with_data")
755
775
  # insert a non-empty lock file
756
776
  exceptionSeen = False
757
777
  lockPath = os.path.join(self.testRundataPath,'data_update.lock')
@@ -785,8 +805,6 @@ class casaconfig_test(unittest.TestCase):
785
805
  self.assertTrue(exceptionSeen, "BadLock not seen as expected in data_update with existing data test")
786
806
  # remove the lock file
787
807
  os.remove(lockPath)
788
- print("BadLock test passed in test_exceptions_with_data\n")
789
-
790
808
 
791
809
  # BadReadme
792
810
 
@@ -850,7 +868,6 @@ class casaconfig_test(unittest.TestCase):
850
868
  # this check happens before the age is determined, so no need to backdate the readme.txt file here
851
869
  casaconfig.measures_update(self.testRundataPath)
852
870
  except casaconfig.BadReadme as exc:
853
- print(str(exc))
854
871
  exceptionSeen = True
855
872
  except Exception as exc:
856
873
  print("unexpected exception seen when testing for BadRadme in measures_update")
@@ -864,12 +881,10 @@ class casaconfig_test(unittest.TestCase):
864
881
 
865
882
  # get the current permissions of the testRundataPath
866
883
  orig_pstat = stat.S_IMODE(os.stat(self.testRundataPath).st_mode)
867
- print('orig_pstat = %s' % orig_pstat)
868
884
  # a bitmask that's the opposite of all of the write permission bits
869
885
  no_write = ~stat.S_IWUSR & ~stat.S_IWGRP & ~stat.S_IWOTH
870
886
  # remove the write permissions
871
887
  pstat = orig_pstat & no_write
872
- print('pstat = %s' % pstat)
873
888
  os.chmod(self.testRundataPath,pstat)
874
889
 
875
890
 
@@ -883,16 +898,174 @@ class casaconfig_test(unittest.TestCase):
883
898
  except Exception as exc:
884
899
  print("unexpected exception seen when testing for NotWritable in measures_update")
885
900
  print(str(exc))
886
- import traceback
887
- traceback.print_exc()
888
901
 
889
902
  # reset to original permissions before anything else is checked
890
903
  os.chmod(self.testRundataPath,orig_pstat)
891
904
 
892
905
  self.assertTrue(exceptionSeen, "NotWritable not seen from measures_update")
893
906
 
907
+ def siteAge(self, ma_site):
908
+ # given a list returned by measures_available return the age of the last file in the list
909
+ dateMatch = re.search(r".*_Measures_(\d{4})(\d{2})(\d{2})-.*", ma_site[-1])
910
+ fileDate = date(int(dateMatch.group(1)), int(dateMatch.group(2)), int(dateMatch.group(3)))
911
+ dateDiff = date.today() - fileDate
912
+ return dateDiff.days
913
+
914
+ def test_measures_site(self):
915
+ '''tests related to measures site'''
916
+
917
+ from casaconfig import config
918
+
919
+ # measures_available should work for the default list and each element individually
920
+ ma = casaconfig.measures_available()
921
+ self.assertTrue(ma[0] in config.measures_site, "measures_available first element is not an element of config.measures_site")
922
+
923
+ # this test code assumes there are 2 sites, if that ever is not the case someone will need
924
+ # to make this more general
925
+ site_0 = config.measures_site[0]
926
+ site_1 = config.measures_site[1]
927
+
928
+ site_0_ma = casaconfig.measures_available(measures_site=site_0)
929
+ self.assertTrue(site_0_ma[0]==site_0)
930
+ site_age_0 = self.siteAge(site_0_ma)
931
+
932
+ site_1_ma = casaconfig.measures_available(measures_site=site_1)
933
+ self.assertTrue(site_1_ma[0]==site_1)
934
+ site_age_1 = self.siteAge(site_1_ma)
935
+
936
+ # reversing the list should get the currently second site, unless that site is too old
937
+ if site_age_1 <= config.measures_site_interval:
938
+ # site is not too old
939
+ config.measures_site.reverse()
940
+ ma = casaconfig.measures_available()
941
+ self.assertTrue(ma[0]==site_1, "reversing measures_site did not return the second site list as expected")
942
+ config.measures_site.reverse()
943
+ else:
944
+ print("test_measures_site, skipping test of reversing measures_site as %s appears to be out of date" % site_1)
945
+
946
+ # everything is out of date, finds the youngest or first site if they are both the same age
947
+ youngestSite = site_0 if site_age_0 <= site_age_1 else site_1
948
+ config.measures_site_interval = -1
949
+ ma = casaconfig.measures_available()
950
+ self.assertTrue(ma[0]==youngestSite,"list from youngest site not return with measures_site_interval = -1")
951
+
952
+ # reverse the list, if they are the same age the first one (now site_1) will be used
953
+ # otherwise it will still return whatever the youngestSite was above
954
+ config.measures_site.reverse()
955
+ if site_age_0 == site_age_1:
956
+ ma = casaconfig.measures_available()
957
+ self.assertTrue(ma[0]==site_1, "reversing measures_site with measures_site_interval = -1 did not return list from second site, sites have same age")
958
+ else:
959
+ ma = casaconfig.measures_available()
960
+ self.assertTrue(ma[0]==youngestSite, "reversing measures_site with measures_site_interval = -1 did not return list from youngest site, sites have same age")
961
+
962
+ # return to default values
963
+ config.measures_site = copy.deepcopy(config._config_defaults.measures_site)
964
+ config.measures_site_interval = config._config_defaults.measures_site_interval
965
+
966
+ # the rest of the tests use the test_measures area
967
+ self.populate_testmeasures()
968
+
969
+ # install an older version from each site
970
+ # check that without specifying the site it finds the site
971
+ # check that with specifying the correct site it finds the site
972
+ # check that when given the wrong site it doesn't find it
973
+
974
+ site_0_version = site_0_ma[-3]
975
+ site_1_version = site_1_ma[-4]
976
+
977
+ di = casaconfig.get_data_info(path=self.testMeasPath, type='measures')
978
+ print('di : %s' % str(di))
894
979
 
895
-
980
+ for site, vers, altSite in [(site_0, site_0_version, site_1), (site_1, site_1_version, site_0)]:
981
+ # let it find the site
982
+ casaconfig.measures_update(path=self.testMeasPath, version=vers, force=True)
983
+ di = casaconfig.get_data_info(path=self.testMeasPath, type='measures')
984
+ self.assertTrue(di['site']==site and di['version']==vers)
985
+
986
+ # give it the site
987
+ casaconfig.measures_update(path=self.testMeasPath,version=vers,measures_site=site, force=True)
988
+ di = casaconfig.get_data_info(path=self.testMeasPath, type='measures')
989
+ self.assertTrue(di['site']==site and di['version']==vers)
990
+
991
+ # this fails without throwing an exception, first, force an update to the most recent version at this site
992
+ casaconfig.measures_update(path=self.testMeasPath, measures_site=site, force=True)
993
+ di = casaconfig.get_data_info(path=self.testMeasPath, type='measures')
994
+ # it should not be the vers being checked here
995
+ self.assertTrue(di['version'] != vers, "unexpected version installed, this should not happen here")
996
+ installedVersion = di['version']
997
+ # trying to install this version from the wrong site will not change that version
998
+ casaconfig.measures_update(path=self.testMeasPath, version=vers, measures_site=altSite, force=True)
999
+ di = casaconfig.get_data_info(path=self.testMeasPath, type='measures')
1000
+ self.assertTrue(di['version'] != vers and di['version']==installedVersion, "measures_update unexpectedly installed a version that should not exist at the requested site")
1001
+
1002
+ # use a site that exists but has no valid measures files - casarundata
1003
+ # each of those should raise a RemoteError exception
1004
+ exceptionCaught = False
1005
+ casarundataURL = 'https://go.nrao.edu/casarundata'
1006
+ try:
1007
+ ma = casaconfig.measures_available(measures_site=[casarundataURL])
1008
+ except casaconfig.RemoteError as exc:
1009
+ exceptionCaught = True
1010
+ self.assertTrue(exceptionCaught, "measures_available on an exisitng site in list with no measures tar files did not raised the expected exception")
1011
+
1012
+ exceptionCaught = False
1013
+ try:
1014
+ ma = casaconfig.measures_available(measures_site=casarundataURL)
1015
+ except casaconfig.RemoteError as exc:
1016
+ exceptionCaught = True
1017
+ self.assertTrue(exceptionCaught, "measures_available on an exisitng site with no measures tar files did not raised the expected exception")
1018
+
1019
+ exceptionCaught = False
1020
+ try:
1021
+ ma = casaconfig.measures_update(path=self.testMeasPath, measures_site=casarundataURL, force=True)
1022
+ except casaconfig.RemoteError as exc:
1023
+ exceptionCaught = True
1024
+ self.assertTrue(exceptionCaught, "measures_update on an exisitng site with no[ measures tar files did not raised the expected exception")
1025
+
1026
+ # add this in at the head of a measures_site list that contains valid sites should silenently move on to a valid site
1027
+ siteList = [casarundataURL] + config.measures_site
1028
+ exceptionCaught = False
1029
+ try:
1030
+ ma = casaconfig.measures_available(measures_site=siteList)
1031
+ except casaconfig.RemoteError as exc:
1032
+ exceptionCaught = True
1033
+ self.assertFalse(exceptionCaught, "measures_available on a list with one empty site at head and non-empty sites unexpectedly raised an exception")
1034
+
1035
+ def test_update_interval(self):
1036
+ '''tests use of config update_interval values'''
1037
+
1038
+ from casaconfig import config
1039
+ self.populate_testrundata()
1040
+
1041
+ # data
1042
+ # populate with an older data
1043
+ da = casaconfig.data_available()
1044
+ casaconfig.data_update(self.testRundataPath,version=da[-2],force=True)
1045
+ # default data_update_interval will not allow an update at this point
1046
+ casaconfig.data_update(self.testRundataPath)
1047
+ di = casaconfig.get_data_info(self.testRundataPath, type='casarundata')
1048
+ self.assertTrue(di['version'] == da[-2],'data_update unexpectedly updated when data_update_interval should not have allowed it to update')
1049
+ # this means data_update always checks and updates if necessary
1050
+ config.data_update_interval = -1
1051
+ casaconfig.data_update(self.testRundataPath)
1052
+ di = casaconfig.get_data_info(self.testRundataPath, type='casarundata')
1053
+ self.assertFalse(di['version'] == da[-2],'data_update did not update casarundata version as expected with negative data_update_interval')
1054
+
1055
+ # measures
1056
+ # populate with an older data
1057
+ ma = casaconfig.measures_available()
1058
+ casaconfig.measures_update(self.testRundataPath,version=ma[-2],force=True)
1059
+ # default measures_update_interval will not allow an update at this point
1060
+ casaconfig.measures_update(self.testRundataPath)
1061
+ di = casaconfig.get_data_info(self.testRundataPath,type='measures')
1062
+ self.assertTrue(di['version'] == ma[-2],'measures_update unexpectedly updated when measures_update_interval should not have allowed it to update')
1063
+ # this means measures_update always checks and updates if necessary
1064
+ config.measures_update_interval = -1
1065
+ casaconfig.measures_update(self.testRundataPath)
1066
+ di = casaconfig.get_data_info(self.testRundataPath,type='measures')
1067
+ self.assertFalse(di['version'] == ma[-2],'measures_update did not update measures version as expected with negative measures_update_interval')
1068
+
896
1069
  if __name__ == '__main__':
897
1070
 
898
1071
  unittest.main()