diff --git a/README.rst b/README.rst index 9ed17efe..83d077cb 100644 --- a/README.rst +++ b/README.rst @@ -75,6 +75,9 @@ Jedi really understands your Python code. For a comprehensive list what Jedi can do, see: https://jedi.readthedocs.org/en/latest/docs/features.html. A list of caveats can be found on the same page. +You can run Jedi on cPython 2.6, 2.7, 3.2 or 3.3, but it should also +understand/parse code older than those versions. + Tips on how to use Jedi efficiently can be found here: https://jedi.readthedocs.org/en/latest/docs/recipes.html @@ -102,14 +105,12 @@ The test suite depends on ``tox`` and ``pytest``:: To run the tests for all supported Python versions:: - PIP_INSECURE=t tox + tox If you want to test only a specific Python version (e.g. Python 2.7), it's as easy as :: tox -e py27 -The ``PIP_INSECURE=t`` env variable is only needed for the ``py25`` target. - Tests are also run automatically on `Travis CI `_. diff --git a/docs/docs/features.rst b/docs/docs/features.rst index 6038e37e..a0674131 100644 --- a/docs/docs/features.rst +++ b/docs/docs/features.rst @@ -9,7 +9,7 @@ Features and Caveats General Features ---------------- -- python 2.5+ and 3.2+ support +- python 2.6+ and 3.2+ support - ignores syntax errors and wrong indentation - can deal with complex module / function / class structures - virtualenv support diff --git a/jedi/_compatibility.py b/jedi/_compatibility.py index 73c7f865..ccb99f8c 100644 --- a/jedi/_compatibility.py +++ b/jedi/_compatibility.py @@ -1,10 +1,7 @@ """ -To ensure compatibility from Python ``2.5`` - ``3.2``, a module has been +To ensure compatibility from Python ``2.6`` - ``3.3``, a module has been created. Clearly there is huge need to use conforming syntax. But many changes (e.g. ``property``, ``hasattr`` in ``2.5``) can be rewritten in pure python. - -Most of the code here is necessary to support Python 2.5. Once this dependency -will be dropped, we'll get rid of most code. """ import sys import imp @@ -16,7 +13,6 @@ except: is_py3k = sys.hexversion >= 0x03000000 is_py33 = sys.hexversion >= 0x03030000 -is_py25 = sys.hexversion < 0x02060000 def find_module_py33(string, path=None): @@ -91,34 +87,6 @@ except NameError: else: return default -# ast module was defined in python 2.6 -try: - from ast import literal_eval -except ImportError: - literal_eval = eval - - -# properties in 2.5 -try: - property.setter -except AttributeError: - class property(property): - def __init__(self, fget, *args, **kwargs): - self.__doc__ = fget.__doc__ - super(property, self).__init__(fget, *args, **kwargs) - - def setter(self, fset): - cls_ns = sys._getframe(1).f_locals - for k, v in cls_ns.iteritems(): - if v == self: - propname = k - break - cls_ns[propname] = property(self.fget, fset, - self.fdel, self.__doc__) - return cls_ns[propname] -else: - property = property - # unicode function try: unicode = unicode @@ -203,66 +171,10 @@ def use_metaclass(meta, *bases): return meta("HackClass", bases, {}) try: - from inspect import cleandoc -except ImportError: - # python 2.5 doesn't have this method - import string - - def cleandoc(doc): - """Clean up indentation from docstrings. - - Any whitespace that can be uniformly removed from the second line - onwards is removed.""" - try: - lines = string.split(string.expandtabs(doc), '\n') - except UnicodeError: - return None - else: - # Find minimum indentation of any non-blank lines after first line. - margin = sys.maxint - for line in lines[1:]: - content = len(string.lstrip(line)) - if content: - indent = len(line) - content - margin = min(margin, indent) - # Remove indentation. - if lines: - lines[0] = lines[0].lstrip() - if margin < sys.maxint: - for i in range(1, len(lines)): - lines[i] = lines[i][margin:] - # Remove any trailing or leading blank lines. - while lines and not lines[-1]: - lines.pop() - while lines and not lines[0]: - lines.pop(0) - return string.join(lines, '\n') - -if is_py25: - # adds the `itertools.chain.from_iterable` constructor - import itertools - - class chain(itertools.chain): - @staticmethod - def from_iterable(iterables): - # chain.from_iterable(['ABC', 'DEF']) --> A B C D E F - for it in iterables: - for element in it: - yield element - itertools.chain = chain - del chain - -try: - from functools import reduce + from functools import reduce # Python 3 except ImportError: reduce = reduce -try: - import json -except ImportError: - # python 2.5 - import simplejson as json - try: encoding = sys.stdout.encoding except AttributeError: diff --git a/jedi/cache.py b/jedi/cache.py index e2c0c236..bf96671f 100644 --- a/jedi/cache.py +++ b/jedi/cache.py @@ -21,6 +21,7 @@ from __future__ import with_statement import time import os import sys +import json import hashlib try: import cPickle as pickle @@ -28,7 +29,6 @@ except: import pickle import shutil -from jedi._compatibility import json from jedi import settings from jedi import common from jedi import debug diff --git a/jedi/evaluate_representation.py b/jedi/evaluate_representation.py index d5402e4b..1bb2c65e 100644 --- a/jedi/evaluate_representation.py +++ b/jedi/evaluate_representation.py @@ -14,7 +14,7 @@ from __future__ import with_statement import copy import itertools -from jedi._compatibility import property, use_metaclass, next, hasattr +from jedi._compatibility import use_metaclass, next, hasattr from jedi import parsing_representation as pr from jedi import cache from jedi import helpers diff --git a/jedi/fast_parser.py b/jedi/fast_parser.py index 1923a76e..eadaa01d 100644 --- a/jedi/fast_parser.py +++ b/jedi/fast_parser.py @@ -6,7 +6,7 @@ finished (and still not working as I want), I won't document it any further. import re import operator -from jedi._compatibility import use_metaclass, reduce, property +from jedi._compatibility import use_metaclass, reduce from jedi import settings from jedi import parsing from jedi import parsing_representation as pr @@ -225,7 +225,7 @@ class FastParser(use_metaclass(CachedFastParser)): if settings.fast_parser_always_reparse: self.parsers[:] = [] - # dict comprehensions are not available in py2.5/2.6 :-( + # dict comprehensions are not available in 2.6 :-( hashes = dict((p.hash, p) for p in self.parsers) line_offset = 0 diff --git a/jedi/keywords.py b/jedi/keywords.py index cd591aa6..c940fd28 100644 --- a/jedi/keywords.py +++ b/jedi/keywords.py @@ -11,11 +11,7 @@ try: from pydoc_data import topics as pydoc_topics except ImportError: # Python 2.6 - try: - import pydoc_topics - except ImportError: - # Python 2.5 - pydoc_topics = None + import pydoc_topics if is_py3k: keys = keyword.kwlist diff --git a/jedi/modules.py b/jedi/modules.py index 3301eba7..398bcf69 100644 --- a/jedi/modules.py +++ b/jedi/modules.py @@ -19,8 +19,9 @@ import re import tokenizer as tokenize import sys import os +from ast import literal_eval -from jedi._compatibility import exec_function, unicode, is_py25, literal_eval +from jedi._compatibility import exec_function, unicode from jedi import cache from jedi import parsing from jedi import parsing_representation as pr @@ -383,8 +384,7 @@ def source_to_unicode(source, encoding=None): http://docs.python.org/2/reference/lexical_analysis.html#encoding-\ declarations """ - byte_mark = '\xef\xbb\xbf' if is_py25 else \ - literal_eval(r"b'\xef\xbb\xbf'") + byte_mark = literal_eval(r"b'\xef\xbb\xbf'") if source.startswith(byte_mark): # UTF-8 byte-order mark return 'utf-8' diff --git a/jedi/parsing_representation.py b/jedi/parsing_representation.py index 562baa67..cd015fc3 100644 --- a/jedi/parsing_representation.py +++ b/jedi/parsing_representation.py @@ -39,9 +39,10 @@ from __future__ import with_statement import os import re import tokenizer as tokenize +from inspect import cleandoc +from ast import literal_eval -from jedi._compatibility import next, literal_eval, cleandoc, Python3Method, \ - encoding, property, unicode, is_py3k +from jedi._compatibility import next, Python3Method, encoding, unicode, is_py3k from jedi import common from jedi import debug diff --git a/setup.py b/setup.py index bb0ee4e9..d32cc781 100755 --- a/setup.py +++ b/setup.py @@ -32,7 +32,6 @@ setup(name='jedi', 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', diff --git a/test/run.py b/test/run.py index 62178501..e1fff345 100755 --- a/test/run.py +++ b/test/run.py @@ -98,14 +98,14 @@ Tests look like this:: """ import os import re +from ast import literal_eval if __name__ == '__main__': import sys sys.path.insert(0, '..') import jedi -from jedi._compatibility import unicode, StringIO, reduce, is_py25, \ - literal_eval +from jedi._compatibility import unicode, reduce, StringIO TEST_COMPLETIONS = 0 @@ -255,11 +255,6 @@ def collect_dir_tests(base_dir, test_files, check_thirdparty=False): files_to_execute = [a for a in test_files.items() if a[0] in f_name] lines_to_execute = reduce(lambda x, y: x + y[1], files_to_execute, []) if f_name.endswith(".py") and (not test_files or files_to_execute): - # for python2.5 certain tests are not being done, because it - # only has these features partially. - if is_py25 and f_name in ['generators.py', 'types.py']: - continue - skip = None if check_thirdparty: lib = f_name.replace('_.py', '') diff --git a/test/test_regression.py b/test/test_regression.py index 3952e6b7..10d423f0 100755 --- a/test/test_regression.py +++ b/test/test_regression.py @@ -14,7 +14,7 @@ import textwrap from .base import TestBase, unittest, cwd_at import jedi -from jedi._compatibility import is_py25, utf8, unicode +from jedi._compatibility import utf8, unicode from jedi import api api_classes = api.api_classes @@ -84,8 +84,7 @@ class TestRegression(TestBase): def test_keyword_doc(self): r = list(self.definition("or", (1, 1))) assert len(r) == 1 - if not is_py25: - assert len(r[0].doc) > 100 + assert len(r[0].doc) > 100 r = list(self.definition("asfdasfd", (1, 1))) assert len(r) == 0 @@ -93,8 +92,7 @@ class TestRegression(TestBase): def test_operator_doc(self): r = list(self.definition("a == b", (1, 3))) assert len(r) == 1 - if not is_py25: - assert len(r[0].doc) > 100 + assert len(r[0].doc) > 100 def test_function_call_signature(self): defs = self.definition(""" @@ -329,8 +327,6 @@ class TestRegression(TestBase): assert [d.doc for d in defs] def test_goto_following_on_imports(self): - if is_py25: - return g = self.goto("import multiprocessing.dummy; multiprocessing.dummy") assert len(g) == 1 assert g[0].start_pos != (0, 0) diff --git a/tox.ini b/tox.ini index a10c0497..acacf755 100644 --- a/tox.ini +++ b/tox.ini @@ -5,11 +5,6 @@ deps = https://bitbucket.org/hpk42/pytest/get/c4f58165e0d4.zip commands = py.test [] -[testenv:py25] -deps = - simplejson - unittest2 - {[testenv]deps} [testenv:py26] deps = unittest2