envstack 0.6.2__tar.gz → 0.6.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.
Files changed (26) hide show
  1. {envstack-0.6.2/lib/envstack.egg-info → envstack-0.6.3}/PKG-INFO +21 -6
  2. {envstack-0.6.2 → envstack-0.6.3}/README.md +20 -5
  3. {envstack-0.6.2 → envstack-0.6.3}/lib/envstack/__init__.py +2 -2
  4. {envstack-0.6.2 → envstack-0.6.3}/lib/envstack/config.py +4 -5
  5. {envstack-0.6.2 → envstack-0.6.3}/lib/envstack/env.py +67 -8
  6. envstack-0.6.3/lib/envstack/util.py +81 -0
  7. {envstack-0.6.2 → envstack-0.6.3/lib/envstack.egg-info}/PKG-INFO +21 -6
  8. {envstack-0.6.2 → envstack-0.6.3}/lib/envstack.egg-info/SOURCES.txt +1 -0
  9. {envstack-0.6.2 → envstack-0.6.3}/setup.py +1 -1
  10. {envstack-0.6.2 → envstack-0.6.3}/LICENSE +0 -0
  11. {envstack-0.6.2 → envstack-0.6.3}/dev.env +0 -0
  12. {envstack-0.6.2 → envstack-0.6.3}/dist.json +0 -0
  13. {envstack-0.6.2 → envstack-0.6.3}/lib/envstack/cli.py +0 -0
  14. {envstack-0.6.2 → envstack-0.6.3}/lib/envstack/exceptions.py +0 -0
  15. {envstack-0.6.2 → envstack-0.6.3}/lib/envstack/logger.py +0 -0
  16. {envstack-0.6.2 → envstack-0.6.3}/lib/envstack/path.py +0 -0
  17. {envstack-0.6.2 → envstack-0.6.3}/lib/envstack/wrapper.py +0 -0
  18. {envstack-0.6.2 → envstack-0.6.3}/lib/envstack.egg-info/dependency_links.txt +0 -0
  19. {envstack-0.6.2 → envstack-0.6.3}/lib/envstack.egg-info/entry_points.txt +0 -0
  20. {envstack-0.6.2 → envstack-0.6.3}/lib/envstack.egg-info/not-zip-safe +0 -0
  21. {envstack-0.6.2 → envstack-0.6.3}/lib/envstack.egg-info/requires.txt +0 -0
  22. {envstack-0.6.2 → envstack-0.6.3}/lib/envstack.egg-info/top_level.txt +0 -0
  23. {envstack-0.6.2 → envstack-0.6.3}/setup.cfg +0 -0
  24. {envstack-0.6.2 → envstack-0.6.3}/stack.env +0 -0
  25. {envstack-0.6.2 → envstack-0.6.3}/tests/test_env.py +0 -0
  26. {envstack-0.6.2 → envstack-0.6.3}/tests/test_path.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: envstack
3
- Version: 0.6.2
3
+ Version: 0.6.3
4
4
  Summary: Stacked environment variable management system
5
5
  Home-page: http://github.com/rsgalloway/envstack
6
6
  Author: Ryan Galloway
@@ -184,19 +184,34 @@ $ envstack [STACK] --sources
184
184
 
185
185
  ## Python API
186
186
 
187
- To init the environment stack, use the `init` function:
187
+ To initialize the environment stack in Python, use the `init` function:
188
188
 
189
189
  ```python
190
- >>> envstack.init("thing")
191
- >>> os.getenv("FOO")
192
- 'bar'
190
+ >>> envstack.init()
191
+ >>> os.getenv("HELLO")
192
+ 'world'
193
+ ```
194
+
195
+ To initialize the "dev" stack:
196
+
197
+ ```python
198
+ >>> envstack.init("dev")
199
+ >>> os.getenv("ENV")
200
+ 'dev'
201
+ ```
202
+
203
+ To revert the original environment:
204
+
205
+ ```python
206
+ >>> envstack.revert()
207
+ >>> os.getenv("HELLO")
208
+ >>>
193
209
  ```
194
210
 
195
211
  Alternatively, `envstack.getenv` can be a drop-in replacement for `os.getenv`
