summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lint.py67
-rw-r--r--test/unittest_lint.py161
2 files changed, 158 insertions, 70 deletions
diff --git a/lint.py b/lint.py
index 4c92b4e..833fe91 100644
--- a/lint.py
+++ b/lint.py
@@ -33,6 +33,7 @@ from pylint.checkers import utils #pylint: disable=unused-import
import sys
import os
import tokenize
+from contextlib import contextmanager
from operator import attrgetter
from warnings import warn
@@ -71,8 +72,9 @@ import six
def _get_python_path(filepath):
- dirname = os.path.dirname(os.path.realpath(
- os.path.expanduser(filepath)))
+ dirname = os.path.realpath(os.path.expanduser(filepath))
+ if not os.path.isdir(dirname):
+ dirname = os.path.dirname(dirname)
while True:
if not os.path.exists(os.path.join(dirname, "__init__.py")):
return dirname
@@ -411,17 +413,6 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
if not self.reporter:
self._load_reporter()
- def prepare_import_path(self, args):
- """Prepare sys.path for running the linter checks."""
- if len(args) == 1:
- sys.path.insert(0, _get_python_path(args[0]))
- else:
- sys.path.insert(0, os.getcwd())
-
- def cleanup_import_path(self):
- """Revert any changes made to sys.path in prepare_import_path."""
- sys.path.pop(0)
-
def load_plugin_modules(self, modnames):
"""take a list of module names which are pylint plugins and load
and register them
@@ -1015,6 +1006,31 @@ def preprocess_options(args, search_for):
else:
i += 1
+
+@contextmanager
+def fix_import_path(args):
+ """Prepare sys.path for running the linter checks.
+
+ Within this context, each of the given arguments is importable.
+ Paths are added to sys.path in corresponding order to the arguments.
+ We avoid adding duplicate directories to sys.path.
+ `sys.path` is reset to its original value upon exitign this context.
+ """
+ orig = list(sys.path)
+ changes = []
+ for arg in args:
+ path = _get_python_path(arg)
+ if path in changes:
+ continue
+ else:
+ changes.append(path)
+ sys.path[:] = changes + sys.path
+ try:
+ yield
+ finally:
+ sys.path[:] = orig
+
+
class Run(object):
"""helper class to use as main for pylint :
@@ -1184,20 +1200,19 @@ group are mutually exclusive.'),
# insert current working directory to the python path to have a correct
# behaviour
- linter.prepare_import_path(args)
- if self.linter.config.profile:
- print('** profiled run', file=sys.stderr)
- import cProfile, pstats
- cProfile.runctx('linter.check(%r)' % args, globals(), locals(),
- 'stones.prof')
- data = pstats.Stats('stones.prof')
- data.strip_dirs()
- data.sort_stats('time', 'calls')
- data.print_stats(30)
- else:
- linter.check(args)
+ with fix_import_path(args):
+ if self.linter.config.profile:
+ print('** profiled run', file=sys.stderr)
+ import cProfile, pstats
+ cProfile.runctx('linter.check(%r)' % args, globals(), locals(),
+ 'stones.prof')
+ data = pstats.Stats('stones.prof')
+ data.strip_dirs()
+ data.sort_stats('time', 'calls')
+ data.print_stats(30)
+ else:
+ linter.check(args)
linter.generate_reports()
- linter.cleanup_import_path()
if exit:
sys.exit(self.linter.msg_status)
diff --git a/test/unittest_lint.py b/test/unittest_lint.py
index bef9c14..c006406 100644
--- a/test/unittest_lint.py
+++ b/test/unittest_lint.py
@@ -12,18 +12,19 @@
# this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+from contextlib import contextmanager
import cStringIO
import sys
import os
import tempfile
from shutil import rmtree
from os import getcwd, chdir
-from os.path import join, basename, dirname, isdir, abspath
+from os.path import join, basename, dirname, isdir, abspath, sep
import unittest
from logilab.common.compat import reload
-from pylint import config
+from pylint import config, lint
from pylint.lint import PyLinter, Run, UnknownMessage, preprocess_options, \
ArgumentPreprocessingError
from pylint.utils import MSG_STATE_SCOPE_CONFIG, MSG_STATE_SCOPE_MODULE, MSG_STATE_CONFIDENCE, \
@@ -57,7 +58,28 @@ class GetNoteMessageTC(unittest.TestCase):
HERE = abspath(dirname(__file__))
INPUTDIR = join(HERE, 'input')
-def create_files(paths, chroot):
+
+@contextmanager
+def tempdir():
+ """Create a temp directory and change the current location to it.
+
+ This is supposed to be used with a *with* statement.
+ """
+ tmp = tempfile.mkdtemp()
+
+ # Get real path of tempfile, otherwise test fail on mac os x
+ current_dir = getcwd()
+ chdir(tmp)
+ abs_tmp = abspath('.')
+
+ try:
+ yield abs_tmp
+ finally:
+ chdir(current_dir)
+ rmtree(abs_tmp)
+
+
+def create_files(paths, chroot='.'):
"""Creates directories and files found in <path>.
:param paths: list of relative paths to files or directories
@@ -94,6 +116,78 @@ def create_files(paths, chroot):
open(filepath, 'w').close()
+class SysPathFixupTC(unittest.TestCase):
+ def setUp(self):
+ self.orig = list(sys.path)
+ self.fake = [1, 2, 3]
+ sys.path[:] = self.fake
+
+ def tearDown(self):
+ sys.path[:] = self.orig
+
+ def test_no_args(self):
+ with lint.fix_import_path([]):
+ self.assertEqual(sys.path, self.fake)
+ self.assertEqual(sys.path, self.fake)
+
+ def test_one_arg(self):
+ with tempdir() as chroot:
+ create_files(['a/b/__init__.py'])
+ expected = [join(chroot, 'a')] + self.fake
+
+ cases = (
+ ['a/b/'],
+ ['a/b'],
+ ['a/b/__init__.py'],
+ ['a/'],
+ ['a'],
+ )
+
+ self.assertEqual(sys.path, self.fake)
+ for case in cases:
+ with lint.fix_import_path(case):
+ self.assertEqual(sys.path, expected)
+ self.assertEqual(sys.path, self.fake)
+
+ def test_two_similar_args(self):
+ with tempdir() as chroot:
+ create_files(['a/b/__init__.py', 'a/c/__init__.py'])
+ expected = [join(chroot, 'a')] + self.fake
+
+ cases = (
+ ['a/b', 'a/c'],
+ ['a/c/', 'a/b/'],
+ ['a/b/__init__.py', 'a/c/__init__.py'],
+ ['a', 'a/c/__init__.py'],
+ )
+
+ self.assertEqual(sys.path, self.fake)
+ for case in cases:
+ with lint.fix_import_path(case):
+ self.assertEqual(sys.path, expected)
+ self.assertEqual(sys.path, self.fake)
+
+ def test_more_args(self):
+ with tempdir() as chroot:
+ create_files(['a/b/c/__init__.py', 'a/d/__init__.py', 'a/e/f.py'])
+ expected = [
+ join(chroot, suffix)
+ for suffix in [sep.join(('a', 'b')), 'a', sep.join(('a', 'e'))]
+ ] + self.fake
+
+ cases = (
+ ['a/b/c/__init__.py', 'a/d/__init__.py', 'a/e/f.py'],
+ ['a/b/c', 'a', 'a/e'],
+ ['a/b/c', 'a', 'a/b/c', 'a/e', 'a'],
+ )
+
+ self.assertEqual(sys.path, self.fake)
+ for case in cases:
+ with lint.fix_import_path(case):
+ self.assertEqual(sys.path, expected)
+ self.assertEqual(sys.path, self.fake)
+
+
class PyLinterTC(unittest.TestCase):
def setUp(self):
@@ -428,18 +522,10 @@ class ConfigTC(unittest.TestCase):
reload(config)
def test_pylintrc_parentdir(self):
- chroot = tempfile.mkdtemp()
-
- # Get real path of tempfile, otherwise test fail on mac os x
- cdir = getcwd()
- chdir(chroot)
- chroot = abspath('.')
- chdir(cdir)
+ with tempdir() as chroot:
- try:
create_files(['a/pylintrc', 'a/b/__init__.py', 'a/b/pylintrc',
- 'a/b/c/__init__.py', 'a/b/c/d/__init__.py'], chroot)
- os.chdir(chroot)
+ 'a/b/c/__init__.py', 'a/b/c/d/__init__.py'])
fake_home = tempfile.mkdtemp('fake-home')
home = os.environ[HOME]
try:
@@ -456,39 +542,26 @@ class ConfigTC(unittest.TestCase):
for basedir, expected in results.items():
os.chdir(join(chroot, basedir))
self.assertEqual(config.find_pylintrc(), expected)
- finally:
- os.chdir(HERE)
- rmtree(chroot)
def test_pylintrc_parentdir_no_package(self):
- chroot = tempfile.mkdtemp()
-
- # Get real path of tempfile, otherwise test fail on mac os x
- cdir = getcwd()
- chdir(chroot)
- chroot = abspath('.')
- chdir(cdir)
-
- fake_home = tempfile.mkdtemp('fake-home')
- home = os.environ[HOME]
- os.environ[HOME] = fake_home
- try:
- create_files(['a/pylintrc', 'a/b/pylintrc', 'a/b/c/d/__init__.py'], chroot)
- os.chdir(chroot)
- self.assertEqual(config.find_pylintrc(), None)
- results = {'a' : join(chroot, 'a', 'pylintrc'),
- 'a/b' : join(chroot, 'a', 'b', 'pylintrc'),
- 'a/b/c' : None,
- 'a/b/c/d' : None,
- }
- for basedir, expected in results.items():
- os.chdir(join(chroot, basedir))
- self.assertEqual(config.find_pylintrc(), expected)
- finally:
- os.environ[HOME] = home
- rmtree(fake_home, ignore_errors=True)
- os.chdir(HERE)
- rmtree(chroot)
+ with tempdir() as chroot:
+ fake_home = tempfile.mkdtemp('fake-home')
+ home = os.environ[HOME]
+ os.environ[HOME] = fake_home
+ try:
+ create_files(['a/pylintrc', 'a/b/pylintrc', 'a/b/c/d/__init__.py'])
+ self.assertEqual(config.find_pylintrc(), None)
+ results = {'a' : join(chroot, 'a', 'pylintrc'),
+ 'a/b' : join(chroot, 'a', 'b', 'pylintrc'),
+ 'a/b/c' : None,
+ 'a/b/c/d' : None,
+ }
+ for basedir, expected in results.items():
+ os.chdir(join(chroot, basedir))
+ self.assertEqual(config.find_pylintrc(), expected)
+ finally:
+ os.environ[HOME] = home
+ rmtree(fake_home, ignore_errors=True)
class PreprocessOptionsTC(unittest.TestCase):