We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
It's possible to build a pex with multiple versions of the same package
``` bash

$ git clone https://github.com/sphinx-doc/sphinx && cd sphinx
$ pex . -v
  snowballstemmer 1.2.0
  MarkupSafe 0.23
  Jinja2 2.8
  six 1.9.0
  Babel 2.0
  Sphinx 1.3.1
  pytz 2015.4
  alabaster 0.7.6
  Pygments 2.0.2
  sphinx-rtd-theme 0.1.8
  Sphinx 1.4a0.dev20150811
  docutils 0.12
```

Note the two copies of sphinx pulled into the environment.  This messes with things like PEX_SCRIPT which expects to see just one version of an entry point.

Support PathResource that comes from egg
I was seeing failures when creating an entry point to a script that was included in an egg. I'm not super familiar with the pex internals, but it seemed to only happen when the pex was actually executing (IE it found the script during the build process but not during execution).

My guess is that the eggs get converted to a PathResource at some point and since the PathResource is treated the same as a WheelResource it fails on paths that came from eggs because the scripts directory is in a different location.

My fix was to try both finding scripts from an egg location and from a wheel location when a PathResource is found. I'm happy to add/update tests if you can point me to the relevant ones.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pex/variables.py`
Content:
```
1 # Copyright 2015 Pants project contributors (see CONTRIBUTORS.md).
2 # Licensed under the Apache License, Version 2.0 (see LICENSE).
3 
4 # Due to the PEX_ properties, disable checkstyle.
5 # checkstyle: noqa
6 
7 import os
8 from contextlib import contextmanager
9 
10 from .common import die
11 
12 __all__ = ('ENV', 'Variables')
13 
14 
15 class Variables(object):
16   """Environment variables supported by the PEX runtime."""
17 
18   @classmethod
19   def process_pydoc(cls, pydoc):
20     if pydoc is None:
21       return 'Unknown', 'Unknown'
22     pydoc = pydoc.splitlines()
23     variable_type = pydoc[0]
24     variable_text = ' '.join(filter(None, (line.strip() for line in pydoc[2:])))
25     return variable_type, variable_text
26 
27   @classmethod
28   def iter_help(cls):
29     for variable_name, value in sorted(cls.__dict__.items()):
30       if not variable_name.startswith('PEX_'):
31         continue
32       variable_type, variable_text = cls.process_pydoc(getattr(value, '__doc__'))
33       yield variable_name, variable_type, variable_text
34 
35   def __init__(self, environ=None, use_defaults=True):
36     self._environ = environ.copy() if environ is not None else os.environ
37     self._use_defaults = use_defaults
38 
39   def copy(self):
40     return self._environ.copy()
41 
42   def delete(self, variable):
43     self._environ.pop(variable, None)
44 
45   def set(self, variable, value):
46     self._environ[variable] = str(value)
47 
48   def _defaulted(self, default):
49     return default if self._use_defaults else None
50 
51   def _get_bool(self, variable, default=False):
52     value = self._environ.get(variable)
53     if value is not None:
54       if value.lower() in ('0', 'false'):
55         return False
56       elif value.lower() in ('1', 'true'):
57         return True
58       else:
59         die('Invalid value for %s, must be 0/1/false/true, got %r' % (variable, value))
60     else:
61       return self._defaulted(default)
62 
63   def _get_string(self, variable, default=None):
64     return self._environ.get(variable, self._defaulted(default))
65 
66   def _get_path(self, variable, default=None):
67     value = self._get_string(variable, default=default)
68     if value is not None:
69       return os.path.realpath(os.path.expanduser(value))
70 
71   def _get_int(self, variable, default=None):
72     try:
73       return int(self._environ[variable])
74     except ValueError:
75       die('Invalid value for %s, must be an integer, got %r' % (variable, self._environ[variable]))
76     except KeyError:
77       return self._defaulted(default)
78 
79   def strip_defaults(self):
80     """Returns a copy of these variables but with defaults stripped.
81 
82     Any variables not explicitly set in the environment will have a value of `None`.
83     """
84     return Variables(environ=self.copy(), use_defaults=False)
85 
86   @contextmanager
87   def patch(self, **kw):
88     """Update the environment for the duration of a context."""
89     old_environ = self._environ
90     self._environ = self._environ.copy()
91     self._environ.update(kw)
92     yield
93     self._environ = old_environ
94 
95   @property
96   def PEX_ALWAYS_CACHE(self):
97     """Boolean
98 
99     Always write PEX dependencies to disk prior to invoking regardless whether or not the
100     dependencies are zip-safe.  For certain dependencies that are very large such as numpy, this
101     can reduce the RAM necessary to launch the PEX.  The data will be written into $PEX_ROOT,
102     which by default is $HOME/.pex.  Default: false.
103     """
104     return self._get_bool('PEX_ALWAYS_CACHE', default=False)
105 
106   @property
107   def PEX_COVERAGE(self):
108     """Boolean
109 
110     Enable coverage reporting for this PEX file.  This requires that the "coverage" module is
111     available in the PEX environment.  Default: false.
112     """
113     return self._get_bool('PEX_COVERAGE', default=False)
114 
115   @property
116   def PEX_COVERAGE_FILENAME(self):
117     """Filename
118 
119     Write the coverage data to the specified filename.  If PEX_COVERAGE_FILENAME is not specified
120     but PEX_COVERAGE is, coverage information will be printed to stdout and not saved.
121     """
122     return self._get_path('PEX_COVERAGE_FILENAME', default=None)
123 
124   @property
125   def PEX_FORCE_LOCAL(self):
126     """Boolean
127 
128     Force this PEX to be not-zip-safe. This forces all code and dependencies to be written into
129     $PEX_ROOT prior to invocation.  This is an option for applications with static assets that
130     refer to paths relative to __file__ instead of using pkgutil/pkg_resources.  Default: false.
131     """
132     return self._get_bool('PEX_FORCE_LOCAL', default=False)
133 
134   @property
135   def PEX_IGNORE_ERRORS(self):
136     """Boolean
137 
138     Ignore any errors resolving dependencies when invoking the PEX file. This can be useful if you
139     know that a particular failing dependency is not necessary to run the application.  Default:
140     false.
141     """
142     return self._get_bool('PEX_IGNORE_ERRORS', default=False)
143 
144   @property
145   def PEX_INHERIT_PATH(self):
146     """Boolean
147 
148     Allow inheriting packages from site-packages.  By default, PEX scrubs any packages and
149     namespace packages from sys.path prior to invoking the application.  This is generally not
150     advised, but can be used in situations when certain dependencies do not conform to standard
151     packaging practices and thus cannot be bundled into PEX files.  Default: false.
152     """
153     return self._get_bool('PEX_INHERIT_PATH', default=False)
154 
155   @property
156   def PEX_INTERPRETER(self):
157     """Boolean
158 
159     Drop into a REPL instead of invoking the predefined entry point of this PEX. This can be
160     useful for inspecting the PEX environment interactively.  It can also be used to treat the PEX
161     file as an interpreter in order to execute other scripts in the context of the PEX file, e.g.
162     "PEX_INTERPRETER=1 ./app.pex my_script.py".  Equivalent to setting PEX_MODULE to empty.
163     Default: false.
164     """
165     return self._get_bool('PEX_INTERPRETER', default=False)
166 
167   @property
168   def PEX_MODULE(self):
169     """String
170 
171     Override the entry point into the PEX file.  Can either be a module, e.g.  'SimpleHTTPServer',
172     or a specific entry point in module:symbol form, e.g.  "myapp.bin:main".
173     """
174     return self._get_string('PEX_MODULE', default=None)
175 
176   @property
177   def PEX_PROFILE(self):
178     """Boolean
179 
180     Enable application profiling.  If specified and PEX_PROFILE_FILENAME is not specified, PEX will
181     print profiling information to stdout.
182     """
183     return self._get_path('PEX_PROFILE', default=None)
184 
185   @property
186   def PEX_PROFILE_FILENAME(self):
187     """Filename
188 
189     Profile the application and dump a profile into the specified filename in the standard
190     "profile" module format.
191     """
192     return self._get_path('PEX_PROFILE_FILENAME', default=None)
193 
194   @property
195   def PEX_PROFILE_SORT(self):
196     """String
197 
198     Toggle the profile sorting algorithm used to print out profile columns.  Default:
199     'cumulative'.
200     """
201     return self._get_string('PEX_PROFILE_SORT', default='cumulative')
202 
203   @property
204   def PEX_PYTHON(self):
205     """String
206 
207     Override the Python interpreter used to invoke this PEX.  Can be either an absolute path to an
208     interpreter or a base name e.g.  "python3.3".  If a base name is provided, the $PATH will be
209     searched for an appropriate match.
210     """
211     return self._get_string('PEX_PYTHON', default=None)
212 
213   @property
214   def PEX_ROOT(self):
215     """Directory
216 
217     The directory location for PEX to cache any dependencies and code.  PEX must write
218     not-zip-safe eggs and all wheels to disk in order to activate them.  Default: ~/.pex
219     """
220     return self._get_path('PEX_ROOT', default=None)
221 
222   @property
223   def PEX_PATH(self):
224     """A set of one or more PEX files
225 
226     Merge the packages from other PEX files into the current environment.  This allows you to
227     do things such as create a PEX file containing the "coverage" module or create PEX files
228     containing plugin entry points to be consumed by a main application.  Paths should be
229     specified in the same manner as $PATH, e.g. PEX_PATH=/path/to/pex1.pex:/path/to/pex2.pex
230     and so forth.
231     """
232     return self._get_string('PEX_PATH', default='')
233 
234   @property
235   def PEX_SCRIPT(self):
236     """String
237 
238     The script name within the PEX environment to execute.  This must either be an entry point as
239     defined in a distribution's console_scripts, or a script as defined in a distribution's
240     scripts section.  While Python supports any script including shell scripts, PEX only supports
241     invocation of Python scripts in this fashion.
242     """
243     return self._get_string('PEX_SCRIPT', default=None)
244 
245   @property
246   def PEX_TEARDOWN_VERBOSE(self):
247     """Boolean
248 
249     Enable verbosity for when the interpreter shuts down.  This is mostly only useful for
250     debugging PEX itself.  Default: false.
251     """
252     return self._get_bool('PEX_TEARDOWN_VERBOSE', default=False)
253 
254   @property
255   def PEX_VERBOSE(self):
256     """Integer
257 
258     Set the verbosity level of PEX debug logging.  The higher the number, the more logging, with 0
259     being disabled.  This environment variable can be extremely useful in debugging PEX
260     environment issues.  Default: 0
261     """
262     return self._get_int('PEX_VERBOSE', default=0)
263 
264   # TODO(wickman) Remove and push into --flags.  #94
265   @property
266   def PEX_HTTP_RETRIES(self):
267     """Integer
268 
269     The number of HTTP retries when performing dependency resolution when building a PEX file.
270     Default: 5.
271     """
272     return self._get_int('PEX_HTTP_RETRIES', default=5)
273 
274 
275 # Global singleton environment
276 ENV = Variables()
277
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pex/variables.py b/pex/variables.py
--- a/pex/variables.py
+++ b/pex/variables.py
@@ -5,6 +5,7 @@
 # checkstyle: noqa
 
 import os
+import sys
 from contextlib import contextmanager
 
 from .common import die
@@ -32,9 +33,13 @@
       variable_type, variable_text = cls.process_pydoc(getattr(value, '__doc__'))
       yield variable_name, variable_type, variable_text
 
-  def __init__(self, environ=None, use_defaults=True):
-    self._environ = environ.copy() if environ is not None else os.environ
+  def __init__(self, environ=None, rc='~/.pexrc', use_defaults=True):
     self._use_defaults = use_defaults
+    self._environ = environ.copy() if environ else os.environ
+    if not self.PEX_IGNORE_RCFILES:
+      rc_values = self._from_rc(rc).copy()
+      rc_values.update(self._environ)
+      self._environ = rc_values
 
   def copy(self):
     return self._environ.copy()
@@ -45,6 +50,22 @@
   def set(self, variable, value):
     self._environ[variable] = str(value)
 
+  def _from_rc(self, rc):
+    ret_vars = {}
+    for filename in [rc, os.path.join(os.path.dirname(sys.argv[0]), '.pexrc')]:
+      try:
+        with open(os.path.expanduser(filename)) as fh:
+          rc_items = map(self._get_kv, fh)
+          ret_vars.update(dict(filter(None, rc_items)))
+      except IOError:
+        continue
+    return ret_vars
+
+  def _get_kv(self, variable):
+    kv = variable.strip().split('=')
+    if len(list(filter(None, kv))) == 2:
+      return kv
+
   def _defaulted(self, default):
     return default if self._use_defaults else None
 
@@ -271,6 +292,14 @@
     """
     return self._get_int('PEX_HTTP_RETRIES', default=5)
 
+  @property
+  def PEX_IGNORE_RCFILES(self):
+    """Boolean
+
+    Explicitly disable the reading/parsing of pexrc files (~/.pexrc). Default: false.
+    """
+    return self._get_bool('PEX_IGNORE_RCFILES', default=False)
+
 
 # Global singleton environment
 ENV = Variables()

{"golden_diff": "diff --git a/pex/variables.py b/pex/variables.py\n--- a/pex/variables.py\n+++ b/pex/variables.py\n@@ -5,6 +5,7 @@\n # checkstyle: noqa\n \n import os\n+import sys\n from contextlib import contextmanager\n \n from .common import die\n@@ -32,9 +33,13 @@\n       variable_type, variable_text = cls.process_pydoc(getattr(value, '__doc__'))\n       yield variable_name, variable_type, variable_text\n \n-  def __init__(self, environ=None, use_defaults=True):\n-    self._environ = environ.copy() if environ is not None else os.environ\n+  def __init__(self, environ=None, rc='~/.pexrc', use_defaults=True):\n     self._use_defaults = use_defaults\n+    self._environ = environ.copy() if environ else os.environ\n+    if not self.PEX_IGNORE_RCFILES:\n+      rc_values = self._from_rc(rc).copy()\n+      rc_values.update(self._environ)\n+      self._environ = rc_values\n \n   def copy(self):\n     return self._environ.copy()\n@@ -45,6 +50,22 @@\n   def set(self, variable, value):\n     self._environ[variable] = str(value)\n \n+  def _from_rc(self, rc):\n+    ret_vars = {}\n+    for filename in [rc, os.path.join(os.path.dirname(sys.argv[0]), '.pexrc')]:\n+      try:\n+        with open(os.path.expanduser(filename)) as fh:\n+          rc_items = map(self._get_kv, fh)\n+          ret_vars.update(dict(filter(None, rc_items)))\n+      except IOError:\n+        continue\n+    return ret_vars\n+\n+  def _get_kv(self, variable):\n+    kv = variable.strip().split('=')\n+    if len(list(filter(None, kv))) == 2:\n+      return kv\n+\n   def _defaulted(self, default):\n     return default if self._use_defaults else None\n \n@@ -271,6 +292,14 @@\n     \"\"\"\n     return self._get_int('PEX_HTTP_RETRIES', default=5)\n \n+  @property\n+  def PEX_IGNORE_RCFILES(self):\n+    \"\"\"Boolean\n+\n+    Explicitly disable the reading/parsing of pexrc files (~/.pexrc). Default: false.\n+    \"\"\"\n+    return self._get_bool('PEX_IGNORE_RCFILES', default=False)\n+\n \n # Global singleton environment\n ENV = Variables()\n", "issue": "It's possible to build a pex with multiple versions of the same package\n``` bash\n\n$ git clone https://github.com/sphinx-doc/sphinx && cd sphinx\n$ pex . -v\n  snowballstemmer 1.2.0\n  MarkupSafe 0.23\n  Jinja2 2.8\n  six 1.9.0\n  Babel 2.0\n  Sphinx 1.3.1\n  pytz 2015.4\n  alabaster 0.7.6\n  Pygments 2.0.2\n  sphinx-rtd-theme 0.1.8\n  Sphinx 1.4a0.dev20150811\n  docutils 0.12\n```\n\nNote the two copies of sphinx pulled into the environment.  This messes with things like PEX_SCRIPT which expects to see just one version of an entry point.\n\nSupport PathResource that comes from egg\nI was seeing failures when creating an entry point to a script that was included in an egg. I'm not super familiar with the pex internals, but it seemed to only happen when the pex was actually executing (IE it found the script during the build process but not during execution).\n\nMy guess is that the eggs get converted to a PathResource at some point and since the PathResource is treated the same as a WheelResource it fails on paths that came from eggs because the scripts directory is in a different location.\n\nMy fix was to try both finding scripts from an egg location and from a wheel location when a PathResource is found. I'm happy to add/update tests if you can point me to the relevant ones.\n\n", "before_files": [{"content": "# Copyright 2015 Pants project contributors (see CONTRIBUTORS.md).\n# Licensed under the Apache License, Version 2.0 (see LICENSE).\n\n# Due to the PEX_ properties, disable checkstyle.\n# checkstyle: noqa\n\nimport os\nfrom contextlib import contextmanager\n\nfrom .common import die\n\n__all__ = ('ENV', 'Variables')\n\n\nclass Variables(object):\n  \"\"\"Environment variables supported by the PEX runtime.\"\"\"\n\n  @classmethod\n  def process_pydoc(cls, pydoc):\n    if pydoc is None:\n      return 'Unknown', 'Unknown'\n    pydoc = pydoc.splitlines()\n    variable_type = pydoc[0]\n    variable_text = ' '.join(filter(None, (line.strip() for line in pydoc[2:])))\n    return variable_type, variable_text\n\n  @classmethod\n  def iter_help(cls):\n    for variable_name, value in sorted(cls.__dict__.items()):\n      if not variable_name.startswith('PEX_'):\n        continue\n      variable_type, variable_text = cls.process_pydoc(getattr(value, '__doc__'))\n      yield variable_name, variable_type, variable_text\n\n  def __init__(self, environ=None, use_defaults=True):\n    self._environ = environ.copy() if environ is not None else os.environ\n    self._use_defaults = use_defaults\n\n  def copy(self):\n    return self._environ.copy()\n\n  def delete(self, variable):\n    self._environ.pop(variable, None)\n\n  def set(self, variable, value):\n    self._environ[variable] = str(value)\n\n  def _defaulted(self, default):\n    return default if self._use_defaults else None\n\n  def _get_bool(self, variable, default=False):\n    value = self._environ.get(variable)\n    if value is not None:\n      if value.lower() in ('0', 'false'):\n        return False\n      elif value.lower() in ('1', 'true'):\n        return True\n      else:\n        die('Invalid value for %s, must be 0/1/false/true, got %r' % (variable, value))\n    else:\n      return self._defaulted(default)\n\n  def _get_string(self, variable, default=None):\n    return self._environ.get(variable, self._defaulted(default))\n\n  def _get_path(self, variable, default=None):\n    value = self._get_string(variable, default=default)\n    if value is not None:\n      return os.path.realpath(os.path.expanduser(value))\n\n  def _get_int(self, variable, default=None):\n    try:\n      return int(self._environ[variable])\n    except ValueError:\n      die('Invalid value for %s, must be an integer, got %r' % (variable, self._environ[variable]))\n    except KeyError:\n      return self._defaulted(default)\n\n  def strip_defaults(self):\n    \"\"\"Returns a copy of these variables but with defaults stripped.\n\n    Any variables not explicitly set in the environment will have a value of `None`.\n    \"\"\"\n    return Variables(environ=self.copy(), use_defaults=False)\n\n  @contextmanager\n  def patch(self, **kw):\n    \"\"\"Update the environment for the duration of a context.\"\"\"\n    old_environ = self._environ\n    self._environ = self._environ.copy()\n    self._environ.update(kw)\n    yield\n    self._environ = old_environ\n\n  @property\n  def PEX_ALWAYS_CACHE(self):\n    \"\"\"Boolean\n\n    Always write PEX dependencies to disk prior to invoking regardless whether or not the\n    dependencies are zip-safe.  For certain dependencies that are very large such as numpy, this\n    can reduce the RAM necessary to launch the PEX.  The data will be written into $PEX_ROOT,\n    which by default is $HOME/.pex.  Default: false.\n    \"\"\"\n    return self._get_bool('PEX_ALWAYS_CACHE', default=False)\n\n  @property\n  def PEX_COVERAGE(self):\n    \"\"\"Boolean\n\n    Enable coverage reporting for this PEX file.  This requires that the \"coverage\" module is\n    available in the PEX environment.  Default: false.\n    \"\"\"\n    return self._get_bool('PEX_COVERAGE', default=False)\n\n  @property\n  def PEX_COVERAGE_FILENAME(self):\n    \"\"\"Filename\n\n    Write the coverage data to the specified filename.  If PEX_COVERAGE_FILENAME is not specified\n    but PEX_COVERAGE is, coverage information will be printed to stdout and not saved.\n    \"\"\"\n    return self._get_path('PEX_COVERAGE_FILENAME', default=None)\n\n  @property\n  def PEX_FORCE_LOCAL(self):\n    \"\"\"Boolean\n\n    Force this PEX to be not-zip-safe. This forces all code and dependencies to be written into\n    $PEX_ROOT prior to invocation.  This is an option for applications with static assets that\n    refer to paths relative to __file__ instead of using pkgutil/pkg_resources.  Default: false.\n    \"\"\"\n    return self._get_bool('PEX_FORCE_LOCAL', default=False)\n\n  @property\n  def PEX_IGNORE_ERRORS(self):\n    \"\"\"Boolean\n\n    Ignore any errors resolving dependencies when invoking the PEX file. This can be useful if you\n    know that a particular failing dependency is not necessary to run the application.  Default:\n    false.\n    \"\"\"\n    return self._get_bool('PEX_IGNORE_ERRORS', default=False)\n\n  @property\n  def PEX_INHERIT_PATH(self):\n    \"\"\"Boolean\n\n    Allow inheriting packages from site-packages.  By default, PEX scrubs any packages and\n    namespace packages from sys.path prior to invoking the application.  This is generally not\n    advised, but can be used in situations when certain dependencies do not conform to standard\n    packaging practices and thus cannot be bundled into PEX files.  Default: false.\n    \"\"\"\n    return self._get_bool('PEX_INHERIT_PATH', default=False)\n\n  @property\n  def PEX_INTERPRETER(self):\n    \"\"\"Boolean\n\n    Drop into a REPL instead of invoking the predefined entry point of this PEX. This can be\n    useful for inspecting the PEX environment interactively.  It can also be used to treat the PEX\n    file as an interpreter in order to execute other scripts in the context of the PEX file, e.g.\n    \"PEX_INTERPRETER=1 ./app.pex my_script.py\".  Equivalent to setting PEX_MODULE to empty.\n    Default: false.\n    \"\"\"\n    return self._get_bool('PEX_INTERPRETER', default=False)\n\n  @property\n  def PEX_MODULE(self):\n    \"\"\"String\n\n    Override the entry point into the PEX file.  Can either be a module, e.g.  'SimpleHTTPServer',\n    or a specific entry point in module:symbol form, e.g.  \"myapp.bin:main\".\n    \"\"\"\n    return self._get_string('PEX_MODULE', default=None)\n\n  @property\n  def PEX_PROFILE(self):\n    \"\"\"Boolean\n\n    Enable application profiling.  If specified and PEX_PROFILE_FILENAME is not specified, PEX will\n    print profiling information to stdout.\n    \"\"\"\n    return self._get_path('PEX_PROFILE', default=None)\n\n  @property\n  def PEX_PROFILE_FILENAME(self):\n    \"\"\"Filename\n\n    Profile the application and dump a profile into the specified filename in the standard\n    \"profile\" module format.\n    \"\"\"\n    return self._get_path('PEX_PROFILE_FILENAME', default=None)\n\n  @property\n  def PEX_PROFILE_SORT(self):\n    \"\"\"String\n\n    Toggle the profile sorting algorithm used to print out profile columns.  Default:\n    'cumulative'.\n    \"\"\"\n    return self._get_string('PEX_PROFILE_SORT', default='cumulative')\n\n  @property\n  def PEX_PYTHON(self):\n    \"\"\"String\n\n    Override the Python interpreter used to invoke this PEX.  Can be either an absolute path to an\n    interpreter or a base name e.g.  \"python3.3\".  If a base name is provided, the $PATH will be\n    searched for an appropriate match.\n    \"\"\"\n    return self._get_string('PEX_PYTHON', default=None)\n\n  @property\n  def PEX_ROOT(self):\n    \"\"\"Directory\n\n    The directory location for PEX to cache any dependencies and code.  PEX must write\n    not-zip-safe eggs and all wheels to disk in order to activate them.  Default: ~/.pex\n    \"\"\"\n    return self._get_path('PEX_ROOT', default=None)\n\n  @property\n  def PEX_PATH(self):\n    \"\"\"A set of one or more PEX files\n\n    Merge the packages from other PEX files into the current environment.  This allows you to\n    do things such as create a PEX file containing the \"coverage\" module or create PEX files\n    containing plugin entry points to be consumed by a main application.  Paths should be\n    specified in the same manner as $PATH, e.g. PEX_PATH=/path/to/pex1.pex:/path/to/pex2.pex\n    and so forth.\n    \"\"\"\n    return self._get_string('PEX_PATH', default='')\n\n  @property\n  def PEX_SCRIPT(self):\n    \"\"\"String\n\n    The script name within the PEX environment to execute.  This must either be an entry point as\n    defined in a distribution's console_scripts, or a script as defined in a distribution's\n    scripts section.  While Python supports any script including shell scripts, PEX only supports\n    invocation of Python scripts in this fashion.\n    \"\"\"\n    return self._get_string('PEX_SCRIPT', default=None)\n\n  @property\n  def PEX_TEARDOWN_VERBOSE(self):\n    \"\"\"Boolean\n\n    Enable verbosity for when the interpreter shuts down.  This is mostly only useful for\n    debugging PEX itself.  Default: false.\n    \"\"\"\n    return self._get_bool('PEX_TEARDOWN_VERBOSE', default=False)\n\n  @property\n  def PEX_VERBOSE(self):\n    \"\"\"Integer\n\n    Set the verbosity level of PEX debug logging.  The higher the number, the more logging, with 0\n    being disabled.  This environment variable can be extremely useful in debugging PEX\n    environment issues.  Default: 0\n    \"\"\"\n    return self._get_int('PEX_VERBOSE', default=0)\n\n  # TODO(wickman) Remove and push into --flags.  #94\n  @property\n  def PEX_HTTP_RETRIES(self):\n    \"\"\"Integer\n\n    The number of HTTP retries when performing dependency resolution when building a PEX file.\n    Default: 5.\n    \"\"\"\n    return self._get_int('PEX_HTTP_RETRIES', default=5)\n\n\n# Global singleton environment\nENV = Variables()\n", "path": "pex/variables.py"}], "after_files": [{"content": "# Copyright 2015 Pants project contributors (see CONTRIBUTORS.md).\n# Licensed under the Apache License, Version 2.0 (see LICENSE).\n\n# Due to the PEX_ properties, disable checkstyle.\n# checkstyle: noqa\n\nimport os\nimport sys\nfrom contextlib import contextmanager\n\nfrom .common import die\n\n__all__ = ('ENV', 'Variables')\n\n\nclass Variables(object):\n  \"\"\"Environment variables supported by the PEX runtime.\"\"\"\n\n  @classmethod\n  def process_pydoc(cls, pydoc):\n    if pydoc is None:\n      return 'Unknown', 'Unknown'\n    pydoc = pydoc.splitlines()\n    variable_type = pydoc[0]\n    variable_text = ' '.join(filter(None, (line.strip() for line in pydoc[2:])))\n    return variable_type, variable_text\n\n  @classmethod\n  def iter_help(cls):\n    for variable_name, value in sorted(cls.__dict__.items()):\n      if not variable_name.startswith('PEX_'):\n        continue\n      variable_type, variable_text = cls.process_pydoc(getattr(value, '__doc__'))\n      yield variable_name, variable_type, variable_text\n\n  def __init__(self, environ=None, rc='~/.pexrc', use_defaults=True):\n    self._use_defaults = use_defaults\n    self._environ = environ.copy() if environ else os.environ\n    if not self.PEX_IGNORE_RCFILES:\n      rc_values = self._from_rc(rc).copy()\n      rc_values.update(self._environ)\n      self._environ = rc_values\n\n  def copy(self):\n    return self._environ.copy()\n\n  def delete(self, variable):\n    self._environ.pop(variable, None)\n\n  def set(self, variable, value):\n    self._environ[variable] = str(value)\n\n  def _from_rc(self, rc):\n    ret_vars = {}\n    for filename in [rc, os.path.join(os.path.dirname(sys.argv[0]), '.pexrc')]:\n      try:\n        with open(os.path.expanduser(filename)) as fh:\n          rc_items = map(self._get_kv, fh)\n          ret_vars.update(dict(filter(None, rc_items)))\n      except IOError:\n        continue\n    return ret_vars\n\n  def _get_kv(self, variable):\n    kv = variable.strip().split('=')\n    if len(list(filter(None, kv))) == 2:\n      return kv\n\n  def _defaulted(self, default):\n    return default if self._use_defaults else None\n\n  def _get_bool(self, variable, default=False):\n    value = self._environ.get(variable)\n    if value is not None:\n      if value.lower() in ('0', 'false'):\n        return False\n      elif value.lower() in ('1', 'true'):\n        return True\n      else:\n        die('Invalid value for %s, must be 0/1/false/true, got %r' % (variable, value))\n    else:\n      return self._defaulted(default)\n\n  def _get_string(self, variable, default=None):\n    return self._environ.get(variable, self._defaulted(default))\n\n  def _get_path(self, variable, default=None):\n    value = self._get_string(variable, default=default)\n    if value is not None:\n      return os.path.realpath(os.path.expanduser(value))\n\n  def _get_int(self, variable, default=None):\n    try:\n      return int(self._environ[variable])\n    except ValueError:\n      die('Invalid value for %s, must be an integer, got %r' % (variable, self._environ[variable]))\n    except KeyError:\n      return self._defaulted(default)\n\n  def strip_defaults(self):\n    \"\"\"Returns a copy of these variables but with defaults stripped.\n\n    Any variables not explicitly set in the environment will have a value of `None`.\n    \"\"\"\n    return Variables(environ=self.copy(), use_defaults=False)\n\n  @contextmanager\n  def patch(self, **kw):\n    \"\"\"Update the environment for the duration of a context.\"\"\"\n    old_environ = self._environ\n    self._environ = self._environ.copy()\n    self._environ.update(kw)\n    yield\n    self._environ = old_environ\n\n  @property\n  def PEX_ALWAYS_CACHE(self):\n    \"\"\"Boolean\n\n    Always write PEX dependencies to disk prior to invoking regardless whether or not the\n    dependencies are zip-safe.  For certain dependencies that are very large such as numpy, this\n    can reduce the RAM necessary to launch the PEX.  The data will be written into $PEX_ROOT,\n    which by default is $HOME/.pex.  Default: false.\n    \"\"\"\n    return self._get_bool('PEX_ALWAYS_CACHE', default=False)\n\n  @property\n  def PEX_COVERAGE(self):\n    \"\"\"Boolean\n\n    Enable coverage reporting for this PEX file.  This requires that the \"coverage\" module is\n    available in the PEX environment.  Default: false.\n    \"\"\"\n    return self._get_bool('PEX_COVERAGE', default=False)\n\n  @property\n  def PEX_COVERAGE_FILENAME(self):\n    \"\"\"Filename\n\n    Write the coverage data to the specified filename.  If PEX_COVERAGE_FILENAME is not specified\n    but PEX_COVERAGE is, coverage information will be printed to stdout and not saved.\n    \"\"\"\n    return self._get_path('PEX_COVERAGE_FILENAME', default=None)\n\n  @property\n  def PEX_FORCE_LOCAL(self):\n    \"\"\"Boolean\n\n    Force this PEX to be not-zip-safe. This forces all code and dependencies to be written into\n    $PEX_ROOT prior to invocation.  This is an option for applications with static assets that\n    refer to paths relative to __file__ instead of using pkgutil/pkg_resources.  Default: false.\n    \"\"\"\n    return self._get_bool('PEX_FORCE_LOCAL', default=False)\n\n  @property\n  def PEX_IGNORE_ERRORS(self):\n    \"\"\"Boolean\n\n    Ignore any errors resolving dependencies when invoking the PEX file. This can be useful if you\n    know that a particular failing dependency is not necessary to run the application.  Default:\n    false.\n    \"\"\"\n    return self._get_bool('PEX_IGNORE_ERRORS', default=False)\n\n  @property\n  def PEX_INHERIT_PATH(self):\n    \"\"\"Boolean\n\n    Allow inheriting packages from site-packages.  By default, PEX scrubs any packages and\n    namespace packages from sys.path prior to invoking the application.  This is generally not\n    advised, but can be used in situations when certain dependencies do not conform to standard\n    packaging practices and thus cannot be bundled into PEX files.  Default: false.\n    \"\"\"\n    return self._get_bool('PEX_INHERIT_PATH', default=False)\n\n  @property\n  def PEX_INTERPRETER(self):\n    \"\"\"Boolean\n\n    Drop into a REPL instead of invoking the predefined entry point of this PEX. This can be\n    useful for inspecting the PEX environment interactively.  It can also be used to treat the PEX\n    file as an interpreter in order to execute other scripts in the context of the PEX file, e.g.\n    \"PEX_INTERPRETER=1 ./app.pex my_script.py\".  Equivalent to setting PEX_MODULE to empty.\n    Default: false.\n    \"\"\"\n    return self._get_bool('PEX_INTERPRETER', default=False)\n\n  @property\n  def PEX_MODULE(self):\n    \"\"\"String\n\n    Override the entry point into the PEX file.  Can either be a module, e.g.  'SimpleHTTPServer',\n    or a specific entry point in module:symbol form, e.g.  \"myapp.bin:main\".\n    \"\"\"\n    return self._get_string('PEX_MODULE', default=None)\n\n  @property\n  def PEX_PROFILE(self):\n    \"\"\"Boolean\n\n    Enable application profiling.  If specified and PEX_PROFILE_FILENAME is not specified, PEX will\n    print profiling information to stdout.\n    \"\"\"\n    return self._get_path('PEX_PROFILE', default=None)\n\n  @property\n  def PEX_PROFILE_FILENAME(self):\n    \"\"\"Filename\n\n    Profile the application and dump a profile into the specified filename in the standard\n    \"profile\" module format.\n    \"\"\"\n    return self._get_path('PEX_PROFILE_FILENAME', default=None)\n\n  @property\n  def PEX_PROFILE_SORT(self):\n    \"\"\"String\n\n    Toggle the profile sorting algorithm used to print out profile columns.  Default:\n    'cumulative'.\n    \"\"\"\n    return self._get_string('PEX_PROFILE_SORT', default='cumulative')\n\n  @property\n  def PEX_PYTHON(self):\n    \"\"\"String\n\n    Override the Python interpreter used to invoke this PEX.  Can be either an absolute path to an\n    interpreter or a base name e.g.  \"python3.3\".  If a base name is provided, the $PATH will be\n    searched for an appropriate match.\n    \"\"\"\n    return self._get_string('PEX_PYTHON', default=None)\n\n  @property\n  def PEX_ROOT(self):\n    \"\"\"Directory\n\n    The directory location for PEX to cache any dependencies and code.  PEX must write\n    not-zip-safe eggs and all wheels to disk in order to activate them.  Default: ~/.pex\n    \"\"\"\n    return self._get_path('PEX_ROOT', default=None)\n\n  @property\n  def PEX_PATH(self):\n    \"\"\"A set of one or more PEX files\n\n    Merge the packages from other PEX files into the current environment.  This allows you to\n    do things such as create a PEX file containing the \"coverage\" module or create PEX files\n    containing plugin entry points to be consumed by a main application.  Paths should be\n    specified in the same manner as $PATH, e.g. PEX_PATH=/path/to/pex1.pex:/path/to/pex2.pex\n    and so forth.\n    \"\"\"\n    return self._get_string('PEX_PATH', default='')\n\n  @property\n  def PEX_SCRIPT(self):\n    \"\"\"String\n\n    The script name within the PEX environment to execute.  This must either be an entry point as\n    defined in a distribution's console_scripts, or a script as defined in a distribution's\n    scripts section.  While Python supports any script including shell scripts, PEX only supports\n    invocation of Python scripts in this fashion.\n    \"\"\"\n    return self._get_string('PEX_SCRIPT', default=None)\n\n  @property\n  def PEX_TEARDOWN_VERBOSE(self):\n    \"\"\"Boolean\n\n    Enable verbosity for when the interpreter shuts down.  This is mostly only useful for\n    debugging PEX itself.  Default: false.\n    \"\"\"\n    return self._get_bool('PEX_TEARDOWN_VERBOSE', default=False)\n\n  @property\n  def PEX_VERBOSE(self):\n    \"\"\"Integer\n\n    Set the verbosity level of PEX debug logging.  The higher the number, the more logging, with 0\n    being disabled.  This environment variable can be extremely useful in debugging PEX\n    environment issues.  Default: 0\n    \"\"\"\n    return self._get_int('PEX_VERBOSE', default=0)\n\n  # TODO(wickman) Remove and push into --flags.  #94\n  @property\n  def PEX_HTTP_RETRIES(self):\n    \"\"\"Integer\n\n    The number of HTTP retries when performing dependency resolution when building a PEX file.\n    Default: 5.\n    \"\"\"\n    return self._get_int('PEX_HTTP_RETRIES', default=5)\n\n  @property\n  def PEX_IGNORE_RCFILES(self):\n    \"\"\"Boolean\n\n    Explicitly disable the reading/parsing of pexrc files (~/.pexrc). Default: false.\n    \"\"\"\n    return self._get_bool('PEX_IGNORE_RCFILES', default=False)\n\n\n# Global singleton environment\nENV = Variables()\n", "path": "pex/variables.py"}]}