diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..443d3cc5
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,7 @@
+# all end-of-lines are normalized to LF when written to the repository
+# https://git-scm.com/docs/gitattributes#_text
+* text=auto
+
+# force all text files on the working dir to have LF line endings
+# https://git-scm.com/docs/gitattributes#_eol
+* text eol=lf
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..05f2c776
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,73 @@
+on: push
+
+jobs:
+ tests:
+ # Set the type of machine to run on
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-20.04, windows-2019]
+ python-version: [3.9, 3.8, 3.7, 3.6]
+ environment: ['3.8', '3.9', '3.7', '3.6', 'interpreter']
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+ with:
+ submodules: recursive
+
+ - uses: actions/setup-python@v2
+ if: ${{ matrix.environment != 'interpreter' }}
+ with:
+ python-version: ${{ matrix.environment }}
+
+ - uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Install dependencies
+ run: 'pip install .[testing]'
+
+ - name: Run tests
+ run: python -m pytest
+ env:
+ JEDI_TEST_ENVIRONMENT: ${{ matrix.environment }}
+
+ code-quality:
+ runs-on: ubuntu-20.04
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+ with:
+ submodules: recursive
+
+ - name: Install dependencies
+ run: 'pip install .[qa]'
+
+ - name: Run tests
+ run: |
+ python -m flake8 jedi setup.py
+ python -m mypy jedi sith.py
+
+ coverage:
+ runs-on: ubuntu-20.04
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+ with:
+ submodules: recursive
+
+ - name: Install dependencies
+ run: 'pip install .[testing] coverage'
+
+ - name: Run tests
+ run: |
+ python -m coverage run --source jedi -m pytest
+ python -m coverage report
+
+ - name: Upload coverage data
+ run: |
+ pip install --quiet codecov coveralls
+ python -m coverage xml
+ python -m coverage report -m
+ bash <(curl -s https://codecov.io/bash) -X gcov -X coveragepy -X search -X fix -X xcode -f coverage.xml
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index e16e2689..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,74 +0,0 @@
-dist: xenial
-language: python
-python:
- - 3.9-dev
- - 3.8
- - 3.7
- - 3.6
-
-env:
- - JEDI_TEST_ENVIRONMENT=38
- - JEDI_TEST_ENVIRONMENT=39
- - JEDI_TEST_ENVIRONMENT=37
- - JEDI_TEST_ENVIRONMENT=36
- - JEDI_TEST_ENVIRONMENT=interpreter
-
-matrix:
- include:
- - python: 3.8
- script:
- - 'pip install coverage'
- - 'coverage run --source jedi -m pytest'
- - 'coverage report'
- after_script:
- - |
- pip install --quiet codecov coveralls
- coverage xml
- coverage report -m
- coveralls
- bash <(curl -s https://codecov.io/bash) -X gcov -X coveragepy -X search -X fix -X xcode -f coverage.xml
- - python: 3.8
- install:
- - 'pip install .[qa]'
- script:
- - 'flake8 jedi setup.py'
- - 'mypy jedi sith.py'
-install:
- - sudo apt-get -y install python3-venv
- - pip install .[testing]
-script:
- - |
- # Setup/install Python for $JEDI_TEST_ENVIRONMENT.
- set -ex
- test_env_version=${JEDI_TEST_ENVIRONMENT:0:1}.${JEDI_TEST_ENVIRONMENT:1:1}
- if [ "$TRAVIS_PYTHON_VERSION" != "$test_env_version" ] && [ "$JEDI_TEST_ENVIRONMENT" != "interpreter" ]; then
- python_bin=python$test_env_version
- python_path="$(which $python_bin || true)"
- if [ -z "$python_path" ]; then
- # Only required for JEDI_TEST_ENVIRONMENT=38, because it's not always
- # available.
- download_name=python-$test_env_version
- if [ "$JEDI_TEST_ENVIRONMENT" == "39" ]; then
- wget https://storage.googleapis.com/travis-ci-language-archives/python/binaries/ubuntu/16.04/x86_64/python-3.9-dev.tar.bz2
- sudo tar xjf python-3.9-dev.tar.bz2 --directory / opt/python
- ln -s "/opt/python/3.9-dev/bin/python" /home/travis/bin/python3.9
- else
- wget https://s3.amazonaws.com/travis-python-archives/binaries/ubuntu/16.04/x86_64/$download_name.tar.bz2
- sudo tar xjf $download_name.tar.bz2 --directory / opt/python
- ln -s "/opt/python/${test_env_version}/bin/python" /home/travis/bin/$python_bin
- fi
- elif [ "${python_path#/opt/pyenv/shims}" != "$python_path" ]; then
- # Activate pyenv version (required with JEDI_TEST_ENVIRONMENT=36).
- pyenv_bin="$(pyenv whence --path "$python_bin" | head -n1)"
- ln -s "$pyenv_bin" /home/travis/bin/$python_bin
- fi
- $python_bin --version
- python_ver=$($python_bin -c 'import sys; print("%d%d" % sys.version_info[0:2])')
- if [ "$JEDI_TEST_ENVIRONMENT" != "$python_ver" ]; then
- echo "Unexpected Python version for $JEDI_TEST_ENVIRONMENT: $python_ver"
- set +ex
- exit 2
- fi
- fi
- set +ex
- - pytest
diff --git a/README.rst b/README.rst
index f63feb8d..7d0d7106 100644
--- a/README.rst
+++ b/README.rst
@@ -10,17 +10,9 @@ Jedi - an awesome autocompletion, static analysis and refactoring library for Py
:target: https://github.com/davidhalter/jedi/issues
:alt: The resolution time is the median time an issue or pull request stays open.
-.. image:: https://travis-ci.org/davidhalter/jedi.svg?branch=master
- :target: https://travis-ci.org/davidhalter/jedi
- :alt: Linux Tests
-
-.. image:: https://ci.appveyor.com/api/projects/status/mgva3bbawyma1new/branch/master?svg=true
- :target: https://ci.appveyor.com/project/davidhalter/jedi/branch/master
- :alt: Windows Tests
-
-.. image:: https://coveralls.io/repos/davidhalter/jedi/badge.svg?branch=master
- :target: https://coveralls.io/r/davidhalter/jedi
- :alt: Coverage status
+.. image:: https://github.com/davidhalter/jedi/workflows/ci/badge.svg?branch=master
+ :target: https://github.com/davidhalter/jedi/actions
+ :alt: Tests
.. image:: https://pepy.tech/badge/jedi
:target: https://pepy.tech/project/jedi
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index df1ed05d..00000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-environment:
- matrix:
- - PYTHON_PATH: C:\Python37
- JEDI_TEST_ENVIRONMENT: 37
- - PYTHON_PATH: C:\Python37
- JEDI_TEST_ENVIRONMENT: 36
-
- - PYTHON_PATH: C:\Python36
- JEDI_TEST_ENVIRONMENT: 37
- - PYTHON_PATH: C:\Python36
- JEDI_TEST_ENVIRONMENT: 36
-install:
- - git submodule update --init --recursive
- - set PATH=%PYTHON_PATH%;%PYTHON_PATH%\Scripts;%PATH%
- - pip install .[testing]
-build_script:
- - pytest
diff --git a/conftest.py b/conftest.py
index c6d02216..eeb531c3 100644
--- a/conftest.py
+++ b/conftest.py
@@ -100,7 +100,9 @@ def environment(request):
if request.config.option.interpreter_env or version == 'interpreter':
return InterpreterEnvironment()
- return get_system_environment(version[0] + '.' + version[1:])
+ if '.' not in version:
+ version = version[0] + '.' + version[1:]
+ return get_system_environment(version)
@pytest.fixture(scope='session')
diff --git a/docs/docs/testing.rst b/docs/docs/testing.rst
index fdb36658..223cc292 100644
--- a/docs/docs/testing.rst
+++ b/docs/docs/testing.rst
@@ -12,8 +12,8 @@ easy as::
python3.8 -m pytest
-Tests are also run automatically on `Travis CI
-`_.
+Tests are also run automatically on `GitHub Actions
+`_.
You want to add a test for |jedi|? Great! We love that. Normally you should
write your tests as :ref:`Blackbox Tests `. Most tests would
diff --git a/docs/index.rst b/docs/index.rst
index 40117d49..78435fbf 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -18,13 +18,9 @@ Jedi - an awesome autocompletion, static analysis and refactoring library for Py
:target: https://github.com/davidhalter/jedi/issues
:alt: The resolution time is the median time an issue or pull request stays open.
-.. image:: https://travis-ci.org/davidhalter/jedi.svg?branch=master
- :target: https://travis-ci.org/davidhalter/jedi
- :alt: Linux Tests
-
-.. image:: https://ci.appveyor.com/api/projects/status/mgva3bbawyma1new/branch/master?svg=true
- :target: https://ci.appveyor.com/project/davidhalter/jedi/branch/master
- :alt: Windows Tests
+.. image:: https://github.com/davidhalter/jedi/workflows/ci/badge.svg?branch=master
+ :target: https://github.com/davidhalter/jedi/actions
+ :alt: Tests
.. image:: https://coveralls.io/repos/davidhalter/jedi/badge.svg?branch=master
:target: https://coveralls.io/r/davidhalter/jedi
@@ -73,5 +69,4 @@ mailing list: https://groups.google.com/g/jedi-announce. To subscribe you can
simply send an empty email to ``jedi-announce+subscribe@googlegroups.com``.
- `Source Code on Github `_
-- `Travis Testing `_
- `Python Package Index `_
diff --git a/jedi/plugins/pytest.py b/jedi/plugins/pytest.py
index cec23733..d0dfba01 100644
--- a/jedi/plugins/pytest.py
+++ b/jedi/plugins/pytest.py
@@ -5,6 +5,7 @@ from jedi.inference.cache import inference_state_method_cache
from jedi.inference.imports import load_module_from_path
from jedi.inference.filters import ParserTreeFilter
from jedi.inference.base_value import NO_VALUES, ValueSet
+from jedi.inference.helpers import infer_call_of_leaf
_PYTEST_FIXTURE_MODULES = [
('_pytest', 'monkeypatch'),
@@ -147,18 +148,35 @@ class FixtureFilter(ParserTreeFilter):
def _filter(self, names):
for name in super()._filter(names):
funcdef = name.parent
+ # Class fixtures are not supported
if funcdef.type == 'funcdef':
- # Class fixtures are not supported
decorated = funcdef.parent
if decorated.type == 'decorated' and self._is_fixture(decorated):
yield name
def _is_fixture(self, decorated):
- for decorator in decorated.children:
+ decorators = decorated.children[0]
+ if decorators.type == 'decorators':
+ decorators = decorators.children
+ else:
+ decorators = [decorators]
+ for decorator in decorators:
dotted_name = decorator.children[1]
# A heuristic, this makes it faster.
if 'fixture' in dotted_name.get_code():
- for value in self.parent_context.infer_node(dotted_name):
+ if dotted_name.type == 'atom_expr':
+ # Since Python3.9 a decorator does not have dotted names
+ # anymore.
+ last_trailer = dotted_name.children[-1]
+ last_leaf = last_trailer.get_last_leaf()
+ if last_leaf == ')':
+ values = infer_call_of_leaf(
+ self.parent_context, last_leaf, cut_own_trailer=True)
+ else:
+ values = self.parent_context.infer_node(dotted_name)
+ else:
+ values = self.parent_context.infer_node(dotted_name)
+ for value in values:
if value.name.get_qualified_names(include_module_names=True) \
== ('_pytest', 'fixtures', 'fixture'):
return True
diff --git a/test/refactor.py b/test/refactor.py
index 582beeb6..7598bc7d 100644
--- a/test/refactor.py
+++ b/test/refactor.py
@@ -82,9 +82,9 @@ def _collect_file_tests(code, path, lines_to_execute):
yield RefactoringCase(name, first, line_nr, index, path, kwargs, type_, second)
if match is None:
- raise Exception("Didn't match any test")
+ raise Exception(f"Didn't match any test for {path}, {code!r}")
if match.end() != len(code):
- raise Exception("Didn't match until the end of the file in %s" % path)
+ raise Exception(f"Didn't match until the end of the file in {path}")
def collect_dir_tests(base_dir, test_files):
diff --git a/test/test_api/test_api.py b/test/test_api/test_api.py
index 51c0da3b..d2ebe62b 100644
--- a/test/test_api/test_api.py
+++ b/test/test_api/test_api.py
@@ -169,7 +169,8 @@ def test_reference_description(Script):
def test_get_line_code(Script):
def get_line_code(source, line=None, **kwargs):
- return Script(source).complete(line=line)[0].get_line_code(**kwargs)
+ # On Windows replace \r
+ return Script(source).complete(line=line)[0].get_line_code(**kwargs).replace('\r', '')
# On builtin
assert get_line_code('abs') == 'def abs(__n: SupportsAbs[_T]) -> _T: ...\n'
diff --git a/test/test_inference/test_extension.py b/test/test_inference/test_extension.py
index 962a8f9c..85cd7c01 100644
--- a/test/test_inference/test_extension.py
+++ b/test/test_inference/test_extension.py
@@ -13,17 +13,15 @@ def test_completions(Script):
assert len(s.complete()) >= 15
-def test_get_signatures_extension(Script):
+def test_get_signatures_extension(Script, environment):
if os.name == 'nt':
func = 'LoadLibrary'
- params = 1
else:
func = 'dlopen'
- params = 2
s = Script('import _ctypes; _ctypes.%s(' % (func,))
sigs = s.get_signatures()
assert len(sigs) == 1
- assert len(sigs[0].params) == params
+ assert len(sigs[0].params) in (1, 2)
def test_get_signatures_stdlib(Script):
diff --git a/test/test_inference/test_gradual/test_conversion.py b/test/test_inference/test_gradual/test_conversion.py
index c77a06b0..ea9ea013 100644
--- a/test/test_inference/test_gradual/test_conversion.py
+++ b/test/test_inference/test_gradual/test_conversion.py
@@ -69,11 +69,12 @@ def test_stub_get_line_code(Script):
code = 'from abc import ABC; ABC'
script = Script(code)
d, = script.goto(only_stubs=True)
- assert d.get_line_code() == 'class ABC(metaclass=ABCMeta): ...\n'
+ # Replace \r for tests on Windows
+ assert d.get_line_code().replace('\r', '') == 'class ABC(metaclass=ABCMeta): ...\n'
del parser_cache[script._inference_state.latest_grammar._hashed][d.module_path]
d, = Script(path=d.module_path).goto(d.line, d.column, only_stubs=True)
assert d.is_stub()
- assert d.get_line_code() == 'class ABC(metaclass=ABCMeta): ...\n'
+ assert d.get_line_code().replace('\r', '') == 'class ABC(metaclass=ABCMeta): ...\n'
def test_os_stat_result(Script):