LSSTApplications  11.0-13-gbb96280,12.1.rc1,12.1.rc1+1,12.1.rc1+2,12.1.rc1+5,12.1.rc1+8,12.1.rc1-1-g06d7636+1,12.1.rc1-1-g253890b+5,12.1.rc1-1-g3d31b68+7,12.1.rc1-1-g3db6b75+1,12.1.rc1-1-g5c1385a+3,12.1.rc1-1-g83b2247,12.1.rc1-1-g90cb4cf+6,12.1.rc1-1-g91da24b+3,12.1.rc1-2-g3521f8a,12.1.rc1-2-g39433dd+4,12.1.rc1-2-g486411b+2,12.1.rc1-2-g4c2be76,12.1.rc1-2-gc9c0491,12.1.rc1-2-gda2cd4f+6,12.1.rc1-3-g3391c73+2,12.1.rc1-3-g8c1bd6c+1,12.1.rc1-3-gcf4b6cb+2,12.1.rc1-4-g057223e+1,12.1.rc1-4-g19ed13b+2,12.1.rc1-4-g30492a7
LSSTDataManagementBasePackage
Classes | Functions | Variables
lsst.base.packages Namespace Reference

Classes

class  Packages
 

Functions

def getVersionFromPythonModule
 
def getPythonPackages
 
def getEnvironmentPackages
 

Variables

list __all__ = ["getVersionFromPythonModule", "getPythonPackages", "getEnvironmentPackages", "Packages"]
 
tuple BUILDTIME = set(["boost", "eigen", "tmv"])
 
tuple PYTHON = set(["galsim"])
 
tuple ENVIRONMENT = set(["astrometry_net", "astrometry_net_data", "minuit2", "xpa"])
 
 _eups = None
 

Detailed Description

Determine which packages are being used in the system and their versions

There are a few different types of packages, and their versions are collected in different ways:
1. Run-time libraries (e.g., cfitsio, fftw): we get their version from interrogating the dynamic library
2. Python modules (e.g., afw, numpy; galsim is also in this group even though we only use it through the
   library, because no version information is currently provided through the library): we get their version
   from the __version__ module variable. Note that this means that we're only aware of modules that have
   already been imported.
3. Other packages provide no run-time accessible version information (e.g., astrometry_net): we get their
   version from interrogating the environment. Currently, that means EUPS; if EUPS is replaced or dropped then
   we'll need to consider an alternative means of getting this version information.
4. Local versions of packages (a non-installed EUPS package, selected with "setup -r /path/to/package"): we
   identify these through the environment (EUPS again) and use as a version the path supplemented with the
   git SHA and, if the git repo isn't clean, an MD5 of the diff.

These package versions are collected and stored in a Packages object, which provides useful comparison and
persistence features.

Example usage:

    from lsst.base import Packages
    pkgs = Packages.fromSystem()
    print "Current packages:", pkgs
    old = Packages.read("/path/to/packages.pickle")
    print "Old packages:", old
    print "Missing packages compared to before:", pkgs.missing(old)
    print "Extra packages compared to before:", pkgs.extra(old)
    print "Different packages: ", pkgs.difference(old)
    old.update(pkgs)  # Include any new packages in the old
    old.write("/path/to/packages.pickle")

Function Documentation

def lsst.base.packages.getEnvironmentPackages ( )
Provide a dict of products and their versions from the environment

We use EUPS to determine the version of certain products (those that don't provide
a means to determine the version any other way) and to check if uninstalled packages
are being used. We only report the product/version for these packages.

Definition at line 131 of file packages.py.

133  """Provide a dict of products and their versions from the environment
134 
135  We use EUPS to determine the version of certain products (those that don't provide
136  a means to determine the version any other way) and to check if uninstalled packages
137  are being used. We only report the product/version for these packages.
138  """
139  try:
140  from eups import Eups
141  from eups.Product import Product
142  except:
143  from lsst.pex.logging import getDefaultLog
144  getDefaultLog().warn("Unable to import eups, so cannot determine package versions from environment")
145  return {}
146 
147  # Cache eups object since creating it can take a while
148  global _eups
149  if not _eups:
150  _eups = Eups()
151  products = _eups.findProducts(tags=["setup"])
152 
153  # Get versions for things we can't determine via runtime mechanisms
154  # XXX Should we just grab everything we can, rather than just a predetermined set?
155  packages = {prod.name: prod.version for prod in products if prod in ENVIRONMENT}
156 
157  # The string 'LOCAL:' (the value of Product.LocalVersionPrefix) in the version name indicates uninstalled
158  # code, so the version could be different than what's being reported by the runtime environment (because
159  # we don't tend to run "scons" every time we update some python file, and even if we did sconsUtils
160  # probably doesn't check to see if the repo is clean).
161  for prod in products:
162  if not prod.version.startswith(Product.LocalVersionPrefix):
163  continue
164  ver = prod.version
165 
166  gitDir = os.path.join(prod.dir, ".git")
167  if os.path.exists(gitDir):
168  # get the git revision and an indication if the working copy is clean
169  revCmd = ["git", "--git-dir=" + gitDir, "--work-tree=" + prod.dir, "rev-parse", "HEAD"]
170  diffCmd = ["git", "--no-pager", "--git-dir=" + gitDir, "--work-tree=" + prod.dir, "diff",
171  "--patch"]
172  try:
173  rev = subprocess.check_output(revCmd).decode().strip()
174  diff = subprocess.check_output(diffCmd)
175  except:
176  ver += "@GIT_ERROR"
177  else:
178  ver += "@" + rev
179  if diff:
180  ver += "+" + hashlib.md5(diff).hexdigest()
181  else:
182  ver += "@NO_GIT"
183 
184  packages[prod.name] = ver
185  return packages
186 
def getEnvironmentPackages
Definition: packages.py:131
def warn
Definition: log.py:99
def lsst.base.packages.getPythonPackages ( )
Return a dict of imported python packages and their versions

