restage 0.7.2__tar.gz → 0.8.1__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. {restage-0.7.2/src/restage.egg-info → restage-0.8.1}/PKG-INFO +18 -2
  2. {restage-0.7.2 → restage-0.8.1}/README.md +16 -0
  3. {restage-0.7.2 → restage-0.8.1}/pyproject.toml +1 -1
  4. {restage-0.7.2 → restage-0.8.1}/src/restage/instr.py +5 -3
  5. {restage-0.7.2 → restage-0.8.1}/src/restage/splitrun.py +93 -46
  6. {restage-0.7.2 → restage-0.8.1/src/restage.egg-info}/PKG-INFO +18 -2
  7. {restage-0.7.2 → restage-0.8.1}/src/restage.egg-info/requires.txt +1 -1
  8. {restage-0.7.2 → restage-0.8.1}/test/test_single.py +51 -23
  9. {restage-0.7.2 → restage-0.8.1}/.github/workflows/pip.yml +0 -0
  10. {restage-0.7.2 → restage-0.8.1}/.github/workflows/wheels.yml +0 -0
  11. {restage-0.7.2 → restage-0.8.1}/.gitignore +0 -0
  12. {restage-0.7.2 → restage-0.8.1}/setup.cfg +0 -0
  13. {restage-0.7.2 → restage-0.8.1}/src/restage/__init__.py +0 -0
  14. {restage-0.7.2 → restage-0.8.1}/src/restage/bifrost_choppers.py +0 -0
  15. {restage-0.7.2 → restage-0.8.1}/src/restage/cache.py +0 -0
  16. {restage-0.7.2 → restage-0.8.1}/src/restage/config/__init__.py +0 -0
  17. {restage-0.7.2 → restage-0.8.1}/src/restage/config/default.yaml +0 -0
  18. {restage-0.7.2 → restage-0.8.1}/src/restage/cspec_choppers.py +0 -0
  19. {restage-0.7.2 → restage-0.8.1}/src/restage/database.py +0 -0
  20. {restage-0.7.2 → restage-0.8.1}/src/restage/emulate.py +0 -0
  21. {restage-0.7.2 → restage-0.8.1}/src/restage/energy.py +0 -0
  22. {restage-0.7.2 → restage-0.8.1}/src/restage/mcpl.py +0 -0
  23. {restage-0.7.2 → restage-0.8.1}/src/restage/range.py +0 -0
  24. {restage-0.7.2 → restage-0.8.1}/src/restage/run.py +0 -0
  25. {restage-0.7.2 → restage-0.8.1}/src/restage/scan.py +0 -0
  26. {restage-0.7.2 → restage-0.8.1}/src/restage/tables.py +0 -0
  27. {restage-0.7.2 → restage-0.8.1}/src/restage.egg-info/SOURCES.txt +0 -0
  28. {restage-0.7.2 → restage-0.8.1}/src/restage.egg-info/dependency_links.txt +0 -0
  29. {restage-0.7.2 → restage-0.8.1}/src/restage.egg-info/entry_points.txt +0 -0
  30. {restage-0.7.2 → restage-0.8.1}/src/restage.egg-info/top_level.txt +0 -0
  31. {restage-0.7.2 → restage-0.8.1}/test/test_cache.py +0 -0
  32. {restage-0.7.2 → restage-0.8.1}/test/test_cache_ro.py +0 -0
  33. {restage-0.7.2 → restage-0.8.1}/test/test_database.py +0 -0
  34. {restage-0.7.2 → restage-0.8.1}/test/test_energy.py +0 -0
  35. {restage-0.7.2 → restage-0.8.1}/test/test_env_vars.py +0 -0
  36. {restage-0.7.2 → restage-0.8.1}/test/test_range.py +0 -0
  37. {restage-0.7.2 → restage-0.8.1}/test/test_scan.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: restage
3
- Version: 0.7.2
3
+ Version: 0.8.1
4
4
  Author-email: Gregory Tucker <gregory.tucker@ess.eu>
5
5
  License: BSD-3-Clause
6
6
  Classifier: License :: OSI Approved :: BSD License
@@ -17,7 +17,7 @@ Requires-Dist: zenlog>=1.1
17
17
  Requires-Dist: platformdirs>=3.11
18
18
  Requires-Dist: confuse
