[zorg] r323937 - Support for checking pip packages

Chris Matthews via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 31 16:33:16 PST 2018


Author: cmatthews
Date: Wed Jan 31 16:33:16 2018
New Revision: 323937

URL: http://llvm.org/viewvc/llvm-project?rev=323937&view=rev
Log:
Support for checking pip packages

Added:
    zorg/trunk/dep/tests/assets/pip_output.json
Modified:
    zorg/trunk/dep/dep.py
    zorg/trunk/dep/tests/test_dep.py

Modified: zorg/trunk/dep/dep.py
URL: http://llvm.org/viewvc/llvm-project/zorg/trunk/dep/dep.py?rev=323937&r1=323936&r2=323937&view=diff
==============================================================================
--- zorg/trunk/dep/dep.py (original)
+++ zorg/trunk/dep/dep.py Wed Jan 31 16:33:16 2018
@@ -502,11 +502,71 @@ class Sdk(Dependency):
         return "{} {}".format(self.str_kind, self.version)
 
 
+class Pip(Dependency):
+    """Verify and Inject pip package dependencies."""
+
+    # pip <package> <operator> <version>.  Operator may not have spaces around it.
+    pip_re = re.compile(r'(?P<command>\w+)\s+(?P<package>\w+)\s*(?P<operator>>=|<=|==)\s*(?P<version_text>[\d.-_]+)')
+
+    def __init__(self, line, kind):
+        # type: (Line, Text) -> None
+        """Parse and verify pip package is installed.
+
+        :param line: the Line with the deceleration of the dependency.
+        :param kind: the detected dependency kind.
+        """
+        super(Pip, self).__init__(line, kind)
+        self.command = None
+        self.operator = None
+        self.package = None
+        self.version = None
+        self.version_text = None
+        self.installed_version = None
+
+    def parse(self):
+        """Parse this dependency."""
+        text = self.line.text
+        match = self.pip_re.match(text)
+        if not match:
+            raise MalformedDependency("Expression does not compile in {}: {}".format(self.__class__.__name__,
+                                                                                     self.line))
+        self.__dict__.update(match.groupdict())
+
+        self.version = Version(self.version_text)
+
+    def verify(self):
+        """Verify the packages in pip match this dependency."""
+        try:
+            pip_package_config = json.loads(subprocess.check_output(["/usr/bin/env",
+                                                                     "python", "-m", "pip", "list", "--format=json"]))
+        except (subprocess.CalledProcessError, OSError):
+            raise MissingDependencyError(self, "Cannot find pip")
+
+        installed = {p['name']: p['version'] for p in pip_package_config}  # type: Dict[Text, Text]
+
+        package = installed.get(self.package)
+
+        if not package:
+            # The package is not installed at all.
+            raise MissingDependencyError(self, "not in package list")
+        self.installed_version = Version(package)
+        return check_version(self.installed_version, self.operator, self.version)
+
+    def inject(self):
+        """Not implemented."""
+        raise NotImplementedError()
+
+    def __str__(self):
+        """Dependency kind, package and version, for printing in error messages."""
+        return "{} {} {}".format(self.str_kind, self.package, self.version)
+
+
 dependencies_implementations = {'brew': Brew,
                                 'os_version': HostOSVersion,
                                 'config_manager': ConMan,
                                 'xcode': Xcode,
                                 'sdk': Sdk,
+                                'pip': Pip,
                                 }
 
 