196
212
  for the default environment stack:
197
213
 
198
214
  ```python
199
- >>> import envstack
200
215
  >>> envstack.getenv("HELLO")
201
216
  'world'
202
217
  ```
@@ -161,19 +161,34 @@ $ envstack [STACK] --sources
161
161
 
162
162
  ## Python API
163
163
 
164
- To init the environment stack, use the `init` function:
164
+ To initialize the environment stack in Python, use the `init` function:
165
165
 
166
166
  ```python
167
- >>> envstack.init("thing")
168
- >>> os.getenv("FOO")
169
- 'bar'
167
+ >>> envstack.init()
168
+ >>> os.getenv("HELLO")
169
+ 'world'
170
+ ```
171
+
172
+ To initialize the "dev" stack:
173
+
174
+ ```python
175
+ >>> envstack.init("dev")
176
+ >>> os.getenv("ENV")
177
+ 'dev'
178
+ ```
179
+
180
+ To revert the original environment:
181
+
182
+ ```python
183
+ >>> envstack.revert()
184
+ >>> os.getenv("HELLO")
185
+ >>>
170
186
  ```
171
187
 
172
188
  Alternatively, `envstack.getenv` can be a drop-in replacement for `os.getenv`
173
189
  for the default environment stack:
174
190
 
175
191
  ```python
176
- >>> import envstack
177
192
  >>> envstack.getenv("HELLO")
178
193
  'world'
179
194
  ```
@@ -34,6 +34,6 @@ Stacked environment variable management system.
34
34
  """
35
35
 
36
36
  __prog__ = "envstack"
37
- __version__ = "0.6.2"
37
+ __version__ = "0.6.3"
38
38
 
39
- from envstack.env import Env, getenv, init, load_file
39
+ from envstack.env import Env, getenv, init, load_file, revert, save
@@ -76,14 +76,13 @@ DEFAULT_ENV = {
76
76
  "USER": USERNAME,
77
77
  }
78
78
 
79
- # default location of envstack files
80
- # NOTE: the siteconf sitecustomize.py module may override this
79
+ # default location of env stack .env files
81
80
  DEFAULT_ENV_DIR = os.getenv(
82
81
  "DEFAULT_ENV_DIR",
83
82
  {
84
- "darwin": "{HOME}/Library/Application Support/envstack",
85
- "linux": "{HOME}/.local/envstack",
86
- "windows": "C:\\ProgramData\\envstack",
83
+ "darwin": "{HOME}/Library/Application Support/pipe/{ENV}/env",
84
+ "linux": "{HOME}/.local/pipe/{ENV}/env",
85
+ "windows": "C:\\ProgramData\\pipe\\{ENV}\\env",
87
86
  }
88
87
  .get(PLATFORM)
89
88
  .format(**DEFAULT_ENV),
@@ -36,8 +36,9 @@ Contains functions and classes for processing scoped .env files.
36
36
  import os
37
37
  import re
38
38
  import string
39
+ import sys
39
40
 
40
- from envstack import config, logger, path
41
+ from envstack import config, logger, path, util
41
42
  from envstack.exceptions import *
42
43
 
43
44
  # value delimiter pattern (splits values by colons or semicolons)
@@ -49,6 +50,9 @@ load_file_cache = {}
49
50
  # value for unresolvable variables
50
51
  null = ""
51
52
 
53
+ # stores the original environment
54
+ SAVED_ENVIRONMENT = None
55
+
52
56
 
53
57
  class EnvVar(string.Template, str):
54
58
  """A string class for supporting $-substitutions, e.g.: ::
@@ -529,7 +533,7 @@ def expandvars(var, env=None, recursive=False):
529
533
  return EnvVar(var).expand(env, recursive=recursive)
530
534
 
531
535
 
