Hello community,
here is the log from the commit of package python-requirements-detector for
openSUSE:Factory checked in at 2015-05-16 19:01:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-requirements-detector (Old)
and /work/SRC/openSUSE:Factory/.python-requirements-detector.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-requirements-detector"
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-requirements-detector/python-requirements-detector.changes
2014-01-23 15:54:42.000000000 +0100
+++
/work/SRC/openSUSE:Factory/.python-requirements-detector.new/python-requirements-detector.changes
2015-05-16 19:01:50.000000000 +0200
@@ -1,0 +2,6 @@
+Tue May 12 14:22:20 UTC 2015 - [email protected]
+
+- update to version 0.4:
+ * no changelog available
+
+-------------------------------------------------------------------
Old:
----
requirements-detector-0.1.1.tar.gz
New:
----
requirements-detector-0.4.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-requirements-detector.spec ++++++
--- /var/tmp/diff_new_pack.wDojQR/_old 2015-05-16 19:01:51.000000000 +0200
+++ /var/tmp/diff_new_pack.wDojQR/_new 2015-05-16 19:01:51.000000000 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-requirements-detector
#
-# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
+# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
Name: python-requirements-detector
-Version: 0.1.1
+Version: 0.4
Release: 0
Summary: Python tool to find and list requirements of a Python project
License: MIT
++++++ requirements-detector-0.1.1.tar.gz -> requirements-detector-0.4.tar.gz
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/requirements-detector-0.1.1/PKG-INFO
new/requirements-detector-0.4/PKG-INFO
--- old/requirements-detector-0.1.1/PKG-INFO 2013-10-26 17:50:56.000000000
+0200
+++ new/requirements-detector-0.4/PKG-INFO 2015-03-24 07:41:47.000000000
+0100
@@ -1,6 +1,6 @@
-Metadata-Version: 1.0
+Metadata-Version: 1.1
Name: requirements-detector
-Version: 0.1.1
+Version: 0.4
Summary: Python tool to find and list requirements of a Python project
Home-page: https://github.com/landscapeio/requirements-detector
Author: landscape.io
@@ -9,3 +9,12 @@
Description: UNKNOWN
Keywords: python requirements detector
Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Intended Audience :: Developers
+Classifier: Operating System :: Unix
+Classifier: Topic :: Software Development :: Quality Assurance
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3.3
+Classifier: License :: OSI Approved :: GNU General Public License v2 or later
(GPLv2+)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/requirements-detector-0.1.1/requirements_detector/detect.py
new/requirements-detector-0.4/requirements_detector/detect.py
--- old/requirements-detector-0.1.1/requirements_detector/detect.py
2013-10-26 17:48:58.000000000 +0200
+++ new/requirements-detector-0.4/requirements_detector/detect.py
2015-03-23 23:06:42.000000000 +0100
@@ -1,14 +1,21 @@
import re
import os
+import sys
from astroid.builder import AstroidBuilder
from astroid import MANAGER, CallFunc, Name, Assign, Keyword, List, Tuple,
Const, AssName
from requirements_detector.requirement import DetectedRequirement
-__all__ = ['find_dependencies',
+__all__ = ['find_requirements',
'RequirementsNotFound',
- 'CouldNotParseRequirements',
- 'get_prospector_profiles']
+ 'CouldNotParseRequirements']
+
+
+# PEP263, see http://legacy.python.org/dev/peps/pep-0263/
+_ENCODING_REGEXP = re.compile(r'coding[:=]\s*([-\w.]+)')
+
+
+_PY3K = sys.version_info >= (3, 0)
_PIP_OPTIONS = (
@@ -28,6 +35,34 @@
pass
+def _load_file_contents(filepath):
+ # This function is a bit of a tedious workaround (AKA 'hack').
+ # Astroid calls 'compile' under the hood, which refuses to accept a Unicode
+ # object which contains a PEP-263 encoding definition. However if we give
+ # Astroid raw bytes, it'll assume ASCII. Therefore we need to detect the
encoding
+ # here, convert the file contents to a Unicode object, *and also strip the
encoding
+ # declaration* to avoid the compile step breaking.
+ with open(filepath) as f:
+ if _PY3K:
+ return f.read()
+
+ contents = f.readlines()
+
+ result = []
+ encoding_lines = contents[0:2]
+ encoding = 'utf-8'
+ for line in encoding_lines:
+ match = _ENCODING_REGEXP.search(line)
+ if match is None:
+ result.append(line)
+ else:
+ encoding = match.group(1)
+
+ result += contents[2:]
+ result = '\n'.join(result)
+ return result.decode(encoding)
+
+
def find_requirements(path):
"""
This method tries to determine the requirements of a particular project
@@ -36,7 +71,7 @@
It will attempt, in order:
1) to parse setup.py in the root for an install_requires value
- 2) to read a requirements.txt file in the root
+ 2) to read a requirements.txt file or a requirements.pip in the root
3) to read all .txt files in a folder called 'requirements' in the root
4) to read files matching "*requirements*.txt" and "*reqs*.txt" in the
root,
excluding any starting or ending with 'test'
@@ -45,29 +80,38 @@
will be returned. If none can be found, then a RequirementsNotFound
will be raised
"""
+ requirements = []
setup_py = os.path.join(path, 'setup.py')
if os.path.exists(setup_py) and os.path.isfile(setup_py):
try:
- return from_setup_py(setup_py)
+ requirements = from_setup_py(setup_py)
+ requirements.sort()
+ return requirements
except CouldNotParseRequirements:
pass
- requirements_txt = os.path.join(path, 'requirements.txt')
- if os.path.exists(requirements_txt) and os.path.isfile(requirements_txt):
- try:
- return from_requirements_txt(requirements_txt)
- except CouldNotParseRequirements:
- pass
+ for reqfile_name in ('requirements.txt', 'requirements.pip'):
+ reqfile_path = os.path.join(path, reqfile_name)
+ if os.path.exists(reqfile_path) and os.path.isfile(reqfile_path):
+ try:
+ requirements += from_requirements_txt(reqfile_path)
+ except CouldNotParseRequirements as e:
+ pass
requirements_dir = os.path.join(path, 'requirements')
if os.path.exists(requirements_dir) and os.path.isdir(requirements_dir):
- requirements = from_requirements_dir(requirements_dir)
- if requirements:
- return requirements
-
- requirements = from_requirements_blob(path)
- if requirements:
+ from_dir = from_requirements_dir(requirements_dir)
+ if from_dir is not None:
+ requirements += from_dir
+
+ from_blob = from_requirements_blob(path)
+ if from_blob is not None:
+ requirements += from_blob
+
+ requirements = list(set(requirements))
+ if len(requirements) > 0:
+ requirements.sort()
return requirements
raise RequirementsNotFound
@@ -108,23 +152,26 @@
values.append(child_node.value)
return values
- def get_install_requires(self):
+ def get_requires(self):
# first, if we have a call to setup, then we can see what its
"install_requires" argument is
if not self._setup_call:
raise CouldNotParseRequirements
+ found_requirements = []
+
for child_node in self._setup_call.get_children():
if not isinstance(child_node, Keyword):
# do we want to try to handle positional arguments?
continue
- if child_node.arg != 'install_requires':
+ if child_node.arg not in ('install_requires', 'requires'):
continue
if isinstance(child_node.value, (List, Tuple)):
# joy! this is a simple list or tuple of requirements
# this is a Keyword -> List or Keyword -> Tuple
- return self._get_list_value(child_node.value)
+ found_requirements += self._get_list_value(child_node.value)
+ continue
if isinstance(child_node.value, Name):
# otherwise, it's referencing a value defined elsewhere
@@ -135,26 +182,33 @@
raise CouldNotParseRequirements
else:
if isinstance(reqs, (List, Tuple)):
- return self._get_list_value(reqs)
+ found_requirements += self._get_list_value(reqs)
+ continue
# otherwise it's something funky and we can't handle it
raise CouldNotParseRequirements
- # if we've fallen off the bottom, we simply didn't find anything useful
+ # if we've fallen off the bottom with nothing in our list of
requirements,
+ # we simply didn't find anything useful
+ if len(found_requirements) > 0:
+ return found_requirements
raise CouldNotParseRequirements
def from_setup_py(setup_file):
- with open(setup_file) as f:
- ast = AstroidBuilder(MANAGER).string_build(f.read())
+ try:
+ contents = _load_file_contents(setup_file)
+ ast = AstroidBuilder(MANAGER).string_build(contents)
+ except SyntaxError:
+ # if the setup file is broken, we can't do much about that...
+ raise CouldNotParseRequirements
walker = SetupWalker(ast)
requirements = []
- for req in walker.get_install_requires():
- requirements.append(DetectedRequirement.parse(req))
+ for req in walker.get_requires():
+ requirements.append(DetectedRequirement.parse(req, setup_file))
- requirements.sort(key=lambda r: r.name)
return requirements
@@ -172,9 +226,11 @@
if req.strip().split()[0] in _PIP_OPTIONS:
# this is a pip option
continue
- requirements.append(DetectedRequirement.parse(req))
+ detected = DetectedRequirement.parse(req, requirements_file)
+ if detected is None:
+ continue
+ requirements.append(detected)
- requirements.sort(key=lambda r: r.name)
return requirements
@@ -182,11 +238,12 @@
requirements = []
for entry in os.listdir(path):
filepath = os.path.join(path, entry)
- if os.path.isfile(filepath) and entry.endswith('.txt'):
+ if not os.path.isfile(filepath):
+ continue
+ if entry.endswith('.txt') or entry.endswith('.pip'):
# TODO: deal with duplicates
requirements += from_requirements_txt(filepath)
- requirements.sort(key=lambda r: r.name)
return requirements
@@ -204,5 +261,4 @@
continue
requirements += from_requirements_txt(filepath)
- requirements.sort(key=lambda r: r.name)
- return requirements
\ No newline at end of file
+ return requirements
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/requirements-detector-0.1.1/requirements_detector/formatters.py
new/requirements-detector-0.4/requirements_detector/formatters.py
--- old/requirements-detector-0.1.1/requirements_detector/formatters.py
2013-10-17 11:04:16.000000000 +0200
+++ new/requirements-detector-0.4/requirements_detector/formatters.py
2014-08-21 19:28:36.000000000 +0200
@@ -4,7 +4,7 @@
def requirements_file(requirements_list):
for requirement in requirements_list:
- sys.stdout.write(str(requirement))
+ sys.stdout.write(requirement.pip_format())
sys.stdout.write('\n')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/requirements-detector-0.1.1/requirements_detector/requirement.py
new/requirements-detector-0.4/requirements_detector/requirement.py
--- old/requirements-detector-0.1.1/requirements_detector/requirement.py
2013-10-19 16:33:02.000000000 +0200
+++ new/requirements-detector-0.4/requirements_detector/requirement.py
2015-03-23 23:11:24.000000000 +0100
@@ -10,9 +10,14 @@
"""
import os
import re
-import urlparse
from pkg_resources import Requirement
+try:
+ import urlparse
+except ImportError:
+ # python3
+ from urllib import parse as urlparse
+
def _is_filepath(req):
# this is (probably) a file
@@ -48,7 +53,7 @@
class DetectedRequirement(object):
- def __init__(self, name=None, url=None, requirement=None):
+ def __init__(self, name=None, url=None, requirement=None,
location_defined=None):
if requirement is not None:
self.name = requirement.key
self.requirement = requirement
@@ -59,6 +64,20 @@
self.version_specs = []
self.url = url
self.requirement = None
+ self.location_defined = location_defined
+
+ def _format_specs(self):
+ return ','.join(['%s%s' % (comp, version) for comp, version in
self.version_specs])
+
+ def pip_format(self):
+ if self.url:
+ if self.name:
+ return '%s#egg=%s' % (self.url, self.name)
+ return self.url
+ if self.name:
+ if self.version_specs:
+ return "%s%s" % (self.name, self._format_specs())
+ return self.name
def __str__(self):
rep = self.name or 'Unknown'
@@ -69,14 +88,20 @@
rep = '%s (%s)' % (rep, self.url)
return rep
+ def __hash__(self):
+ return hash(str(self.name) + str(self.url) + str(self.version_specs))
+
def __repr__(self):
return 'DetectedRequirement:%s' % str(self)
def __eq__(self, other):
return self.name == other.name and self.url == other.url and
self.version_specs == other.version_specs
+ def __gt__(self, other):
+ return (self.name or "") > (other.name or "")
+
@staticmethod
- def parse(line):
+ def parse(line, location_defined=None):
# the options for a Pip requirements file are:
#
# 1) <dependency_name>
@@ -96,14 +121,22 @@
# if it is a VCS URL, then we want to strip off the protocol as
urlparse
# might not handle it correctly
vcs_scheme = None
- if '+' in url.scheme:
- vcs_scheme = url.scheme
+ if '+' in url.scheme or url.scheme in ('git',):
+ if url.scheme == 'git':
+ vcs_scheme = 'git+git'
+ else:
+ vcs_scheme = url.scheme
url = urlparse.urlparse(re.sub(r'^%s://' % re.escape(url.scheme),
'', line))
if vcs_scheme is None and url.scheme == '' and not _is_filepath(line):
# if we are here, it is a simple dependency
- req = Requirement.parse(line)
- return DetectedRequirement(requirement=req)
+ try:
+ req = Requirement.parse(line)
+ except ValueError:
+ # this happens if the line is invalid
+ return None
+ else:
+ return DetectedRequirement(requirement=req,
location_defined=location_defined)
# otherwise, this is some kind of URL
name = _parse_egg_name(url.fragment)
@@ -112,4 +145,4 @@
if vcs_scheme:
url = '%s://%s' % (vcs_scheme, url)
- return DetectedRequirement(name=name, url=url)
\ No newline at end of file
+ return DetectedRequirement(name=name, url=url,
location_defined=location_defined)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/requirements-detector-0.1.1/requirements_detector.egg-info/PKG-INFO
new/requirements-detector-0.4/requirements_detector.egg-info/PKG-INFO
--- old/requirements-detector-0.1.1/requirements_detector.egg-info/PKG-INFO
2013-10-26 17:50:56.000000000 +0200
+++ new/requirements-detector-0.4/requirements_detector.egg-info/PKG-INFO
2015-03-24 07:41:47.000000000 +0100
@@ -1,6 +1,6 @@
-Metadata-Version: 1.0
+Metadata-Version: 1.1
Name: requirements-detector
-Version: 0.1.1
+Version: 0.4
Summary: Python tool to find and list requirements of a Python project
Home-page: https://github.com/landscapeio/requirements-detector
Author: landscape.io
@@ -9,3 +9,12 @@
Description: UNKNOWN
Keywords: python requirements detector
Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Intended Audience :: Developers
+Classifier: Operating System :: Unix
+Classifier: Topic :: Software Development :: Quality Assurance
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3.3
+Classifier: License :: OSI Approved :: GNU General Public License v2 or later
(GPLv2+)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/requirements-detector-0.1.1/requirements_detector.egg-info/requires.txt
new/requirements-detector-0.4/requirements_detector.egg-info/requires.txt
--- old/requirements-detector-0.1.1/requirements_detector.egg-info/requires.txt
2013-10-26 17:50:56.000000000 +0200
+++ new/requirements-detector-0.4/requirements_detector.egg-info/requires.txt
2015-03-24 07:41:47.000000000 +0100
@@ -1 +1 @@
-astroid>=1.0.0
\ No newline at end of file
+astroid>=1.0.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/requirements-detector-0.1.1/setup.py
new/requirements-detector-0.4/setup.py
--- old/requirements-detector-0.1.1/setup.py 2013-10-26 17:50:46.000000000
+0200
+++ new/requirements-detector-0.4/setup.py 2015-03-23 23:11:11.000000000
+0100
@@ -3,11 +3,24 @@
from setuptools import find_packages
-_version = "0.1.1"
+_version = "0.4"
_packages = find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"])
_short_description = "Python tool to find and list requirements of a Python
project"
+_CLASSIFIERS = (
+ 'Development Status :: 5 - Production/Stable',
+ 'Environment :: Console',
+ 'Intended Audience :: Developers',
+ 'Operating System :: Unix',
+ 'Topic :: Software Development :: Quality Assurance',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3.3',
+ 'License :: OSI Approved :: '
+ 'GNU General Public License v2 or later (GPLv2+)',
+)
+
setup(
name='requirements-detector',
@@ -21,4 +34,5 @@
packages=_packages,
license='MIT',
keywords='python requirements detector',
+ classifiers=_CLASSIFIERS,
)