19
19
  Requires-Dist: psutil>=5.9.6
20
- Requires-Dist: mccode-antlr[hdf5]>=0.14.0
20
+ Requires-Dist: mccode-antlr[hdf5]>=0.15.0
21
21
  Provides-Extra: test
22
22
  Requires-Dist: pytest; extra == "test"
23
23
  Requires-Dist: chopcal; extra == "test"
@@ -107,6 +107,22 @@ splitrun my_instrument.instr -n 1000000 --split-at split_at -d /data/output samp
107
107
  ```
108
108
 
109
109
 
110
+ ## MCPL components
111
+ There are a small collection of `MCPL` input and output components that are provided
112
+ along with the McStas and McXtrace distributions, and you may also decide to write your
113
+ own specialized variant of those provided.
114
+ By default `splitrun` will insert an `MCPL_output` component at the end of the first
115
+ stage, and an `MCPL_input` component at the start of the second stage.
116
+ Should you prefer to a different component, or need to provide parameter values for
117
+ the components, these can be specified in the command line call to `splitrun`.
118
+
119
+ Components are specified as their file name (minus the `.comp` extension) and
120
+ parameters as comma-separated `key:value` pairs, e.g.:
121
+
122
+ ```bash
123
+ splitrun -n 1M a3=0:179 --mcpl-input-component MCPL_input_once --mcpl-output-parameters weight_mode:1,double_prec:1 instr.h5
124
+ ```
125
+
110
126
 
111
127
  ## Cached data
112
128
  ### Default writable cache
@@ -83,6 +83,22 @@ splitrun my_instrument.instr -n 1000000 --split-at split_at -d /data/output samp
83
83
  ```
84
84
 
85
85
 
86
+ ## MCPL components
87
+ There are a small collection of `MCPL` input and output components that are provided
88
+ along with the McStas and McXtrace distributions, and you may also decide to write your
89
+ own specialized variant of those provided.
90
+ By default `splitrun` will insert an `MCPL_output` component at the end of the first
91
+ stage, and an `MCPL_input` component at the start of the second stage.
92
+ Should you prefer to a different component, or need to provide parameter values for
93
+ the components, these can be specified in the command line call to `splitrun`.
94
+
95
+ Components are specified as their file name (minus the `.comp` extension) and
96
+ parameters as comma-separated `key:value` pairs, e.g.:
97
+
98
+ ```bash
99
+ splitrun -n 1M a3=0:179 --mcpl-input-component MCPL_input_once --mcpl-output-parameters weight_mode:1,double_prec:1 instr.h5
100
+ ```
101
+
86
102
 
87
103
  ## Cached data
88
104
  ### Default writable cache
@@ -9,7 +9,7 @@ dependencies = [
9
9
  'platformdirs>=3.11',
10
10
  'confuse',
11
11
  'psutil>=5.9.6',
12
- 'mccode-antlr[hdf5]>=0.14.0',
12
+ 'mccode-antlr[hdf5]>=0.15.0',
13
13
  ]
14
14
  readme = "README.md"
15
15
  license = {text = "BSD-3-Clause"}
@@ -10,17 +10,19 @@ from mccode_antlr.instr import Instr
10
10
 
11
11
  def load_instr(filepath: Union[str, Path]) -> Instr:
12
12
  """Loads an Instr object from a .instr file or a HDF5 file"""
13
- from mccode_antlr.io import load_hdf5
14
- from mccode_antlr.loader import load_mcstas_instr
15
-
16
13
  if not isinstance(filepath, Path):
17
14
  filepath = Path(filepath)
18
15
  if not filepath.exists() or not filepath.is_file():
19
16
  raise ValueError(f'The provided {filepath=} does not exist or is not a file')
20
17
 
21
18
  if filepath.suffix == '.instr':
19
+ from mccode_antlr.loader import load_mcstas_instr
22
20
  return load_mcstas_instr(filepath)
21
+ elif filepath.suffix.lower() == '.json':
22
+ from mccode_antlr.io.json import load_json
23
+ return load_json(filepath)
23
24
 
25
+ from mccode_antlr.io import load_hdf5
24
26
  return load_hdf5(filepath)
25
27
 
26
28
 