532
- def export(name, shell="bash", resolve=False, scope=None, clear=False):
536
+ def export(name, shell=config.SHELL, resolve=False, scope=None, clear=False):
533
537
  """Returns environment commands that can be sourced.
534
538
 
535
539
  $ source <(envstack --export)
@@ -542,7 +546,7 @@ def export(name, shell="bash", resolve=False, scope=None, clear=False):
542
546
  (see output of config.detect_shell()).
543
547
 
544
548
  :param name: stack namespace.
545
- :param shell: name of shell (default: bash).
549
+ :param shell: name of shell (default: current shell).
546
550
  :param resolve: resolve values (default: True).
547
551
  :param scope: environment scope (default: cwd).
548
552
  :param clear: clear existing values (default: False).
@@ -580,14 +584,66 @@ def export(name, shell="bash", resolve=False, scope=None, clear=False):
580
584
  return exp
581
585
 
582
586
 
587
+ def save():
588
+ """Saves the current environment."""
589
+ global SAVED_ENVIRONMENT
590
+ if not SAVED_ENVIRONMENT:
591
+ SAVED_ENVIRONMENT = dict(os.environ.copy())
592
+ return SAVED_ENVIRONMENT
593
+
594
+
595
+ def revert():
596
+ """Reverts the environment to the saved environment."""
597
+ global SAVED_ENVIRONMENT
598
+ if SAVED_ENVIRONMENT is None:
599
+ return
600
+ os.environ.clear()
601
+ os.environ.update(SAVED_ENVIRONMENT)
602
+
603
+
583
604
  def init(name=config.DEFAULT_NAMESPACE):
584
- """Initializes the environment for a given namespace.
605
+ """Initializes the environment for a given namespace. Modifies sys.path
606
+ from PYTHONPATH.
585
607
 
586
- :param name: namespace (basename of env files).
608
+ # initialize the default environemnt
609
+ >>> envstack.init()
610
+
611
+ # initialize the dev environment
612
+ >>> envstack.init('dev')
613
+
614
+ # revert to the original environment
615
+ >>> envstack.revert()
616
+
617
+ :param name: stack namespace (default stack).
587
618
  """
619
+ logger.log.debug("initializing env stack: %s", name)
620
+
621
+ # save the current environment
622
+ save()
623
+
624
+ # clear old sys.path values
625
+ for path in util.get_paths_from_var("PYTHONPATH"):
626
+ if path and path in sys.path:
627
+ sys.path.remove(path)
628
+
629
+ # clear vars from stack namespace
630
+ env = load_environ(name, environ=None)
631
+ for key in env.keys():
632
+ if key in os.environ:
633
+ del os.environ[key]
634
+
635
+ # store the name of the environment stack (e.g. for $PS1)
636
+ os.environ["ENVSTACK"] = name
637
+
638
+ # load the new environment
588
639
  env = load_environ(name)
589
640
  os.environ.update(encode(env))
590
641
 
642
+ # update sys.path from PYTHONPATH
643
+ for path in util.get_paths_from_var("PYTHONPATH"):
644
+ if path and path not in sys.path:
645
+ sys.path.insert(0, path)
646
+
591
647
 