Added: zorg/trunk/dep/tests/assets/pip_output.json
URL: http://llvm.org/viewvc/llvm-project/zorg/trunk/dep/tests/assets/pip_output.json?rev=323937&view=auto
==============================================================================
--- zorg/trunk/dep/tests/assets/pip_output.json (added)
+++ zorg/trunk/dep/tests/assets/pip_output.json Wed Jan 31 16:33:16 2018
@@ -0,0 +1,422 @@
+[
+  {
+    "version": "0.10.2",
+    "name": "altgraph"
+  },
+  {
+    "version": "1.2.0",
+    "name": "aniso8601"
+  },
+  {
+    "version": "0.24.0",
+    "name": "asn1crypto"
+  },
+  {
+    "version": "17.3.0",
+    "name": "attrs"
+  },
+  {
+    "version": "1.4",
+    "name": "backports.functools-lru-cache"
+  },
+  {
+    "version": "3.1.4",
+    "name": "bcrypt"
+  },
+  {
+    "version": "0.5.0",
+    "name": "bdist-mpkg"
+  },
+  {
+    "version": "0.3",
+    "name": "bonjour-py"
+  },
+  {
+    "version": "1.11.2",
+    "name": "cffi"
+  },
+  {
+    "version": "6.7",
+    "name": "click"
+  },
+  {
+    "version": "0.5.5",
+    "name": "contextlib2"
+  },
+  {
+    "version": "1.0",
+    "name": "CoreNLP"
+  },
+  {
+    "version": "2.1.4",
+    "name": "cryptography"
+  },
+  {
+    "version": "1.1.6",
+    "name": "enum34"
+  },
+  {
+    "version": "1.14.0",
+    "name": "Fabric"
+  },
+  {
+    "version": "0.12.2",
+    "name": "Flask"
+  },
+  {
+    "version": "0.3.4",
+    "name": "Flask-RESTful"
+  },
+  {
+    "version": "0.12",
+    "name": "Flask-WTF"
+  },
+  {
+    "version": "1.0.2",
+    "name": "funcsigs"
+  },
+  {
+    "version": "2.6",
+    "name": "idna"
+  },
+  {
+    "version": "0.2.5",
+    "name": "inflect"
+  },
+  {
+    "version": "1.0.19",
+    "name": "ipaddress"
+  },
+  {
+    "version": "16.1",
+    "name": "irc"
+  },
+  {
+    "version": "0.24",
+    "name": "itsdangerous"
+  },
+  {
+    "version": "1.4.3",
+    "name": "jaraco.classes"
+  },
+  {
+    "version": "1.5.2",
+    "name": "jaraco.collections"
+  },
+  {
+    "version": "1.17",
+    "name": "jaraco.functools"
+  },
+  {
+    "version": "2.1",
+    "name": "jaraco.itertools"
+  },
+  {
+    "version": "1.5",
+    "name": "jaraco.logging"
+  },
+  {
+    "version": "1.1.2",
+    "name": "jaraco.stream"
+  },
+  {
+    "version": "1.9.2",
+    "name": "jaraco.text"
+  },
+  {
+    "version": "2.10",
+    "name": "Jinja2"
+  },
+  {
+    "version": "1.0",
+    "name": "LanguageModeling"
+  },
+  {
+    "version": "0.6.0.dev0",
+    "name": "lit"
+  },
+  {
+    "version": "0.4.2.dev0",
+    "name": "LNT"
+  },
+  {
+    "version": "1.5.1",
+    "name": "macholib"
+  },
+  {
+    "version": "1.0",
+    "name": "MarkupSafe"
+  },
+  {
+    "version": "1.3.1",
+    "name": "matplotlib"
+  },
+  {
+    "version": "2.0.0",
+    "name": "mock"
+  },
+  {
+    "version": "0.10.4",
+    "name": "modulegraph"
+  },
+  {
+    "version": "4.0.1",
+    "name": "more-itertools"
+  },
+  {
+    "version": "1.8.0rc1",
+    "name": "numpy"
+  },
+  {
+    "version": "2.4.0",
+    "name": "paramiko"
+  },
+  {
+    "version": "3.1.1",
+    "name": "pbr"
+  },
+  {
+    "version": "9.0.1",
+    "name": "pip"
+  },
+  {
+    "version": "0.6.0",
+    "name": "pluggy"
+  },
+  {
+    "version": "1.5.2",
+    "name": "py"
+  },
+  {
+    "version": "0.7.3",
+    "name": "py2app"
+  },
+  {
+    "version": "0.4.2",
+    "name": "pyasn1"
+  },
+  {
+    "version": "2.18",
+    "name": "pycparser"
+  },
+  {
+    "version": "1.2.1",
+    "name": "PyNaCl"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-core"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-Accounts"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-AddressBook"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-AppleScriptKit"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-AppleScriptObjC"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-Automator"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-CFNetwork"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-Cocoa"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-Collaboration"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-CoreData"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-CoreLocation"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-CoreText"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-DictionaryServices"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-EventKit"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-ExceptionHandling"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-FSEvents"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-InputMethodKit"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-InstallerPlugins"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-InstantMessage"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-LatentSemanticMapping"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-LaunchServices"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-Message"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-OpenDirectory"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-PreferencePanes"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-PubSub"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-QTKit"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-Quartz"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-ScreenSaver"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-ScriptingBridge"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-SearchKit"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-ServiceManagement"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-Social"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-SyncServices"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-SystemConfiguration"
+  },
+  {
+    "version": "2.5.1",
+    "name": "pyobjc-framework-WebKit"
+  },
+  {
+    "version": "0.13.1",
+    "name": "pyOpenSSL"
+  },
+  {
+    "version": "2.0.1",
+    "name": "pyparsing"
+  },
+  {
+    "version": "3.3.1",
+    "name": "pytest"
+  },
+  {
+    "version": "1.6.3",
+    "name": "pytest-mock"
+  },
+  {
+    "version": "1.5",
+    "name": "python-dateutil"
+  },
+  {
+    "version": "0.3.7",
+    "name": "python-gnupg"
+  },
+  {
+    "version": "2013.7",
+    "name": "pytz"
+  },
+  {
+    "version": "3.12",
+    "name": "PyYAML"
+  },
+  {
+    "version": "6.4.0",
+    "name": "raven"
+  },
+  {
+    "version": "0.13.0b1",
+    "name": "scipy"
+  },
+  {
+    "version": "38.2.4",
+    "name": "setuptools"
+  },
+  {
+    "version": "1.11.0",
+    "name": "six"
+  },
+  {
+    "version": "1.1.11",
+    "name": "SQLAlchemy"
+  },
+  {
+    "version": "1.9",
+    "name": "tempora"
+  },
+  {
+    "version": "3.6.2",
+    "name": "typing"
+  },
+  {
+    "version": "0.12.2",
+    "name": "Werkzeug"
+  },
+  {
+    "version": "2.0.2",
+    "name": "WTForms"
+  },
+  {
+    "version": "0.6.4",
+    "name": "xattr"
+  },
+  {
+    "version": "4.1.1",
+    "name": "zope.interface"
+  }
+]
\ No newline at end of file