@@ -1,51 +1,93 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from pathlib import Path
4
+ from typing import Optional
5
+
4
6
  from .tables import SimulationEntry, InstrEntry
5
7
 
6
- def mcpl_parameter_split(s: str) -> tuple[str, str]:
7
- k, v = s.split(':', 1)
8
- return k, v
8
+ def mcpl_parameters_split(s: str) -> list[tuple[str, str]]:
9
+ return [(k, v) for k, v in [kv.split(':', maxsplit=1) for kv in s.split(',')]]
10
+
11
+ def si_int(s: str) -> int:
12
+ from loguru import logger
13
+ suffix_value = {
14
+ 'k': 1000, 'M': 10 ** 6, 'G': 10 ** 9, 'T': 10 ** 12, 'P': 10 ** 15,
15
+ 'Ki': 2 ** 10, 'Mi': 2 ** 20, 'Gi': 2 ** 30, 'Ti': 2 ** 40, 'Pi': 2 ** 50
16
+ }
17
+ def int_mult(x: str, mult: int = 1):
18
+ if len(x) == 0 and mult > 1:
19
+ return mult
20
+ return int(x) * mult if x.isnumeric() else int(float(x) * mult)
21
+
22
+ def do_parse():
23
+ try:
24
+ if suffix := next(k for k in suffix_value if s.endswith(k)):
25
+ return int_mult(s[:-len(suffix)].strip(), suffix_value[suffix])
26
+ except StopIteration:
27
+ pass
28
+ return int_mult(s)
29
+ value = do_parse()
30
+ if value < 0:
31
+ raise ValueError(f'Negative {value=} encountered')
32
+ elif value > 2**53:
33
+ logger.info(
34
+ 'McStas/McXtrace parse integer inputs as doubles,'
35
+ f' this requested {value=} will not be evaluated precisely'
36
+ ' since it is more than 2^53'
37
+ )
38
+ return value
39
+
40
+ def si_int_limits(s: str) -> tuple[Optional[int], int, Optional[int]]:
41
+ low, high = None, None
42
+ min_seps, max_seps = (']', '-', '}'), ('[', '+', '{')
43
+ if any(x in s for x in min_seps):
44
+ low, s = s.split(next(x for x in min_seps if x in s), maxsplit=1)
45
+ low = si_int(low)
46
+ if any(x in s for x in max_seps):
47
+ s, high = s.split(next(x for x in max_seps if x in s), maxsplit=1)
48
+ high = si_int(high)
49
+ return low, si_int(s), high
9
50
 
10
51
  def make_splitrun_parser():
11
52
  from argparse import ArgumentParser
12
53
  parser = ArgumentParser('splitrun')
13
54
  aa = parser.add_argument
14
- parser = ArgumentParser('splitrun')
15
- aa = parser.add_argument
16
- aa('instrument', nargs=1, type=str, default=None,
17
- help='Instrument `.instr` file name or serialised HDF5 Instr object')
55
+ aa('instrument', type=str, default=None,
56
+ help='Instrument `.instr` file name or serialised HDF5 or JSON Instr object')
18
57
  aa('parameters', nargs='*', type=str, default=None)
19
- aa('-n', '--ncount', nargs=1, type=int, default=None, help='Number of neutrons to simulate')
58
+ aa('-n', '--ncount', type=si_int_limits, default=None, metavar='[MIN-]COUNT[+MAX]',
59
+ help='COUNT {number}[kMGTP] target, MIN MAX replace missing --nmin --nmax')
20
60
  aa('-m', '--mesh', action='store_true', default=False, help='N-dimensional mesh scan')
21
- aa('-d', '--dir', nargs=1, type=str, default=None, help='Output directory')
22
- aa('-s', '--seed', nargs=1, type=int, default=None, help='Random number generator seed')
61
+ aa('-d', '--dir', type=str, default=None, help='Output directory')
62
+ aa('-s', '--seed', type=int, default=None, help='Random number generator seed')
23
63
  aa('-t', '--trace', action='store_true', default=False, help='Enable tracing')
24
64
  aa('-g', '--gravitation', action='store_true', default=False,
25
65
  help='Enable gravitation for all trajectories')