592
648
  def load_environ(
593
649
  name=config.DEFAULT_NAMESPACE,
@@ -688,9 +744,11 @@ def merge(env, other, strict=False, platform=config.PLATFORM):
688
744
  """
689
745
  merged = env.copy()
690
746
  for key, value in merged.items():
691
- var = "${%s}" % key
747
+ varstr = "${%s}" % key
748
+ # replace variables in other with values from env
692
749
  if key in other:
693
- if var in str(value):
750
+ # replace variables in value with values from other
751
+ if varstr in str(value):
694
752
  value = re.sub(
695
753
  r"\${(\w+)}",
696
754
  lambda match: other.get(match.group(1), match.group(0)),
@@ -699,7 +757,8 @@ def merge(env, other, strict=False, platform=config.PLATFORM):
699
757
  elif not strict:
700
758
  value = other.get(key)
701
759
  else:
702
- value = str(value).replace(var, "")
760
+ value = str(value).replace(varstr, "")
761
+ # replace colons with semicolons on windows
703
762
  if platform == "windows":
704
763
  result = re.sub(r"(?<!\b[A-Za-z]):", ";", str(value))
705
764
  value = result.rstrip(";")
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env python
2
+ #
3
+ # Copyright (c) 2024, Ryan Galloway (ryan@rsgalloway.com)
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # - Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # - Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # - Neither the name of the software nor the names of its contributors
16
+ # may be used to endorse or promote products derived from this software
17
+ # without specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+
32
+ __doc__ = """
33
+ Contains common utility functions and classes.
34
+ """
35
+
36
+ import os
37
+
38
+
39
+ def dict_diff(dict1, dict2):
40
+ """
41
+ Compare two dictionaries and return their differences.
42
+
43
+ :param dict1: First dictionary.
44
+ :param dict2: Second dictionary.
45
+ :returns: diff dict: 'added', 'removed', 'changed', and 'unchanged'.
46
+ """
47
+ added = {k: dict2[k] for k in dict2 if k not in dict1}
48
+ removed = {k: dict1[k] for k in dict1 if k not in dict2}
49
+ changed = {
50
+ k: (dict1[k], dict2[k]) for k in dict1 if k in dict2 and dict1[k] != dict2[k]
51
+ }
52
+ unchanged = {k: dict1[k] for k in dict1 if k in dict2 and dict1[k] == dict2[k]}
53
+
54
+ return {
55
+ "added": added,
56
+ "removed": removed,
57
+ "changed": changed,
58
+ "unchanged": unchanged,
59
+ }
60
+
61
+
62
+ def get_paths_from_var(var="PYTHONPATH", pathsep=os.pathsep, reverse=True):
63
+ """Returns a list of paths from a given pathsep separated environment
64
+ variable.
65
+
66
+ :param var: The environment variable to get paths from.
67
+ :param pathsep: The path separator to use.
68
+ :param reverse: Reverse the order of the paths.
69
+ :returns: A list of paths.
70
+ """
71
+
72
+ paths = []
73
+ value = os.environ.get(var)
74
+
75
+ if value:
76
+ paths = value.split(pathsep)
77
+
78
+ if reverse:
79
+ paths.reverse()
80
+
81
+ return paths
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: envstack
3
- Version: 0.6.2
3
+ Version: 0.6.3
4
4
  Summary: Stacked environment variable management system
5
5
  Home-page: http://github.com/rsgalloway/envstack
6
6
  Author: Ryan Galloway
@@ -184,19 +184,34 @@ $ envstack [STACK] --sources
184
184
 
185
185
  ## Python API
186
186
 
187
- To init the environment stack, use the `init` function:
187
+ To initialize the environment stack in Python, use the `init` function:
188
188
 
189
189
  ```python
190
- >>> envstack.init("thing")
191
- >>> os.getenv("FOO")
192
- 'bar'
190
+ >>> envstack.init()
191
+ >>> os.getenv("HELLO")
192
+ 'world'
193
+ ```
194
+
195
+ To initialize the "dev" stack:
196
+
197
+ ```python
198
+ >>> envstack.init("dev")
199
+ >>> os.getenv("ENV")
200
+ 'dev'
201
+ ```
202
+
203
+ To revert the original environment:
204
+
205
+ ```python
206
+ >>> envstack.revert()
207
+ >>> os.getenv("HELLO")
208
+ >>>
193
209
  ```
194
210
 
195
211
  Alternatively, `envstack.getenv` can be a drop-in replacement for `os.getenv`
196
212
  for the default environment stack:
197
213
 
198
214
  ```python
199
- >>> import envstack
200
215
  >>> envstack.getenv("HELLO")
201
216
  'world'
202
217
  ```
@@ -11,6 +11,7 @@ lib/envstack/env.py
11
11
  lib/envstack/exceptions.py
12
12
  lib/envstack/logger.py
13
13
  lib/envstack/path.py
14
+ lib/envstack/util.py
14
15
  lib/envstack/wrapper.py
15
16
  lib/envstack.egg-info/PKG-INFO
16
17
  lib/envstack.egg-info/SOURCES.txt
@@ -74,7 +74,7 @@ class PostInstallCommand(install):
74
74
 
75
75
  setup(
76
76
  name="envstack",
77
- version="0.6.2",
77
+ version="0.6.3",
78
78
  description="Stacked environment variable management system",
79
79
  long_description=long_description,
80
80
  long_description_content_type="text/markdown",
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