[Python-modules-commits] [python-requirements-detector] 01/02: Imported Upstream version 0.4
Daniel Stender
danstender-guest at moszumanska.debian.org
Sun Jun 21 13:59:11 UTC 2015
This is an automated email from the git hooks/post-receive script.
danstender-guest pushed a commit to branch master
in repository python-requirements-detector.
commit 8c55f2d702fdf78aed1c4ecee474d96d7098eee2
Author: Daniel Stender <debian at danielstender.com>
Date: Sun Jun 21 15:53:09 2015 +0200
Imported Upstream version 0.4
---
.coveragerc | 3 +
.gitignore | 35 +++
.landscape.yaml | 4 +
.travis.yml | 13 +
LICENSE | 21 ++
MANIFEST.in | 1 +
README.md | 49 ++++
bin/detect-requirements | 3 +
requirements_detector/__init__.py | 1 +
requirements_detector/detect.py | 264 +++++++++++++++++++++
requirements_detector/formatters.py | 13 +
requirements_detector/requirement.py | 148 ++++++++++++
requirements_detector/run.py | 36 +++
setup.py | 38 +++
tests/__init__.py | 0
tests/detection/syntax_error/setup.py | 10 +
tests/detection/test1/requirements.txt | 6 +
tests/detection/test2/requirements/base.txt | 2 +
tests/detection/test2/requirements/webui.pip | 2 +
tests/detection/test3/pip_requirements.txt | 1 +
tests/detection/test3/reqs.txt | 1 +
tests/detection/test3/requirements_base.txt | 1 +
tests/detection/test3/requirements_test.txt | 1 +
tests/detection/test3/test_requirements.txt | 1 +
tests/detection/test4/callable.py | 13 +
tests/detection/test4/in_file.py | 12 +
tests/detection/test4/simple.py | 10 +
tests/detection/test4/subscript_assign.py | 19 ++
tests/detection/test4/tuple.py | 10 +
tests/detection/test4/uses_requires.py | 10 +
.../test4/uses_requires_and_install_requires.py | 12 +
tests/detection/test4/utf8.py | 11 +
tests/detection/test5/invalid_requirements.txt | 5 +
tests/detection/test6/requirements.txt | 82 +++++++
tests/test_detection.py | 93 ++++++++
tests/test_failure_cases.py | 10 +
tests/test_parsing.py | 80 +++++++
tox.ini | 6 +
38 files changed, 1027 insertions(+)
diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..0382f85
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,3 @@
+
+[run]
+source=requirements_detector
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d2d6f36
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,35 @@
+*.py[cod]
+
+# C extensions
+*.so
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+eggs
+parts
+bin
+var
+sdist
+develop-eggs
+.installed.cfg
+lib
+lib64
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+nosetests.xml
+
+# Translations
+*.mo
+
+# Mr Developer
+.mr.developer.cfg
+.project
+.pydevproject
diff --git a/.landscape.yaml b/.landscape.yaml
new file mode 100644
index 0000000..e509d42
--- /dev/null
+++ b/.landscape.yaml
@@ -0,0 +1,4 @@
+doc-warnings: no
+strictness: veryhigh
+max-line-length: 120
+
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..5e4e364
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,13 @@
+language: python
+python:
+ - "2.6"
+ - "2.7"
+ - "3.3"
+ - "3.4"
+install:
+ - "pip install --use-mirrors nose coverage coveralls"
+ - "pip install --use-mirrors --editable ."
+script:
+ nosetests -s --with-coverage --cover-package requirements_detector --cover-inclusive
+after_success:
+ coveralls
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..46eb817
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..a09e60e
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1 @@
+include bin/detect-requirements
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1b46bbb
--- /dev/null
+++ b/README.md
@@ -0,0 +1,49 @@
+# Requirements Detector
+
+## Status
+
+[![Latest Version](https://pypip.in/version/requirements-detector/badge.svg?text=version&style=flat)](https://pypi.python.org/pypi/requirements-detector)
+[![Build Status](https://travis-ci.org/landscapeio/requirements-detector.png?branch=master)](https://travis-ci.org/landscapeio/requirements-detector)
+[![Health](https://landscape.io/github/landscapeio/requirements-detector/master/landscape.svg?style=flat)](https://landscape.io/github/landscapeio/requirements-detector/master)
+[![Coverage Status](https://img.shields.io/coveralls/landscapeio/requirements-detector.svg?style=flat)](https://coveralls.io/r/landscapeio/requirements-detector)
+[![Documentation](https://readthedocs.org/projects/requirements-detector/badge/?version=master)](https://readthedocs.org/projects/requirements-detector/)
+
+## About
+
+`requirements-detector` is a simple Python tool which attempts to find and list the requirements of a Python project.
+
+When run from the root of a Python project, it will try to ascertain which libraries and the versions of those libraries that the project depends on.
+
+It uses the following methods in order, in the root of the project:
+
+1. Parse `setup.py` (if this is successful, the remaining steps are skipped)
+2. Parse `requirements.txt` or `requirements.pip`
+3. Parse all `*.txt` and `*.pip` files inside a folder called `requirements`
+4. Parse all files in the root folder matching `*requirements*.txt` or `reqs.txt` (so for example, `pip_requirements.txt` would match, as would `requirements_common.txt`)
+
+### Usage
+
+```
+detect-requirements [path]
+```
+If `path` is not specified, the current working directory will be used.
+
+### Output
+
+The output will be plaintext, and match that of a [pip requirements file](http://www.pip-installer.org/en/latest/logic.html), for example:
+
+```
+Django==1.5.2
+South>=0.8
+anyjson
+celery>=2.2,<3
+```
+
+### Usage From Python
+
+```
+>>> import os
+>>> from requirements_detector import find_requirements
+>>> find_requirements(os.getcwd())
+[DetectedRequirement:Django==1.5.2, DetectedRequirement:South>=0.8, ...]
+```
diff --git a/bin/detect-requirements b/bin/detect-requirements
new file mode 100755
index 0000000..854ed3b
--- /dev/null
+++ b/bin/detect-requirements
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+from requirements_detector.run import run
+run()
\ No newline at end of file
diff --git a/requirements_detector/__init__.py b/requirements_detector/__init__.py
new file mode 100644
index 0000000..2a4de15
--- /dev/null
+++ b/requirements_detector/__init__.py
@@ -0,0 +1 @@
+from requirements_detector.detect import find_requirements
\ No newline at end of file
diff --git a/requirements_detector/detect.py b/requirements_detector/detect.py
new file mode 100644
index 0000000..e289497
--- /dev/null
+++ b/requirements_detector/detect.py
@@ -0,0 +1,264 @@
+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_requirements',
+ 'RequirementsNotFound',
+ '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 = (
+ '-i', '--index-url',
+ '--extra-index-url',
+ '--no-index',
+ '-f', '--find-links',
+ '-r'
+)
+
+
+class RequirementsNotFound(Exception):
+ pass
+
+
+class CouldNotParseRequirements(Exception):
+ 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
+ by inspecting the possible places that they could be defined.
+
+ 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 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'
+
+ If one of these succeeds, then a list of pkg_resources.Requirement's
+ 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:
+ requirements = from_setup_py(setup_py)
+ requirements.sort()
+ return requirements
+ 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):
+ 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
+
+
+class SetupWalker(object):
+
+ def __init__(self, ast):
+ self._ast = ast
+ self._setup_call = None
+ self._top_level_assigns = {}
+ self.walk()
+
+ def walk(self, node=None):
+ top = node is None
+ node = node or self._ast
+
+ # test to see if this is a call to setup()
+ if isinstance(node, CallFunc):
+ for child_node in node.get_children():
+ if isinstance(child_node, Name) and child_node.name == 'setup':
+ # TODO: what if this isn't actually the distutils setup?
+ self._setup_call = node
+
+ for child_node in node.get_children():
+ if top and isinstance(child_node, Assign):
+ for target in child_node.targets:
+ if isinstance(target, AssName):
+ self._top_level_assigns[target.name] = child_node.value
+ self.walk(child_node)
+
+ def _get_list_value(self, list_node):
+ values = []
+ for child_node in list_node.get_children():
+ if not isinstance(child_node, Const):
+ # we can't handle anything fancy, only constant values
+ raise CouldNotParseRequirements
+ values.append(child_node.value)
+ return values
+
+ 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 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
+ found_requirements += self._get_list_value(child_node.value)
+ continue
+
+ if isinstance(child_node.value, Name):
+ # otherwise, it's referencing a value defined elsewhere
+ # this will be a Keyword -> Name
+ try:
+ reqs = self._top_level_assigns[child_node.value.name]
+ except KeyError:
+ raise CouldNotParseRequirements
+ else:
+ if isinstance(reqs, (List, Tuple)):
+ 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 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):
+ 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_requires():
+ requirements.append(DetectedRequirement.parse(req, setup_file))
+
+ return requirements
+
+
+def from_requirements_txt(requirements_file):
+ # see http://www.pip-installer.org/en/latest/logic.html
+ requirements = []
+ with open(requirements_file) as f:
+ for req in f.readlines():
+ if req.strip() == '':
+ # empty line
+ continue
+ if req.strip().startswith('#'):
+ # this is a comment
+ continue
+ if req.strip().split()[0] in _PIP_OPTIONS:
+ # this is a pip option
+ continue
+ detected = DetectedRequirement.parse(req, requirements_file)
+ if detected is None:
+ continue
+ requirements.append(detected)
+
+ return requirements
+
+
+def from_requirements_dir(path):
+ requirements = []
+ for entry in os.listdir(path):
+ filepath = os.path.join(path, entry)
+ if not os.path.isfile(filepath):
+ continue
+ if entry.endswith('.txt') or entry.endswith('.pip'):
+ # TODO: deal with duplicates
+ requirements += from_requirements_txt(filepath)
+
+ return requirements
+
+
+def from_requirements_blob(path):
+ requirements = []
+
+ for entry in os.listdir(path):
+ filepath = os.path.join(path, entry)
+ if not os.path.isfile(filepath):
+ continue
+ m = re.match(r'^(\w*)req(uirement)?s(\w*)\.txt$', entry)
+ if m is None:
+ continue
+ if m.group(1).startswith('test') or m.group(3).endswith('test'):
+ continue
+ requirements += from_requirements_txt(filepath)
+
+ return requirements
diff --git a/requirements_detector/formatters.py b/requirements_detector/formatters.py
new file mode 100644
index 0000000..415cf60
--- /dev/null
+++ b/requirements_detector/formatters.py
@@ -0,0 +1,13 @@
+
+import sys
+
+
+def requirements_file(requirements_list):
+ for requirement in requirements_list:
+ sys.stdout.write(requirement.pip_format())
+ sys.stdout.write('\n')
+
+
+FORMATTERS = {
+ 'requirements_file': requirements_file
+}
diff --git a/requirements_detector/requirement.py b/requirements_detector/requirement.py
new file mode 100644
index 0000000..40d2c95
--- /dev/null
+++ b/requirements_detector/requirement.py
@@ -0,0 +1,148 @@
+"""
+This module represents the various types of requirement that can be specified for
+a project. It is somewhat redundant to re-implement here as we could use
+`pip.req.InstallRequirement`, but that would require depending on pip which is not
+easy to do since it will usually be installed by the user at a specific version.
+Additionally, the pip implementation has a lot of extra features that we don't need -
+we don't expect relative file paths to exist, for example. Note that the parsing here
+is also intentionally more lenient - it is not our job to validate the requirements
+list.
+"""
+import os
+import re
+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
+ return os.path.sep in req or req.startswith('.')
+
+
+def _parse_egg_name(url_fragment):
+ """
+ >>> _parse_egg_name('egg=fish&cake=lala')
+ fish
+ >>> _parse_egg_name('something_spurious')
+ None
+ """
+ if '=' not in url_fragment:
+ return None
+ parts = urlparse.parse_qs(url_fragment)
+ if 'egg' not in parts:
+ return None
+ return parts['egg'][0] # taking the first value mimics pip's behaviour
+
+
+def _strip_fragment(urlparts):
+ new_urlparts = (
+ urlparts.scheme,
+ urlparts.netloc,
+ urlparts.path,
+ urlparts.params,
+ urlparts.query,
+ None
+ )
+ return urlparse.urlunparse(new_urlparts)
+
+
+class DetectedRequirement(object):
+
+ def __init__(self, name=None, url=None, requirement=None, location_defined=None):
+ if requirement is not None:
+ self.name = requirement.key
+ self.requirement = requirement
+ self.version_specs = requirement.specs
+ self.url = None
+ else:
+ self.name = name
+ 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'
+ if self.version_specs:
+ specs = ','.join(['%s%s' % (comp, version) for comp, version in self.version_specs])
+ rep = '%s%s' % (rep, specs)
+ if self.url:
+ 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, location_defined=None):
+ # the options for a Pip requirements file are:
+ #
+ # 1) <dependency_name>
+ # 2) <dependency_name><version_spec>
+ # 3) <vcs_url>(#egg=<dependency_name>)?
+ # 4) <url_to_archive>(#egg=<dependency_name>)?
+ # 5) <path_to_dir>
+ # 6) (-e|--editable) <path_to_dir>(#egg=<dependency_name)?
+ # 7) (-e|--editable) <vcs_url>#egg=<dependency_name>
+ line = line.strip()
+
+ # strip the editable flag
+ line = re.sub('^(-e|--editable) ', '', line)
+
+ url = urlparse.urlparse(line)
+
+ # 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 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
+ 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)
+ url = _strip_fragment(url)
+
+ if vcs_scheme:
+ url = '%s://%s' % (vcs_scheme, url)
+
+ return DetectedRequirement(name=name, url=url, location_defined=location_defined)
diff --git a/requirements_detector/run.py b/requirements_detector/run.py
new file mode 100644
index 0000000..cbb4080
--- /dev/null
+++ b/requirements_detector/run.py
@@ -0,0 +1,36 @@
+import os
+import sys
+from requirements_detector.detect import RequirementsNotFound
+from requirements_detector.formatters import FORMATTERS
+from requirements_detector import find_requirements
+
+
+def _die(message):
+ sys.stderr.write("%s\n" % message)
+ sys.exit(1)
+
+
+def run():
+ if len(sys.argv) > 1:
+ path = sys.argv[1]
+ else:
+ path = os.getcwd()
+
+ if not os.path.exists(path):
+ _die("%s does not exist" % path)
+
+ if not os.path.isdir(path):
+ _die("%s is not a directory" % path)
+
+ try:
+ requirements = find_requirements(path)
+ except RequirementsNotFound:
+ _die("Unable to find requirements at %s" % path)
+
+ format_name = 'requirements_file' # TODO: other output formats such as JSON
+ FORMATTERS[format_name](requirements)
+ sys.exit(0)
+
+
+if __name__ == '__main__':
+ run()
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..eeedd54
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,38 @@
+# -*- coding: UTF-8 -*-
+from distutils.core import setup
+from setuptools import find_packages
+
+
+_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',
+ url='https://github.com/landscapeio/requirements-detector',
+ author='landscape.io',
+ author_email='code at landscape.io',
+ description=_short_description,
+ version=_version,
+ scripts=['bin/detect-requirements'],
+ install_requires=['astroid>=1.0.0'],
+ packages=_packages,
+ license='MIT',
+ keywords='python requirements detector',
+ classifiers=_CLASSIFIERS,
+)
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/detection/syntax_error/setup.py b/tests/detection/syntax_error/setup.py
new file mode 100644
index 0000000..cc5a9d6
--- /dev/null
+++ b/tests/detection/syntax_error/setup.py
@@ -0,0 +1,10 @@
+from distutils.core import setup
+
+setup(
+ name='prospector-test-1',
+ version='0.0.1',
+ install_requires=[
+ 'Django==1.5.0',
+ 'django-gubbins==1.1.2'
+ ] narm narm narm
+)
\ No newline at end of file
diff --git a/tests/detection/test1/requirements.txt b/tests/detection/test1/requirements.txt
new file mode 100644
index 0000000..764434b
--- /dev/null
+++ b/tests/detection/test1/requirements.txt
@@ -0,0 +1,6 @@
+-i https://example.com/custom/pypi
+Django>=1.5.0
+South==0.8.2
+amqp!=1.0.13
+# we want six too
+six<1.4,>=1.3.0
\ No newline at end of file
diff --git a/tests/detection/test2/requirements/base.txt b/tests/detection/test2/requirements/base.txt
new file mode 100644
index 0000000..54f1b29
--- /dev/null
+++ b/tests/detection/test2/requirements/base.txt
@@ -0,0 +1,2 @@
+amqp==1.0.13
+anyjson==0.3.3
diff --git a/tests/detection/test2/requirements/webui.pip b/tests/detection/test2/requirements/webui.pip
new file mode 100644
index 0000000..14ae0d2
--- /dev/null
+++ b/tests/detection/test2/requirements/webui.pip
@@ -0,0 +1,2 @@
+Django==1.5.2
+South==0.8.2
\ No newline at end of file
diff --git a/tests/detection/test3/pip_requirements.txt b/tests/detection/test3/pip_requirements.txt
new file mode 100644
index 0000000..b9ba1e0
--- /dev/null
+++ b/tests/detection/test3/pip_requirements.txt
@@ -0,0 +1 @@
+anyjson==0.3.3
diff --git a/tests/detection/test3/reqs.txt b/tests/detection/test3/reqs.txt
new file mode 100644
index 0000000..ac7d70c
--- /dev/null
+++ b/tests/detection/test3/reqs.txt
@@ -0,0 +1 @@
+django-gubbins==1.1.2
\ No newline at end of file
diff --git a/tests/detection/test3/requirements_base.txt b/tests/detection/test3/requirements_base.txt
new file mode 100644
index 0000000..dca95d6
--- /dev/null
+++ b/tests/detection/test3/requirements_base.txt
@@ -0,0 +1 @@
+amqp==1.0.13
diff --git a/tests/detection/test3/requirements_test.txt b/tests/detection/test3/requirements_test.txt
new file mode 100644
index 0000000..2cdfeb3
--- /dev/null
+++ b/tests/detection/test3/requirements_test.txt
@@ -0,0 +1 @@
+South==0.8.2
\ No newline at end of file
diff --git a/tests/detection/test3/test_requirements.txt b/tests/detection/test3/test_requirements.txt
new file mode 100644
index 0000000..7dd404b
--- /dev/null
+++ b/tests/detection/test3/test_requirements.txt
@@ -0,0 +1 @@
+Django==1.5.2
\ No newline at end of file
diff --git a/tests/detection/test4/callable.py b/tests/detection/test4/callable.py
new file mode 100644
index 0000000..0232e5c
--- /dev/null
+++ b/tests/detection/test4/callable.py
@@ -0,0 +1,13 @@
+from distutils.core import setup
+
+def _install_requires():
+ return [
+ 'Django==1.5.0',
+ 'django-gubbins==1.1.2'
+ ]
+
+setup(
+ name='prospector-test-2',
+ version='0.0.1',
+ install_requires=_install_requires()
+)
\ No newline at end of file
diff --git a/tests/detection/test4/in_file.py b/tests/detection/test4/in_file.py
new file mode 100644
index 0000000..7d11615
--- /dev/null
+++ b/tests/detection/test4/in_file.py
@@ -0,0 +1,12 @@
+from distutils.core import setup
+
+_install_requires = [
+ 'Django==1.5.0',
+ 'django-gubbins==1.1.2'
+]
+
+setup(
+ name='prospector-test-2',
+ version='0.0.1',
+ install_requires=_install_requires
+)
\ No newline at end of file
diff --git a/tests/detection/test4/simple.py b/tests/detection/test4/simple.py
new file mode 100644
index 0000000..793c915
--- /dev/null
+++ b/tests/detection/test4/simple.py
@@ -0,0 +1,10 @@
+from distutils.core import setup
+
+setup(
+ name='prospector-test-1',
+ version='0.0.1',
+ install_requires=[
+ 'Django==1.5.0',
+ 'django-gubbins==1.1.2'
+ ]
+)
\ No newline at end of file
diff --git a/tests/detection/test4/subscript_assign.py b/tests/detection/test4/subscript_assign.py
new file mode 100644
index 0000000..e12aeb3
--- /dev/null
+++ b/tests/detection/test4/subscript_assign.py
@@ -0,0 +1,19 @@
+"""
+This test is to verify that top level subscript assigns (x[y]) don't break the
+parser. For version <=0.1, a subscript assign would break the setup.py AST walker
+completely.
+"""
+
+from distutils.core import setup
+
+something = dict()
+something['fish'] = ['a', 'b', 'c']
+
+setup(
+ name='prospector-test-1',
+ version='0.0.1',
+ install_requires=(
+ 'Django==1.5.0',
+ 'django-gubbins==1.1.2'
+ )
+)
\ No newline at end of file
diff --git a/tests/detection/test4/tuple.py b/tests/detection/test4/tuple.py
new file mode 100644
index 0000000..af441dc
--- /dev/null
+++ b/tests/detection/test4/tuple.py
@@ -0,0 +1,10 @@
+from distutils.core import setup
+
+setup(
+ name='prospector-test-1',
+ version='0.0.1',
+ install_requires=(
+ 'Django==1.5.0',
+ 'django-gubbins==1.1.2'
+ )
+)
\ No newline at end of file
diff --git a/tests/detection/test4/uses_requires.py b/tests/detection/test4/uses_requires.py
new file mode 100644
index 0000000..5ed80f3
--- /dev/null
+++ b/tests/detection/test4/uses_requires.py
@@ -0,0 +1,10 @@
+from distutils.core import setup
+
+setup(
+ name='prospector-test-1',
+ version='0.0.1',
+ requires=[
+ 'Django==1.5.0',
+ 'django-gubbins==1.1.2'
+ ]
+)
\ No newline at end of file
diff --git a/tests/detection/test4/uses_requires_and_install_requires.py b/tests/detection/test4/uses_requires_and_install_requires.py
new file mode 100644
index 0000000..32ccb0d
--- /dev/null
+++ b/tests/detection/test4/uses_requires_and_install_requires.py
@@ -0,0 +1,12 @@
+from distutils.core import setup
+
+setup(
+ name='prospector-test-1',
+ version='0.0.1',
+ requires=[
+ 'Django==1.5.0',
+ ],
+ install_requires=[
+ 'django-gubbins==1.1.2'
+ ]
+)
\ No newline at end of file
diff --git a/tests/detection/test4/utf8.py b/tests/detection/test4/utf8.py
new file mode 100644
index 0000000..37ea216
--- /dev/null
+++ b/tests/detection/test4/utf8.py
@@ -0,0 +1,11 @@
+# -*- coding: UTF-8 -*-
+from distutils.core import setup
+
+setup(
+ name=u'prospector-test-4-üéø',
+ version='0.0.1',
+ install_requires=[
+ 'Django==1.5.0',
+ 'django-gubbins==1.1.2'
... 318 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-requirements-detector.git
More information about the Python-modules-commits
mailing list