26
- aa('--bufsiz', nargs=1, type=int, default=None, help='Monitor_nD list/buffer-size')
27
- aa('--format', nargs=1, type=str, default=None, help='Output data files using FORMAT')
28
- aa('--nmin', nargs=1, type=int, default=None,
29
- help='Minimum number of particles to simulate during first instrument simulations')
30
- aa('--nmax', nargs=1, type=int, default=None,
31
- help='Maximum number of particles to simulate during first instrument simulations')
66
+ aa('--bufsiz', type=si_int, default=None, help='Monitor_nD list/buffer-size')
67
+ aa('--format', type=str, default=None, help='Output data files using FORMAT')
68
+ aa('--nmin', type=si_int, default=None, metavar='MIN',
69
+ help='MIN {number}[kMGTP] rays per first-instrument simulation')
70
+ aa('--nmax', type=si_int, default=None, metavar='MAX',
71
+ help='MAX {number}[kMGTP] rays per first-instrument simulation')
32
72
  aa('--dryrun', action='store_true', default=False,
33
73
  help='Do not run any simulations, just print the commands')
34
74
  aa('--parallel', action='store_true', default=False,
35
- help='Use MPI multi-process parallelism (primary instrument only at the moment)')
75
+ help='Use MPI multi-process parallelism')
36
76
  aa('--gpu', action='store_true', default=False,
37
- help='Use GPU OpenACC parallelism (primary instrument only at the moment)')
38
- aa('--process-count', nargs=1, type=int, default=0,
77
+ help='Use GPU OpenACC parallelism')
78
+ aa('--process-count', type=int, default=0,
39
79
  help='MPI process count, 0 == System Default')
40
80
  # splitrun controlling parameters