Modified: zorg/trunk/dep/tests/test_dep.py
URL: http://llvm.org/viewvc/llvm-project/zorg/trunk/dep/tests/test_dep.py?rev=323937&r1=323936&r2=323937&view=diff
==============================================================================
--- zorg/trunk/dep/tests/test_dep.py (original)
+++ zorg/trunk/dep/tests/test_dep.py Wed Jan 31 16:33:16 2018
@@ -7,6 +7,7 @@ import json
 import os
 import sys
 import pytest
+import subprocess
 
 import dep
 from dep import Line, Brew, Version, MissingDependencyError, ConMan, HostOSVersion, Xcode, Sdk
@@ -189,36 +190,64 @@ def test_sdk_version_requirement(mocker)
     b.verify_and_act()
 
     line = Line("foo.c", 10, "sdk iphoneos == 2.0", "test")
-    bad = Sdk(line, "sdk")
+    bad = dep.Sdk(line, "sdk")
     bad.parse()
     with pytest.raises(MissingDependencyError):
         bad.verify_and_act()
 
-    b = Sdk(Line("foo.c", 11, "sdk iphoneos == 1.0", "test"), "sdk")
+    b = dep.Sdk(Line("foo.c", 11, "sdk iphoneos == 1.0", "test"), "sdk")
     b.parse()
     b.verify_and_act()
 
-    b = Sdk(Line("foo.c", 11, "sdk iphoneos <= 1.0", "test"), "sdk")
+    b = dep.Sdk(Line("foo.c", 11, "sdk iphoneos <= 1.0", "test"), "sdk")
     b.parse()
     b.verify_and_act()
 
-    b = Sdk(Line("foo.c", 11, "sdk iphonesimulator <= 1.0", "test"), "sdk")
+    b = dep.Sdk(Line("foo.c", 11, "sdk iphonesimulator <= 1.0", "test"), "sdk")
     b.parse()
     b.verify_and_act()
 
-    b = Sdk(Line("foo.c", 11, "sdk iwash == 1.0", "test"), "sdk")
+    b = dep.Sdk(Line("foo.c", 11, "sdk iwash == 1.0", "test"), "sdk")
     b.parse()
     # TODO handle unversioned SDKs.
     with pytest.raises(MissingDependencyError):
         b.verify_and_act()
 
-    b = Sdk(Line("foo.c", 11, "sdk macosx == 10.12", "test"), "sdk")
+    b = dep.Sdk(Line("foo.c", 11, "sdk macosx == 10.12", "test"), "sdk")
     b.parse()
     b.verify_and_act()
 
-    b = Sdk(Line("foo.c", 11, "sdk macosx == 10.11", "test"), "sdk")
+    b = dep.Sdk(Line("foo.c", 11, "sdk macosx == 10.11", "test"), "sdk")
     b.parse()
     b.verify_and_act()
 
 
+def test_pip_requirement(mocker):
+    """Detailed check of a pip packages dependency."""
+    line = Line("foo.c", 10, "pip pytest <= 3.3.1", "test")
 
+    b = dep.Pip(line, "pip")
+    b.parse()
+    assert b.operator == "<="
+    assert b.command == "pip"
+    assert b.package == "pytest"
+    assert b.version_text == "3.3.1"
+    mocker.patch('dep.subprocess.check_output')
+    dep.subprocess.check_output.return_value = open(here + '/assets/pip_output.json').read()
+    b.verify_and_act()
+    assert dep.subprocess.check_output.called
+
+    b = dep.Pip(Line("foo.c", 10, "pip pytest == 3.3.1", "test"), "pip")
+    b.parse()
+    b.verify_and_act()
+
+    b = dep.Pip(Line("foo.c", 10, "pip pytest <= 3.3.0", "test"), "pip")
+    b.parse()
+    with pytest.raises(MissingDependencyError):
+        b.verify_and_act()
+
+    mocker.patch('dep.subprocess.check_output')
+    no_pip = "/usr/bin/python: No module named pip"
+    dep.subprocess.check_output.side_effect = subprocess.CalledProcessError(1, [], output=no_pip)
+    with pytest.raises(MissingDependencyError):
+        b.verify_and_act()




More information about the llvm-commits mailing list