All About Your Python(s)
stdout" or "stderr" streams of "subprocess.POpen()" under Python 3.x.
Here I present a script that provides diagnostics about the current Python execution context, or the Python environment of the interpreter passed as an argument.
As a Python developer, I have multiple Python versions side-by-side for testing purposes, using scripts that munge my $PATH variable to "import" and "unimport" different versions of Python as I need them.
While "which python" is always available, many times I want to know things like, "what is the version of the current default Python?" or "where is the current Python's 'site-packages' directory?". Though all this information is usually one or two commands away, it can be pretty tedious jump through these hoops every time this information is required.
Also, often mature systems that have gone through various systems administrators and upgrades have both legacy and current stuff scattered all over the place, and it can be a hassle trying to figure out where the site packages and other components of a particular installation of Python are located.
The offspring of my laziness is the attached script.
Running it without arguments provides a summary of the shell's current default Python environment:
$ describe-python
[Python 2.6.1]
Executable: /usr/bin/python
Version: 2.6.1.final.0
Installation Prefix: /System/Library/Frameworks/Python.framework/Versions/2.6
Site Packages: /Library/Python/2.6/site-packages
Implementation: CPython
Branch: tags/r261
Revision: 67515
Compiler: GCC 4.2.1 (Apple Inc. build 5646)
Build Date: Jul 7 2009 23:51:51You can also pass in an explicit path to a specific Python interpreter:
$ describe-python /opt/python-2.4.5/bin/python
[Python 2.4.5]
Executable: /opt/python-2.4.5/bin/python
Version: 2.4.5.final.0
Installation Prefix: /opt/python-2.4.5
Site Packages: /opt/python-2.4.5/lib/python2.4/site-packages
Implementation: ???
Branch: ???
Revision: ???
Compiler: GCC 4.0.1 (Apple Inc. build 5465)
Build Date: Sep 29 2008 21:20:46$ describe-python /opt/pypy-1.2-osx/bin/pypy
[Python 2.5.2 (72096, Mar 11 2010, 12:33:31) [PyPy 1.2.0] ]
Executable: /opt/pypy-1.2-osx/bin/pypy
Version: 2.5.2.beta.42
Installation Prefix:
Site Packages: /opt/pypy-1.2-osx/site-packages
Implementation: ???
Branch: ???
Revision: ???
Compiler: PyPy 1.2.0
Build Date: Mar 11 2010 12:33:31$ describe-python /opt/jython2.5.0/bin/jython
[Jython 2.5.0]
Executable: /opt/jython2.5.0/bin/jython
Version: 2.5.0.final.0
Installation Prefix: /opt/jython2.5.0
Site Packages: /opt/jython2.5.0/Lib/site-packages
Implementation: ???
Branch: ???
Revision: ???
Compiler: Java HotSpot(TM) 64-Bit Server VM (Apple Inc.)
Build Date: Jun 16 2009 13:33:26The "-s" or "--site-packages" flag, which will result in the full path of the site packages directory of the Python environment being written to the standard output:
[~]$ describe-python -s /Library/Python/2.6/site-packages [~]$ describe-python -s /usr/local/bin/python2.6/ /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages [~]$ describe-python -s /opt/python-2.4.5/bin/python /opt/python-2.4.5/lib/python2.4/site-packages
This makes hopping to the site packages directory of a particular Python installation as simple as:
$ cd $(describe-python -s)
or:
$ cd `describe-python -s`
For those who would prefer to inspect the script without downloading it:
#! /usr/bin/env python import subprocess import optparse import os import sys __version__ = "1.0.0" __author__ = "Jeet Sukumaran" class cached_property(object): """ Lazy-loading read/write property descriptor. Value is stored locally in descriptor object. If value is not set when accessed, value is computed using given function. Value can be cleared by calling 'del'. """ def __init__(self, func): self._func = func self._values = {} self.__name__ = func.__name__ self.__doc__ = func.__doc__ def __get__(self, obj, obj_class): if obj is None: return obj if obj not in self._values \ or self._values[obj] is None: self._values[obj] = self._func(obj) return self._values[obj] def __set__(self, obj, value): self._values[obj] = value def __delete__(self, obj): if self.__name__ in obj.__dict__: del obj.__dict__[self.__name__] self._values[obj] = None class PythonEnvironment(object): """ Wraps interrogation of a particular Python interpreter (i.e., Python compiler/ interpreter binary) for information. """ def __init__(self, python_interpreter='python'): self._python_interpreter = None self.python_interpreter = python_interpreter def _get_python_interpreter(self): return self._python_interpreter def _set_python_interpreter(self, p): if not p or p is None: raise ValueError("Python interpreter path cannot be empty") self._python_interpreter = p python_interpreter = property(_get_python_interpreter, _set_python_interpreter) def _exec_python(self, cmd, first_line_only=True, default=None, exit_on_fail=True): try: p = subprocess.Popen([self.python_interpreter, "-c", cmd], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError: sys.exit("'%s' is not a valid Python interpreter" % self.python_interpreter) result = p.stdout.readlines() if result: if first_line_only: return result[0].decode("utf-8").replace('\n', '') else: return [r.decode("utf-8").replace('\n', '') for r in result] else: e = p.stderr.read() if e and exit_on_fail: sys.exit(e) else: return default def prefetch(self): code = r""" import sys import platform from distutils.sysconfig import get_python_lib print("executable$$$%s" % sys.executable) try: print("prefix$$$%s" % sys.prefix) except AttributeError: print("prefix$$$") print("site_packages$$$%s" % get_python_lib()) try: print("implementation$$$%s" % platform.python_implementation()) except AttributeError: print("implementation$$$???") print("version_short$$$%s" % ('.'.join([str(s) for s in sys.version_info]))) print("version_long$$$%s" % (sys.version.replace('\n', ': '))) print("version$$$%s" % platform.python_version()) print("site_packages$$$%s" % get_python_lib()) try: print("branch$$$%s" % platform.python_branch()) except AttributeError: print("branch$$$???") try: print("revision$$$%s" % platform.python_revision()) except AttributeError: print("revision$$$???") print("build_date$$$%s" % (platform.python_build()[1])) print("compiler$$$%s" % platform.python_compiler()) """ result = self._exec_python(code, first_line_only=False) for line in result: key, value = line.split('$$$') setattr(self, key, value) @cached_property def executable(self): return self._exec_python(r"import sys; print(sys.executable)") @cached_property def prefix(self): return self._exec_python(r"import sys; print(sys.prefix)", default="", exit_on_fail=False) @cached_property def site_packages(self): return self._exec_python(r"from distutils.sysconfig import get_python_lib; print(get_python_lib())") @cached_property def sys_path(self): sp = self._exec_python(r"import sys; print('\n'.join(sys.path))", first_line_only=False) return sp @cached_property def implementation(self): return self._exec_python(r"import platform; print(platform.python_implementation())", default="???", exit_on_fail=False) @cached_property def version_short(self): return self._exec_python(r"import sys; print('.'.join([str(s) for s in sys.version_info]))") @cached_property def version_long(self): return self._exec_python(r"import sys; print(sys.version.replace('\n', ': '))") @cached_property def version(self): return self._exec_python(r"import platform; print(platform.python_version())") @cached_property def branch(self): return self._exec_python(r"import platform; print(platform.python_branch())", default="???", exit_on_fail=False) @cached_property def revision(self): return self._exec_python(r"import platform; print(platform.python_revision())", default="???", exit_on_fail=False) @cached_property def build_date(self): return self._exec_python(r"import platform; print(platform.python_build()[1])") @cached_property def compiler(self): return self._exec_python(r"import platform; print(platform.python_compiler())") @cached_property def title(self): try: p = subprocess.Popen([self.python_interpreter, "-V"], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError: sys.exit("'%s' is not a valid Python interpreter" % self.python_interpreter) result = p.stderr.readlines() if result: return result[0].decode("utf-8").replace('\n', '') else: result = p.stdout.read() if result: return result.decode("utf-8").replace('\n', ' ') else: return "???" if __name__ == "__main__": parser = optparse.OptionParser( usage="%prog [options] [python]", description="""\ Describe the paths and implementation details of the environment of a Python installation.""" ) parser.add_option('-e', '--executable', action="store_true", help="show full path to Python interpreter executable and exit") parser.add_option('-v', '-V', '--version', action="store_true", help="show Python version and exit") parser.add_option('-p', '--prefix', action="store_true", help="show full path to Python installation prefix and exit") parser.add_option('-s', '--site-packages', action="store_true", help="show full path to Python site package directory and exit") parser.add_option('-d', '--build-date', action="store_true", help="show Python build information and exit") parser.add_option('-b', '--build-info', action="store_true", help="show Python build information and exit") opts, args = parser.parse_args() if len(args) == 0: pe = PythonEnvironment('python') else: pe = PythonEnvironment(args[0]) if opts.executable: print(pe.executable) elif opts.version: print(pe.version_short) elif opts.prefix: print(pe.prefix) elif opts.site_packages: print(pe.site_packages) elif opts.build_date: print(pe.build_date) elif opts.build_info: pe.prefetch() print("%s %s:%s built on %s by %s" % (pe.implementation, pe.branch, pe.revision, pe.build_date, pe.compiler)) else: pe.prefetch() print("[%s]"% (pe.title)) print(" Executable: %s" % (pe.executable)) print(" Version: %s" % (pe.version_short)) print("Installation Prefix: %s" % (pe.prefix)) print(" Site Packages: %s" % (pe.site_packages)) print(" Implementation: %s" % (pe.implementation)) print(" Branch: %s" % (pe.branch)) print(" Revision: %s" % (pe.revision)) print(" Compiler: %s" % (pe.compiler)) print(" Build Date: %s" % (pe.build_date))
| Attachment | Size |
|---|---|
| describe-python.py | 8.23 KB |
feed
Comments
3 comments postedPost new comment