41
- aa('--split-at', nargs=1, type=str, default=['mcpl_split'],
81
+ aa('--split-at', type=str, default='mcpl_split',
42
82
  help='Component at which to split -- DEFAULT: mcpl_split')
43
- aa('--mcpl-output-component', nargs=1, type=str, default=None,
44
- help='Inserted MCPL file producing component, MCPL_output(.comp) if not provided')
45
- aa('--mcpl-input-component', nargs=1, type=str, default=None,
46
- help='Inserted MCPL file consuming component, MCPL_input(.comp) if not provided')
47
- aa('--mcpl-input-parameters', nargs='+', type=mcpl_parameter_split, metavar='key:value')
48
- aa('--mcpl-output-parameters', nargs='+', type=mcpl_parameter_split, metavar='key:value')
83
+ aa('--mcpl-output-component', type=str, default=None,
84
+ help='Inserted MCPL file producing component, "MCPL_output" if not provided')
85
+ aa('--mcpl-input-component', type=str, default=None,
86
+ help='Inserted MCPL file consuming component, "MCPL_input" if not provided')
87
+ aa('--mcpl-input-parameters', type=mcpl_parameters_split,
88
+ metavar='in_parameter1:value1,in_parameter2:value2,...')
89
+ aa('--mcpl-output-parameters',type=mcpl_parameters_split,
90
+ metavar='out_parameter1:value1,out_parameter2:value2,...')
49
91
  aa('-P', action='append', default=[], help='Cache parameter matching precision')
50
92
 
51
93
  # Other McCode runtime arguments exist, but are likely not used during a scan:
@@ -105,6 +147,19 @@ def parse_splitrun(parser):
105
147
  args.mcpl_input_parameters = dict(args.mcpl_input_parameters)
106
148
  if args.mcpl_output_parameters is not None:
107
149
  args.mcpl_output_parameters = dict(args.mcpl_output_parameters)
150
+
151
+ if args.ncount is not None:
152
+ nmin, ncount, nmax = args.ncount
153
+ if args.nmin and nmin and args.nmin != nmin:
154
+ raise ValueError(f'Invalid repeated nmin specification: {nmin} != {args.nmin}')
155
+ if args.nmax and nmax and args.nmax != nmax:
156
+ raise ValueError(f'Invalid repeated nmax specification: {nmax} != {args.nmax}')
157
+ if nmin and not args.nmin:
158
+ args.nmin = nmin
159
+ if nmax and not args.nmax:
160
+ args.nmax = nmax
161
+ args.ncount = ncount
162
+
108
163
  parameters = parse_scan_parameters(args.parameters)
109
164
  precision = parse_splitrun_precision(args.P)
110
165
  return args, parameters, precision
@@ -117,36 +172,28 @@ def entrypoint():
117
172
 
118
173
  def splitrun_from_file(args, parameters, precision):
119
174
  from .instr import load_instr
120
- instr = load_instr(args.instrument[0])
175
+ instr = load_instr(args.instrument)
121
176
  splitrun_args(instr, parameters, precision, args)
122
177
 
123
178
 
124
- def give_me_an_integer(something):
125
- if isinstance(something, (list, tuple)):
126
- return something[0]
127
- if isinstance(something, int):
128
- return something
129
- return 0
130
-
131
-
132
179
  def splitrun_args(instr, parameters, precision, args, **kwargs):
133
- splitrun(instr, parameters, precision, split_at=args.split_at[0], grid=args.mesh,
134
- seed=args.seed[0] if args.seed is not None else None,
135
- ncount=args.ncount[0] if args.ncount is not None else None,
136
- out_dir=args.dir[0] if args.dir is not None else None,
180
+ splitrun(instr, parameters, precision, split_at=args.split_at, grid=args.mesh,
181
+ seed=args.seed,
182
+ ncount=args.ncount,
183
+ out_dir=args.dir,
137
184
  trace=args.trace,
138
185
  gravitation=args.gravitation,
139
- bufsiz=args.bufsiz[0] if args.bufsiz is not None else None,
140
- format=args.format[0] if args.format is not None else None,
141
- minimum_particle_count=args.nmin[0] if args.nmin is not None else None,
142
- maximum_particle_count=args.nmax[0] if args.nmax is not None else None,
186
+ bufsiz=args.bufsiz,
187
+ format=args.format,
188
+ minimum_particle_count=args.nmin,
189
+ maximum_particle_count=args.nmax,
143
190
  dry_run=args.dryrun,
144
191
  parallel=args.parallel,
145
192
  gpu=args.gpu,
146
- process_count=give_me_an_integer(args.process_count),
147
- mcpl_output_component=args.mcpl_output_component[0] if args.mcpl_output_component is not None else None,
193
+ process_count=args.process_count,
194
+ mcpl_output_component=args.mcpl_output_component,
148
195
  mcpl_output_parameters=args.mcpl_output_parameters,
149
- mcpl_input_component=args.mcpl_input_component[0] if args.mcpl_input_component is not None else None,
196
+ mcpl_input_component=args.mcpl_input_component,
150
197
  mcpl_input_parameters=args.mcpl_input_parameters,
151
198
  **kwargs
152
199
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: restage
3
- Version: 0.7.2
3
+ Version: 0.8.1
4
4
  Author-email: Gregory Tucker <gregory.tucker@ess.eu>
5
5
  License: BSD-3-Clause
6
6
  Classifier: License :: OSI Approved :: BSD License
@@ -17,7 +17,7 @@ Requires-Dist: zenlog>=1.1
17
17
  Requires-Dist: platformdirs>=3.11
18
18
  Requires-Dist: confuse
19
19
  Requires-Dist: psutil>=5.9.6
20
- Requires-Dist: mccode-antlr[hdf5]>=0.14.0
20
+ Requires-Dist: mccode-antlr[hdf5]>=0.15.0
21
21
  Provides-Extra: test
22
22
  Requires-Dist: pytest; extra == "test"
23
23
  Requires-Dist: chopcal; extra == "test"
@@ -107,6 +107,22 @@ splitrun my_instrument.instr -n 1000000 --split-at split_at -d /data/output samp
107
107
  ```
108
108
 
109
109
 
110
+ ## MCPL components
111
+ There are a small collection of `MCPL` input and output components that are provided
112
+ along with the McStas and McXtrace distributions, and you may also decide to write your
113
+ own specialized variant of those provided.
114
+ By default `splitrun` will insert an `MCPL_output` component at the end of the first
115
+ stage, and an `MCPL_input` component at the start of the second stage.
116
+ Should you prefer to a different component, or need to provide parameter values for
117
+ the components, these can be specified in the command line call to `splitrun`.
118
+
119
+ Components are specified as their file name (minus the `.comp` extension) and
120
+ parameters as comma-separated `key:value` pairs, e.g.:
121
+
122
+ ```bash
123
+ splitrun -n 1M a3=0:179 --mcpl-input-component MCPL_input_once --mcpl-output-parameters weight_mode:1,double_prec:1 instr.h5
124
+ ```
125
+
110
126
 
111
127
  ## Cached data
112
128
  ### Default writable cache
@@ -2,7 +2,7 @@ zenlog>=1.1
2
2
  platformdirs>=3.11
3
3
  confuse
4
4
  psutil>=5.9.6
5
- mccode-antlr[hdf5]>=0.14.0
5
+ mccode-antlr[hdf5]>=0.15.0
6
6
 
7
7
  [test]
8
8
  pytest
@@ -32,53 +32,81 @@ class SingleTestCase(unittest.TestCase):
32
32
 
33
33
  def test_parsing(self):
34
34
  args = self.parser.parse_args(['test.instr', 'a=1', 'b=2', '--split-at=here', '-m'])
35
- self.assertEqual(args.instrument, ['test.instr'])
35
+ self.assertEqual(args.instrument, 'test.instr')
36
36
  self.assertEqual(args.parameters, ['a=1', 'b=2'])
37
- self.assertEqual(args.split_at, ['here'])
37
+ self.assertEqual(args.split_at, 'here')
38
38
  self.assertTrue(args.mesh)
39
39
 
40
40
  def test_mixed_parsing(self):
41
41
  from mccode_antlr.run.runner import sort_args
42
42
  args = self.parser.parse_args(sort_args(['test.instr', '-m', 'a=1', 'b=2', '--split-at=here']))
43
- self.assertEqual(args.instrument, ['test.instr'])
43
+ self.assertEqual(args.instrument, 'test.instr')
44
44
  self.assertEqual(args.parameters, ['a=1', 'b=2'])
45
- self.assertEqual(args.split_at, ['here'])
45
+ self.assertEqual(args.split_at, 'here')
46
46
  self.assertTrue(args.mesh)
47
47
 
48
+ def test_negative_count_throws(self):
49
+ from restage.splitrun import si_int, si_int_limits
50
+ with self.assertRaises(ValueError):
51
+ si_int('-10')
52
+ with self.assertRaises(ValueError):
53
+ si_int_limits('10--4+10') # '10--4+10' -> ('10', '-4+10') -> (10, '-4', '10')
54
+ with self.assertRaises(ValueError):
55
+ # This is probably a parsing error, but would raise a negative error
56
+ # in si_int, so is fine. '-10]-2[-1' -> ('','10]-2[-1') -> Error on int('')
57
+ si_int_limits('-10]-2[-1')
58
+
48
59
  def test_mccode_flags(self):
49
- args = self.parser.parse_args(['test.instr', '-s', '123456', '-n', '-1', '-d', '/a/dir', '-t', '-g'])
50
- self.assertEqual(args.seed, [123456])
51
- self.assertEqual(args.ncount, [-1])
52
- self.assertEqual(args.dir, ['/a/dir'])
60
+ args = self.parser.parse_args(['test.instr', '-s', '123456', '-n', '1', '-d', '/a/dir', '-t', '-g'])
61
+ self.assertEqual(args.seed, 123456)
62
+ self.assertEqual(args.ncount, (None, 1, None))
63
+ self.assertEqual(args.dir, '/a/dir')
53
64
  self.assertEqual(args.trace, True)
54
65
  self.assertEqual(args.gravitation, True)
55
66
 
56
67
  args = self.parser.parse_args(['test.instr', '-s=99999', '-n=10000', '-d=/b/dir'])
57
- self.assertEqual(args.seed, [99999])
58
- self.assertEqual(args.ncount, [10000])
59
- self.assertEqual(args.dir, ['/b/dir'])
68
+ self.assertEqual(args.seed, 99999)
69
+ self.assertEqual(args.ncount, (None, 10000, None))
70
+ self.assertEqual(args.dir, '/b/dir')
60
71
  self.assertEqual(args.trace, False)
61
72
  self.assertEqual(args.gravitation, False)
62
73
 
63
74
  args = self.parser.parse_args(['test.instr', '--seed', '888', '--ncount', '4', '--dir', '/c/dir', '--trace',
64
75
  '--gravitation', '--bufsiz', '1000', '--format', 'NEXUS'])
65
- self.assertEqual(args.seed, [888])
66
- self.assertEqual(args.ncount, [4])
67
- self.assertEqual(args.dir, ['/c/dir'])
76
+ self.assertEqual(args.seed, 888)
77
+ self.assertEqual(args.ncount, (None, 4, None))
78
+ self.assertEqual(args.dir, '/c/dir')
68
79
  self.assertEqual(args.trace, True)
69
80
  self.assertEqual(args.gravitation, True)
70
- self.assertEqual(args.bufsiz, [1000])
71
- self.assertEqual(args.format, ['NEXUS'])
81
+ self.assertEqual(args.bufsiz, 1000)
82
+ self.assertEqual(args.format, 'NEXUS')
72
83
 
73
84
  args = self.parser.parse_args(['test.instr', '--seed=777', '--ncount=5', '--dir=/d/dir', '--bufsiz=2000',
74
85
  '--format=RAW'])
75
- self.assertEqual(args.seed, [777])
76
- self.assertEqual(args.ncount, [5])
77
- self.assertEqual(args.dir, ['/d/dir'])
86
+ self.assertEqual(args.seed, 777)
87
+ self.assertEqual(args.ncount, (None, 5, None))
88
+ self.assertEqual(args.dir, '/d/dir')
78
89
  self.assertEqual(args.trace, False)
79
90
  self.assertEqual(args.gravitation, False)
80
- self.assertEqual(args.bufsiz, [2000])
81
- self.assertEqual(args.format, ['RAW'])
91
+ self.assertEqual(args.bufsiz, 2000)
92
+ self.assertEqual(args.format, 'RAW')
93
+
94
+ def test_ncount_varieties(self):
95
+ args = self.parser.parse_args(['test.instr', '--ncount=5'])
96
+ self.assertEqual(args.ncount, (None, 5, None))
97
+ args = self.parser.parse_args(['test.instr', '-n' ,'4k'])
98
+ self.assertEqual(args.ncount, (None, 4000, None))
99
+ args = self.parser.parse_args(['test.instr', '-n', '3-2+1'])
100
+ self.assertEqual(args.ncount, (3, 2, 1))
101
+ args = self.parser.parse_args(['test.instr', '-n', '1M]1G[1T'])
102
+ self.assertEqual(args.ncount, (10**6, 10**9, 10**12))
103
+ args = self.parser.parse_args(['test.instr', '-n', '1Ki}Mi{2Gi'])
104
+ self.assertEqual(args.ncount, (2**10, 2**20, 2**31))
105
+ args = self.parser.parse_args(['t.instr', '-n', '1.1M', '--nmin', 'M', '--nmax', '2M'])
106
+ self.assertEqual(args.ncount, (None, 1100000, None))
107
+ self.assertEqual(args.nmin, 1000000)
108
+ self.assertEqual(args.nmax, 2000000)
109
+
82
110
 
83
111
  def test_parameters(self):
84
112
  from restage.range import MRange, Singular, parameters_to_scan, parse_scan_parameters
@@ -106,14 +134,14 @@ class SingleTestCase(unittest.TestCase):
106
134
 
107
135
  def test_mcpl_split_parameters(self):
108
136
  args = self.parser.parse_args(['test.instr', 'a=1.0', 'b=2', 'c=3:5', 'd=blah', 'e=/data',
109
- '--mcpl-input-parameters', 'preload:1', 'v_smear:0.01'])
137
+ '--mcpl-input-parameters', 'preload:1,v_smear:0.01'])
110
138
  self.assertEqual(args.parameters, ['a=1.0', 'b=2', 'c=3:5', 'd=blah', 'e=/data'])
111
139
  self.assertEqual(args.mcpl_input_parameters, [('preload', '1'), ('v_smear', '0.01')])
112
140
  args = self.parser.parse_args(['new_tst.instr', '--mcpl-output-parameters', 'preload:1',
113
141
  '--mcpl-input-component=MCPL_input_once'])
114
142
  self.assertEqual(args.parameters, [])
115
143
  self.assertEqual(args.mcpl_output_parameters, [('preload', '1')])
116
- self.assertEqual(args.mcpl_input_component, ['MCPL_input_once'])
144
+ self.assertEqual(args.mcpl_input_component, 'MCPL_input_once')
117
145
 
118
146
 
119
147
  class DictWranglingTestCase(unittest.TestCase):
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes