envstack 0.8.2__tar.gz → 0.8.3__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.
- {envstack-0.8.2/lib/envstack.egg-info → envstack-0.8.3}/PKG-INFO +14 -1
- {envstack-0.8.2 → envstack-0.8.3}/README.md +13 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack/__init__.py +1 -1
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack/util.py +20 -31
- {envstack-0.8.2 → envstack-0.8.3/lib/envstack.egg-info}/PKG-INFO +14 -1
- {envstack-0.8.2 → envstack-0.8.3}/setup.py +1 -1
- {envstack-0.8.2 → envstack-0.8.3}/tests/test_cmds.py +1 -5
- {envstack-0.8.2 → envstack-0.8.3}/tests/test_env.py +109 -19
- {envstack-0.8.2 → envstack-0.8.3}/tests/test_util.py +71 -8
- {envstack-0.8.2 → envstack-0.8.3}/LICENSE +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/dist.json +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack/cli.py +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack/config.py +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack/encrypt.py +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack/env.py +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack/exceptions.py +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack/logger.py +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack/node.py +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack/path.py +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack/wrapper.py +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack.egg-info/SOURCES.txt +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack.egg-info/dependency_links.txt +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack.egg-info/entry_points.txt +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack.egg-info/not-zip-safe +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack.egg-info/requires.txt +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/lib/envstack.egg-info/top_level.txt +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/setup.cfg +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/tests/test_encrypt.py +0 -0
- {envstack-0.8.2 → envstack-0.8.3}/tests/test_node.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: envstack
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.3
|
|
4
4
|
Summary: Stacked environment variable management system
|
|
5
5
|
Home-page: http://github.com/rsgalloway/envstack
|
|
6
6
|
Author: Ryan Galloway
|
|
@@ -277,6 +277,19 @@ BIZ=foo
|
|
|
277
277
|
FOO=foo
|
|
278
278
|
```
|
|
279
279
|
|
|
280
|
+
Here is an example using nested variable expansion:
|
|
281
|
+
|
|
282
|
+
```yaml
|
|
283
|
+
FOO: ${BIZ:=${BAR:=${BAZ:=baz}}}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Resolves to:
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
$ envstack -r
|
|
290
|
+
FOO=baz
|
|
291
|
+
```
|
|
292
|
+
|
|
280
293
|
#### Includes
|
|
281
294
|
|
|
282
295
|
Environment stack files can include other namespaced environments (you should
|
|
@@ -253,6 +253,19 @@ BIZ=foo
|
|
|
253
253
|
FOO=foo
|
|
254
254
|
```
|
|
255
255
|
|
|
256
|
+
Here is an example using nested variable expansion:
|
|
257
|
+
|
|
258
|
+
```yaml
|
|
259
|
+
FOO: ${BIZ:=${BAR:=${BAZ:=baz}}}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Resolves to:
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
$ envstack -r
|
|
266
|
+
FOO=baz
|
|
267
|
+
```
|
|
268
|
+
|
|
256
269
|
#### Includes
|
|
257
270
|
|
|
258
271
|
Environment stack files can include other namespaced environments (you should
|
|
@@ -49,14 +49,14 @@ from envstack.node import AESGCMNode, Base64Node, EncryptedNode, FernetNode
|
|
|
49
49
|
# value for unresolvable variables
|
|
50
50
|
null = ""
|
|
51
51
|
|
|
52
|
+
# regular expression pattern for matching windows drive letters
|
|
53
|
+
drive_letter_pattern = re.compile(r"(?P<sep>[:;])?(?P<drive>[A-Z]:[/\\])")
|
|
54
|
+
|
|
52
55
|
# regular expression pattern for bash-like variable expansion
|
|
53
56
|
variable_pattern = re.compile(
|
|
54
|
-
r"\$\{([a-zA-Z_][a-zA-Z0-9_]*)(?::([=?])(
|
|
57
|
+
r"\$\{([a-zA-Z_][a-zA-Z0-9_]*)(?::([=?])((?:\$\{[^}]+\}|[^}])*))?\}"
|
|
55
58
|
)
|
|
56
59
|
|
|
57
|
-
# regular expression pattern for matching windows drive letters
|
|
58
|
-
drive_letter_pattern = re.compile(r"(?P<sep>[:;])?(?P<drive>[A-Z]:[/\\])")
|
|
59
|
-
|
|
60
60
|
|
|
61
61
|
def clear_sys_path(var: str = "PYTHONPATH"):
|
|
62
62
|
"""
|
|
@@ -72,9 +72,9 @@ def clear_sys_path(var: str = "PYTHONPATH"):
|
|
|
72
72
|
def decode_value(value: str):
|
|
73
73
|
"""Returns a decoded value that's been encoded by a wrapper.
|
|
74
74
|
|
|
75
|
-
Decoding encoded environments can be tricky. For example, it must account
|
|
76
|
-
templates that include curly braces, e.g. path templates string
|
|
77
|
-
preserved:
|
|
75
|
+
Decoding encoded environments can be tricky. For example, it must account
|
|
76
|
+
for path templates that include curly braces, e.g. path templates string
|
|
77
|
+
like this must be preserved:
|
|
78
78
|
|
|
79
79
|
'/path/with/{variable}'
|
|
80
80
|
|
|
@@ -270,6 +270,16 @@ def evaluate_modifiers(expression: str, environ: dict = os.environ):
|
|
|
270
270
|
error message.
|
|
271
271
|
"""
|
|
272
272
|
|
|
273
|
+
def sanitize_value(value):
|
|
274
|
+
"""Sanitize the value before returning it."""
|
|
275
|
+
# HACK: remove trailing curly braces if they exist
|
|
276
|
+
if type(value) is str and value.endswith("}") and not value.startswith("${"):
|
|
277
|
+
return value.rstrip("}")
|
|
278
|
+
# sanitize path-like values
|
|
279
|
+
elif type(value) is str and ":" in value and ("/" in value or "\\" in value):
|
|
280
|
+
return dedupe_paths(value)
|
|
281
|
+
return value
|
|
282
|
+
|
|
273
283
|
def substitute_variable(match):
|
|
274
284
|
"""Substitute a variable match with its value."""
|
|
275
285
|
var_name = match.group(1)
|
|
@@ -311,19 +321,10 @@ def evaluate_modifiers(expression: str, environ: dict = os.environ):
|
|
|
311
321
|
# substitute all matches in the expression
|
|
312
322
|
result = variable_pattern.sub(substitute_variable, expression)
|
|
313
323
|
|
|
314
|
-
# HACK: remove trailing curly braces if they exist
|
|
315
|
-
if result.endswith("}") and not result.startswith("${"):
|
|
316
|
-
result = result.rstrip("}")
|
|
317
|
-
|
|
318
324
|
# evaluate any remaining modifiers, eg. ${VAR:=${FOO:=bar}}
|
|
319
325
|
if variable_pattern.search(result):
|
|
320
326
|
result = evaluate_modifiers(result, environ)
|
|
321
327
|
|
|
322
|
-
# dedupe path-like values and resolve separators
|
|
323
|
-
# TODO: replace with regex pattern to detect path-like strings
|
|
324
|
-
elif ":" in result and ("/" in result or "\\" in result):
|
|
325
|
-
result = dedupe_paths(result)
|
|
326
|
-
|
|
327
328
|
# detect recursion errors
|
|
328
329
|
except RecursionError:
|
|
329
330
|
raise CyclicalReference(f"Cyclical reference detected in {expression}")
|
|
@@ -340,27 +341,15 @@ def evaluate_modifiers(expression: str, environ: dict = os.environ):
|
|
|
340
341
|
elif isinstance(expression, FernetNode):
|
|
341
342
|
result = expression.resolve(env=environ)
|
|
342
343
|
elif isinstance(expression, list):
|
|
343
|
-
result = [
|
|
344
|
-
(
|
|
345
|
-
variable_pattern.sub(substitute_variable, str(v))
|
|
346
|
-
if isinstance(v, str)
|
|
347
|
-
else v
|
|
348
|
-
)
|
|
349
|
-
for v in expression
|
|
350
|
-
]
|
|
344
|
+
result = [(evaluate_modifiers(v, environ)) for v in expression]
|
|
351
345
|
elif isinstance(expression, dict):
|
|
352
346
|
result = {
|
|
353
|
-
k: (
|
|
354
|
-
variable_pattern.sub(substitute_variable, str(v))
|
|
355
|
-
if isinstance(v, str)
|
|
356
|
-
else v
|
|
357
|
-
)
|
|
358
|
-
for k, v in expression.items()
|
|
347
|
+
k: (evaluate_modifiers(v, environ)) for k, v in expression.items()
|
|
359
348
|
}
|
|
360
349
|
else:
|
|
361
350
|
result = expression
|
|
362
351
|
|
|
363
|
-
return result
|
|
352
|
+
return sanitize_value(result)
|
|
364
353
|
|
|
365
354
|
|
|
366
355
|
def load_sys_path(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: envstack
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.3
|
|
4
4
|
Summary: Stacked environment variable management system
|
|
5
5
|
Home-page: http://github.com/rsgalloway/envstack
|
|
6
6
|
Author: Ryan Galloway
|
|
@@ -277,6 +277,19 @@ BIZ=foo
|
|
|
277
277
|
FOO=foo
|
|
278
278
|
```
|
|
279
279
|
|
|
280
|
+
Here is an example using nested variable expansion:
|
|
281
|
+
|
|
282
|
+
```yaml
|
|
283
|
+
FOO: ${BIZ:=${BAR:=${BAZ:=baz}}}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Resolves to:
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
$ envstack -r
|
|
290
|
+
FOO=baz
|
|
291
|
+
```
|
|
292
|
+
|
|
280
293
|
#### Includes
|
|
281
294
|
|
|
282
295
|
Environment stack files can include other namespaced environments (you should
|
|
@@ -40,7 +40,7 @@ with open(os.path.join(here, "README.md")) as f:
|
|
|
40
40
|
|
|
41
41
|
setup(
|
|
42
42
|
name="envstack",
|
|
43
|
-
version="0.8.
|
|
43
|
+
version="0.8.3",
|
|
44
44
|
description="Stacked environment variable management system",
|
|
45
45
|
long_description=long_description,
|
|
46
46
|
long_description_content_type="text/markdown",
|
|
@@ -799,8 +799,4 @@ class TestIssues(unittest.TestCase):
|
|
|
799
799
|
|
|
800
800
|
|
|
801
801
|
if __name__ == "__main__":
|
|
802
|
-
|
|
803
|
-
if sys.platform == "linux":
|
|
804
|
-
unittest.main()
|
|
805
|
-
else:
|
|
806
|
-
print(f"platform not supported: {sys.platform}")
|
|
802
|
+
unittest.main()
|
|
@@ -348,10 +348,101 @@ class TestResolveEnviron(unittest.TestCase):
|
|
|
348
348
|
"""Tests expansion modifier with special chars."""
|
|
349
349
|
from envstack.env import resolve_environ
|
|
350
350
|
|
|
351
|
+
# remove ENV and ROOT from the environment
|
|
352
|
+
if "FOO" in os.environ:
|
|
353
|
+
del os.environ["FOO"]
|
|
354
|
+
if "VAR" in os.environ:
|
|
355
|
+
del os.environ["VAR"]
|
|
351
356
|
env = {"VAR": "${VAR:=${FOO:=/foo/bar}}"}
|
|
352
357
|
resolved = resolve_environ(env)
|
|
353
358
|
self.assertEqual(resolved["VAR"], "/foo/bar")
|
|
354
359
|
|
|
360
|
+
def test_deploy_root_two(self):
|
|
361
|
+
"""Tests $DEPLOY_ROOT with two vars."""
|
|
362
|
+
from envstack.env import resolve_environ
|
|
363
|
+
|
|
364
|
+
# set ENV and ROOT in the environment
|
|
365
|
+
os.environ["ROOT"] = "/mnt/pipe"
|
|
366
|
+
os.environ["ENV"] = "dev"
|
|
367
|
+
env = {
|
|
368
|
+
"DEPLOY_ROOT": "${ROOT}/${ENV}}",
|
|
369
|
+
"ENV": "${ENV:=prod}",
|
|
370
|
+
"ROOT": "${ROOT:=/var/tmp}",
|
|
371
|
+
}
|
|
372
|
+
resolved = resolve_environ(env)
|
|
373
|
+
self.assertEqual(resolved["DEPLOY_ROOT"], "/mnt/pipe/dev")
|
|
374
|
+
|
|
375
|
+
def test_deploy_root_three(self):
|
|
376
|
+
"""Tests $DEPLOY_ROOT with three vars."""
|
|
377
|
+
from envstack.env import resolve_environ
|
|
378
|
+
|
|
379
|
+
env_value = os.getenv("ENV", "prod")
|
|
380
|
+
env = {
|
|
381
|
+
"DEPLOY_ROOT": "${MOUNT}/${DRIVE}/${ENV}}",
|
|
382
|
+
"ENV": "${ENV:=prod}",
|
|
383
|
+
"MOUNT": "/mnt",
|
|
384
|
+
"DRIVE": "${DRIVE:=pipe}",
|
|
385
|
+
}
|
|
386
|
+
resolved = resolve_environ(env)
|
|
387
|
+
self.assertEqual(resolved["DEPLOY_ROOT"], f"/mnt/pipe/{env_value}")
|
|
388
|
+
|
|
389
|
+
def test_deploy_root_default_one(self):
|
|
390
|
+
"""Tests $DEPLOY_ROOT with default value and one var."""
|
|
391
|
+
from envstack.env import resolve_environ
|
|
392
|
+
|
|
393
|
+
# remove DEPLOY_ROOT, ENV and ROOT from the environment
|
|
394
|
+
if "DEPLOY_ROOT" in os.environ:
|
|
395
|
+
del os.environ["DEPLOY_ROOT"]
|
|
396
|
+
if "ENV" in os.environ:
|
|
397
|
+
del os.environ["ENV"]
|
|
398
|
+
if "ROOT" in os.environ:
|
|
399
|
+
del os.environ["ROOT"]
|
|
400
|
+
env = {
|
|
401
|
+
"DEPLOY_ROOT": "${DEPLOY_ROOT:=${TMP}}",
|
|
402
|
+
"ENV": "${ENV:=prod}",
|
|
403
|
+
"ROOT": "${ROOT:=/var/tmp}",
|
|
404
|
+
"TMP": "${ROOT}/${ENV}",
|
|
405
|
+
}
|
|
406
|
+
resolved = resolve_environ(env)
|
|
407
|
+
self.assertEqual(resolved["DEPLOY_ROOT"], "/var/tmp/prod")
|
|
408
|
+
|
|
409
|
+
def test_deploy_root_default_two(self):
|
|
410
|
+
"""Tests $DEPLOY_ROOT with default value and two vars."""
|
|
411
|
+
from envstack.env import resolve_environ
|
|
412
|
+
|
|
413
|
+
# remove DEPLOY_ROOT, ENV and ROOT from the environment
|
|
414
|
+
if "DEPLOY_ROOT" in os.environ:
|
|
415
|
+
del os.environ["DEPLOY_ROOT"]
|
|
416
|
+
if "ENV" in os.environ:
|
|
417
|
+
del os.environ["ENV"]
|
|
418
|
+
if "ROOT" in os.environ:
|
|
419
|
+
del os.environ["ROOT"]
|
|
420
|
+
env = {
|
|
421
|
+
"DEPLOY_ROOT": "${DEPLOY_ROOT:=${ROOT}/${ENV}}",
|
|
422
|
+
"ENV": "${ENV:=prod}",
|
|
423
|
+
"ROOT": "${ROOT:=/var/lib}",
|
|
424
|
+
}
|
|
425
|
+
resolved = resolve_environ(env)
|
|
426
|
+
self.assertEqual(resolved["DEPLOY_ROOT"], "/var/lib/prod")
|
|
427
|
+
|
|
428
|
+
def test_deploy_root_default_two_from_env(self):
|
|
429
|
+
"""Tests $DEPLOY_ROOT with default value from env."""
|
|
430
|
+
from envstack.env import resolve_environ
|
|
431
|
+
|
|
432
|
+
# remove DEPLOY_ROOT, ENV and ROOT from the environment
|
|
433
|
+
if "ENV" in os.environ:
|
|
434
|
+
del os.environ["ENV"]
|
|
435
|
+
if "ROOT" in os.environ:
|
|
436
|
+
del os.environ["ROOT"]
|
|
437
|
+
os.environ["DEPLOY_ROOT"] = "/some/path/here"
|
|
438
|
+
env = {
|
|
439
|
+
"DEPLOY_ROOT": "${DEPLOY_ROOT:=${ROOT}/${ENV}}",
|
|
440
|
+
"ENV": "${ENV:=prod}",
|
|
441
|
+
"ROOT": "${ROOT:=/var/lib}",
|
|
442
|
+
}
|
|
443
|
+
resolved = resolve_environ(env)
|
|
444
|
+
self.assertEqual(resolved["DEPLOY_ROOT"], "/some/path/here")
|
|
445
|
+
|
|
355
446
|
def test_expansion_modifier_deferred(self):
|
|
356
447
|
"""Tests expansion modifier with deferred value."""
|
|
357
448
|
from envstack.env import resolve_environ
|
|
@@ -387,30 +478,29 @@ class TestResolveEnviron(unittest.TestCase):
|
|
|
387
478
|
self.assertEqual(resolved["BAZ"], "")
|
|
388
479
|
self.assertRaises(KeyError, lambda: resolved["QUX"])
|
|
389
480
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
# from envstack.env import resolve_environ
|
|
481
|
+
def test_recursive_list_dict(self):
|
|
482
|
+
"""Tests resolving a recursive list dict environment."""
|
|
483
|
+
from envstack.env import resolve_environ
|
|
394
484
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
485
|
+
env = {"FOO": "foo", "BAR": "${FOO}", "BAZ": [{"qux": "${BAR}"}]}
|
|
486
|
+
resolved = resolve_environ(env)
|
|
487
|
+
self.assertEqual(resolved["BAZ"], [{"qux": "foo"}])
|
|
398
488
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
489
|
+
def test_recursive_dict_list(self):
|
|
490
|
+
"""Tests resolving a recursive dict list environment."""
|
|
491
|
+
from envstack.env import resolve_environ
|
|
402
492
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
493
|
+
env = {"FOO": "foo", "BAR": "${FOO}", "BAZ": {"qux": ["${BAR}"]}}
|
|
494
|
+
resolved = resolve_environ(env)
|
|
495
|
+
self.assertEqual(resolved["BAZ"], {"qux": ["foo"]})
|
|
406
496
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
497
|
+
def test_recursive_list_list(self):
|
|
498
|
+
"""Tests resolving a recursive list list environment."""
|
|
499
|
+
from envstack.env import resolve_environ
|
|
410
500
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
501
|
+
env = {"FOO": "foo", "BAR": "${FOO}", "BAZ": [["${BAR}"]]}
|
|
502
|
+
resolved = resolve_environ(env)
|
|
503
|
+
self.assertEqual(resolved["BAZ"], [["foo"]])
|
|
414
504
|
|
|
415
505
|
|
|
416
506
|
class TestBakeEnviron(unittest.TestCase):
|
|
@@ -210,6 +210,13 @@ class TestEvaluateModifiers(unittest.TestCase):
|
|
|
210
210
|
result = evaluate_modifiers(expression, environ)
|
|
211
211
|
self.assertEqual(result, "/foo/bar/baz")
|
|
212
212
|
|
|
213
|
+
def test_embedded_substitution_multiple_env(self):
|
|
214
|
+
"""Test multiple embedded substitution with value from env."""
|
|
215
|
+
expression = "${VAR:=${FOO:=${BAR:=/foo/bar/baz}}}"
|
|
216
|
+
environ = {"FOO": "/a/b/c"}
|
|
217
|
+
result = evaluate_modifiers(expression, environ)
|
|
218
|
+
self.assertEqual(result, "/a/b/c")
|
|
219
|
+
|
|
213
220
|
def test_embedded_substitution_prefix(self):
|
|
214
221
|
"""Test embedded substitution with prefix."""
|
|
215
222
|
expression = "${VAR:=default}/path"
|
|
@@ -224,19 +231,75 @@ class TestEvaluateModifiers(unittest.TestCase):
|
|
|
224
231
|
result = evaluate_modifiers(expression, environ)
|
|
225
232
|
self.assertEqual(result, "default/path")
|
|
226
233
|
|
|
227
|
-
def
|
|
228
|
-
"""Test embedded substitution with
|
|
229
|
-
expression = "${VAR:=${FOO}
|
|
234
|
+
def test_embedded_substitution_default_one_var_dash(self):
|
|
235
|
+
"""Test embedded substitution with one var default dash"""
|
|
236
|
+
expression = "${VAR:=${FOO}-bar}"
|
|
230
237
|
environ = {"FOO": "foo"}
|
|
231
238
|
result = evaluate_modifiers(expression, environ)
|
|
232
|
-
self.assertEqual(result, "foo
|
|
239
|
+
self.assertEqual(result, "foo-bar")
|
|
233
240
|
|
|
234
|
-
def
|
|
235
|
-
"""Test embedded substitution with
|
|
236
|
-
expression = "${VAR:=${FOO}
|
|
241
|
+
def test_embedded_substitution_default_one_var_slash(self):
|
|
242
|
+
"""Test embedded substitution with one var default slash"""
|
|
243
|
+
expression = "${VAR:=${FOO}/bar}"
|
|
237
244
|
environ = {"FOO": "foo"}
|
|
238
245
|
result = evaluate_modifiers(expression, environ)
|
|
239
|
-
self.assertEqual(result, "foo
|
|
246
|
+
self.assertEqual(result, "foo/bar")
|
|
247
|
+
|
|
248
|
+
def test_embedded_substitution_default_two_vars(self):
|
|
249
|
+
"""Test embedded substitution with two var default."""
|
|
250
|
+
expression = "${VAR:=${FOO}/${BAR}}"
|
|
251
|
+
environ = {"FOO": "foo", "BAR": "bar"}
|
|
252
|
+
result = evaluate_modifiers(expression, environ)
|
|
253
|
+
self.assertEqual(result, "foo/bar")
|
|
254
|
+
|
|
255
|
+
def test_embedded_substitution_default_two_vars_alt_1(self):
|
|
256
|
+
"""Test embedded substitution with two var default, alt 1."""
|
|
257
|
+
expression = "${VAR:=/${FOO}/${BAR:=bar}}"
|
|
258
|
+
environ = {"FOO": "foo", "BAR": "baz"}
|
|
259
|
+
result = evaluate_modifiers(expression, environ)
|
|
260
|
+
self.assertEqual(result, "/foo/baz")
|
|
261
|
+
|
|
262
|
+
def test_embedded_substitution_default_two_vars_alt_2(self):
|
|
263
|
+
"""Test embedded substitution with two var default, alt 2."""
|
|
264
|
+
expression = "${VAR:=/${FOO}/${FOO}}"
|
|
265
|
+
environ = {"FOO": "foo", "BAR": "bar"}
|
|
266
|
+
result = evaluate_modifiers(expression, environ)
|
|
267
|
+
self.assertEqual(result, "/foo/foo")
|
|
268
|
+
|
|
269
|
+
def test_embedded_substitution_default_two_vars_alt_3(self):
|
|
270
|
+
"""Test embedded substitution with two var default, alt 3."""
|
|
271
|
+
expression = "${VAR:=/${FOO}}/${FOO}"
|
|
272
|
+
environ = {"FOO": "foo", "BAR": "bar"}
|
|
273
|
+
result = evaluate_modifiers(expression, environ)
|
|
274
|
+
self.assertEqual(result, "/foo/foo")
|
|
275
|
+
|
|
276
|
+
def test_embedded_substitution_default_two_vars_alt_4(self):
|
|
277
|
+
"""Test embedded substitution with two var default, alt 4."""
|
|
278
|
+
expression = "${VAR:=/${FOO}}/${BAR:=bar}"
|
|
279
|
+
environ = {"FOO": "foo", "BAR": "baz"}
|
|
280
|
+
result = evaluate_modifiers(expression, environ)
|
|
281
|
+
self.assertEqual(result, "/foo/baz")
|
|
282
|
+
|
|
283
|
+
def test_embedded_substitution_default_three_vars(self):
|
|
284
|
+
"""Test embedded substitution with three vars."""
|
|
285
|
+
expression = "${VAR:=/${FOO}/${BAR}/${BAZ:=baz}}"
|
|
286
|
+
environ = {"FOO": "foo", "BAR": "bar"}
|
|
287
|
+
result = evaluate_modifiers(expression, environ)
|
|
288
|
+
self.assertEqual(result, "/foo/bar/baz")
|
|
289
|
+
|
|
290
|
+
def test_embedded_substitution_default_three_vars_alt_1(self):
|
|
291
|
+
"""Test embedded substitution with three vars, atl 1."""
|
|
292
|
+
expression = "${VAR:=/${FOO}}/${BAR}/${BAZ:=baz}"
|
|
293
|
+
environ = {"FOO": "foo", "BAR": "bar"}
|
|
294
|
+
result = evaluate_modifiers(expression, environ)
|
|
295
|
+
self.assertEqual(result, "/foo/bar/baz")
|
|
296
|
+
|
|
297
|
+
def test_embedded_substitution_default_two_vars_from_env(self):
|
|
298
|
+
"""Test embedded substitution with default, value from environ."""
|
|
299
|
+
expression = "${VAR:=${FOO}/${BAR}}"
|
|
300
|
+
environ = {"VAR": "/env/value", "FOO": "foo", "BAR": "bar"}
|
|
301
|
+
result = evaluate_modifiers(expression, environ)
|
|
302
|
+
self.assertEqual(result, "/env/value")
|
|
240
303
|
|
|
241
304
|
|
|
242
305
|
class TestUtils(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
|
|
File without changes
|