We wade through sys.modules and attempt to determine the version for each
module.  Note, therefore, that we can only report on modules that have
*already* been imported.

We don't include any module for which we cannot determine a version.

Definition at line 81 of file packages.py.

81 
82 def getPythonPackages():
83  """Return a dict of imported python packages and their versions
84 
85  We wade through sys.modules and attempt to determine the version for each
86  module. Note, therefore, that we can only report on modules that have
87  *already* been imported.
88 
89  We don't include any module for which we cannot determine a version.
90  """
91  # Attempt to import libraries that only report their version in python
92  for module in PYTHON:
93  try:
94  importlib.import_module(module)
95  except:
96  pass # It's not available, so don't care
97 
98  packages = {"python": sys.version}
99  # Not iterating with sys.modules.iteritems() because it's not atomic and subject to race conditions
100  moduleNames = list(sys.modules.keys())
101  for name in moduleNames:
102  module = sys.modules[name]
103  try:
104  ver = getVersionFromPythonModule(module)
105  except:
106  continue # Can't get a version from it, don't care
107 
108  # Remove "foo.bar.version" in favor of "foo.bar"
109  # This prevents duplication when the __init__.py includes "from .version import *"
110  found = False
111  for ending in (".version", "._version"):
112  if name.endswith(ending):
113  name = name[:-len(ending)]
114  if name in packages:
115  assert ver == packages[name]
116  found = True
117  elif name in packages:
118  assert ver == packages[name]
119 
120  # Use LSST package names instead of python module names
121  # This matches the names we get from the environment (i.e., EUPS) so we can clobber these build-time
122  # versions if the environment reveals that we're not using the packages as-built.
123  if "lsst" in name:
124  name = name.replace("lsst.", "").replace(".", "_")
125 
126  packages[name] = ver
127 
128  return packages
129 
def getVersionFromPythonModule
Definition: packages.py:62
def lsst.base.packages.getVersionFromPythonModule (   module)
Determine the version of a python module

Will raise AttributeError if the __version__ attribute is not set.

We supplement the version with information from the __dependency_versions__
(a specific variable set by LSST's sconsUtils at build time) only for packages
that are typically used only at build-time.

Definition at line 62 of file packages.py.

62 
63 def getVersionFromPythonModule(module):
64  """Determine the version of a python module
65 
66  Will raise AttributeError if the __version__ attribute is not set.
67 
68  We supplement the version with information from the __dependency_versions__
69  (a specific variable set by LSST's sconsUtils at build time) only for packages
70  that are typically used only at build-time.
71  """
72  version = module.__version__
73  if hasattr(module, "__dependency_versions__"):
74  # Add build-time dependencies
75  deps = module.__dependency_versions__
76  buildtime = BUILDTIME & set(deps.keys())
77  if buildtime:
78  version += " with " + " ".join("%s=%s" % (pkg, deps[pkg]) for pkg in buildtime)
79  return version
80 
def getVersionFromPythonModule
Definition: packages.py:62

Variable Documentation

list lsst.base.packages.__all__ = ["getVersionFromPythonModule", "getPythonPackages", "getEnvironmentPackages", "Packages"]

Definition at line 47 of file packages.py.

lsst.base.packages._eups = None

Definition at line 130 of file packages.py.

tuple lsst.base.packages.BUILDTIME = set(["boost", "eigen", "tmv"])

Definition at line 51 of file packages.py.

tuple lsst.base.packages.ENVIRONMENT = set(["astrometry_net", "astrometry_net_data", "minuit2", "xpa"])

Definition at line 59 of file packages.py.

tuple lsst.base.packages.PYTHON = set(["galsim"])

Definition at line 55 of file packages.py.