Compare commits

..

11 Commits

Author SHA1 Message Date
Bruno Oliveira
180f93158e Introduce missing remark as commented in original PR
https://github.com/pytest-dev/pytest/pull/6870/files#r390667966
2020-05-08 12:59:26 -03:00
Bruno Oliveira
f1d7aa60b1 Preparing release version 4.6.10 2020-05-08 11:14:53 -04:00
Bruno Oliveira
ded772b288 Merge pull request #6870 from fermezz/backport-invocation-args 2020-05-08 08:04:49 -03:00
Bruno Oliveira
3d470555e8 Merge pull request #7190 from hroncok/backport-7179 2020-05-07 22:25:40 -03:00
Bruno Oliveira
2a5ca51fe8 [4.6] Merge pull request #7179 from asottile/py39 2020-05-07 23:22:29 +02:00
Fernando Mez
a6029ff2b7 BACKPORT: Introduction of Config.invocation_args 2020-03-26 16:41:08 -03:00
Bruno Oliveira
020831d868 Merge pull request #6884 from fermezz/use-github-actions
Fix travis config and coverage report.
2020-03-26 12:42:55 -03:00
Fernando Mez
c5831ac98f Fix CI config and coverage report 2020-03-12 16:58:33 -03:00
Bruno Oliveira
f606fef19d [4.6] Remove usage of parser module, deprecated in Python 3.9 (#6408)
[4.6] Remove usage of parser module, deprecated in Python 3.9
2020-01-06 13:07:40 -03:00
Bruno Oliveira
24898e0640 Remove usage of parser module, deprecated in Python 3.9
Fix #6404
2020-01-06 08:58:39 -03:00
Anthony Sottile
b39b867967 Merge pull request #6391 from asottile/release-4.6.9
Preparing release version 4.6.9
2020-01-04 15:59:26 -05:00
18 changed files with 416 additions and 148 deletions

191
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,191 @@
name: main
on:
push:
branches:
- 4.6.x
tags:
- "*"
pull_request:
branches:
- 4.6.x
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
name: [
"windows-py27",
"windows-py35",
"windows-py36",
"windows-py37",
"windows-py37-pluggy",
"windows-py38",
"ubuntu-py27-pluggy",
"ubuntu-py27-nobyte",
"ubuntu-py37",
"ubuntu-py37-pluggy",
"ubuntu-py37-pexpect-py37-twisted",
"ubuntu-py37-freeze",
"ubuntu-pypy",
"ubuntu-pypy3",
"macos-py27",
"macos-py38",
]
include:
# Windows jobs
- name: "windows-py27"
python: "2.7"
os: windows-latest
tox_env: "py27-xdist"
use_coverage: true
- name: "windows-py35"
python: "3.5"
os: windows-latest
tox_env: "py35-xdist"
use_coverage: true
- name: "windows-py36"
python: "3.6"
os: windows-latest
tox_env: "py36-xdist"
use_coverage: true
- name: "windows-py37"
python: "3.7"
os: windows-latest
tox_env: "py37-twisted-numpy"
use_coverage: true
- name: "windows-py37-pluggy"
python: "3.7"
os: windows-latest
tox_env: "py37-pluggymaster-xdist"
use_coverage: true
- name: "windows-py38"
python: "3.8"
os: windows-latest
tox_env: "py38-xdist"
use_coverage: true
# Ubuntu jobs find the rest of them in .travis.yml
- name: "ubuntu-py27-pluggy"
python: "2.7"
os: ubuntu-latest
tox_env: "py27-pluggymaster-xdist"
use_coverage: true
- name: "ubuntu-py27-nobyte"
python: "2.7"
os: ubuntu-latest
tox_env: "py27-nobyte-numpy-xdist"
use_coverage: true
- name: "ubuntu-py37"
python: "3.7"
os: ubuntu-latest
tox_env: "py37-lsof-numpy-xdist"
use_coverage: true
- name: "ubuntu-py37-pluggy"
python: "3.7"
os: ubuntu-latest
tox_env: "py37-pluggymaster-xdist"
use_coverage: true
- name: "ubuntu-py37-pexpect-py37-twisted"
python: "3.7"
os: ubuntu-latest
tox_env: "py37-pexpect,py37-twisted"
use_coverage: true
- name: "ubuntu-py37-freeze"
python: "3.7"
os: ubuntu-latest
tox_env: "py37-freeze"
- name: "ubuntu-pypy"
python: "pypy2"
os: ubuntu-latest
tox_env: "pypy-xdist"
use_coverage: true
- name: "ubuntu-pypy3"
python: "pypy3"
os: ubuntu-latest
tox_env: "pypy3-xdist"
use_coverage: true
# MacOS jobs
- name: "macos-py27"
python: "2.7"
os: macos-latest
tox_env: "py27-xdist"
use_coverage: true
- name: "macos-py38"
python: "3.8"
os: macos-latest
tox_env: "py38-xdist"
use_coverage: true
steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python }} on ${{ matrix.os }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox coverage
- name: Test without coverage
if: "! matrix.use_coverage"
run: "tox -e ${{ matrix.tox_env }}"
- name: Test with coverage
if: "matrix.use_coverage"
env:
_PYTEST_TOX_COVERAGE_RUN: "coverage run -m"
COVERAGE_PROCESS_START: ".coveragerc"
_PYTEST_TOX_EXTRA_DEP: "coverage-enable-subprocess"
run: "tox -vv -e ${{ matrix.tox_env }}"
- name: Prepare coverage token
if: (matrix.use_coverage && ( github.repository == 'pytest-dev/pytest' || github.event_name == 'pull_request' ))
run: |
python scripts/append_codecov_token.py
- name: Report coverage
if: (matrix.use_coverage)
env:
CODECOV_NAME: ${{ matrix.name }}
run: bash scripts/report-coverage.sh -F GHA,${{ runner.os }}
deploy:
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') && github.repository == 'pytest-dev/pytest'
runs-on: ubuntu-latest
needs: [build]
steps:
- uses: actions/checkout@v1
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: "3.7"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install --upgrade wheel setuptools tox
- name: Build package
run: |
python setup.py sdist bdist_wheel
- name: Publish package to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
user: __token__
password: ${{ secrets.pypi_token }}
- name: Publish GitHub release notes
env:
GH_RELEASE_NOTES_TOKEN: ${{ secrets.release_notes }}
run: |
sudo apt-get install pandoc
tox -e publish-gh-release-notes

View File

@@ -1,17 +1,12 @@
language: python language: python
dist: xenial dist: xenial
stages: python: '3.7.4'
- baseline
- name: test
if: repo = pytest-dev/pytest AND tag IS NOT present
- name: deploy
if: repo = pytest-dev/pytest AND tag IS present
python: '3.7'
cache: false cache: false
env: env:
global: global:
- PYTEST_ADDOPTS=-vv - PYTEST_ADDOPTS="-vv --showlocals --durations=100 --exitfirst"
- PYTEST_COVERAGE=1
# setuptools-scm needs all tags in order to obtain a proper version # setuptools-scm needs all tags in order to obtain a proper version
git: git:
@@ -22,113 +17,44 @@ install:
jobs: jobs:
include: include:
# OSX tests - first (in test stage), since they are the slower ones.
- &test-macos
os: osx
osx_image: xcode10.1
language: generic
# Coverage for:
# - py2 with symlink in test_cmdline_python_package_symlink.
env: TOXENV=py27-xdist PYTEST_COVERAGE=1
before_install:
- python -V
- test $(python -c 'import sys; print("%d%d" % sys.version_info[0:2])') = 27
- <<: *test-macos
env: TOXENV=py37-pexpect,py37-xdist PYTEST_COVERAGE=1
before_install:
- which python3
- python3 -V
- ln -sfn "$(which python3)" /usr/local/bin/python
- python -V
- test $(python -c 'import sys; print("%d%d" % sys.version_info[0:2])') = 37
# Full run of latest (major) supported versions, without xdist.
- env: TOXENV=py27
python: '2.7'
- env: TOXENV=py37
python: '3.7'
# Coverage tracking is slow with pypy, skip it.
- env: TOXENV=pypy-xdist
python: 'pypy'
- env: TOXENV=pypy3-xdist
python: 'pypy3'
- env: TOXENV=py34-xdist
python: '3.4'
- env: TOXENV=py35-xdist
python: '3.5'
# Coverage for: # Coverage for:
# - pytester's LsofFdLeakChecker
# - TestArgComplete (linux only) # - TestArgComplete (linux only)
# - numpy # - numpy
# Empty PYTEST_ADDOPTS to run this non-verbose. # - verbose=0
- env: TOXENV=py37-lsof-numpy-xdist PYTEST_COVERAGE=1 PYTEST_ADDOPTS=
# Specialized factors for py27.
- env: TOXENV=py27-nobyte-numpy-xdist
python: '2.7'
- env: TOXENV=py27-pluggymaster-xdist
python: '2.7'
# Specialized factors for py37.
# Coverage for:
# - test_sys_breakpoint_interception (via pexpect).
- env: TOXENV=py37-pexpect,py37-twisted PYTEST_COVERAGE=1
- env: TOXENV=py37-pluggymaster-xdist
- env: TOXENV=py37-freeze
# Jobs only run via Travis cron jobs (currently daily).
- env: TOXENV=py38-xdist
python: '3.8-dev'
if: type = cron
- stage: baseline - stage: baseline
# Coverage for: env: TOXENV=py27-xdist
# - _pytest.unittest._handle_skip (via pexpect).
env: TOXENV=py27-pexpect,py27-twisted PYTEST_COVERAGE=1
python: '2.7' python: '2.7'
# Use py36 here for faster baseline.
- env: TOXENV=py36-xdist - env: TOXENV=py38-xdist
python: '3.6' python: '3.8'
- env: TOXENV=linting,docs,doctesting PYTEST_COVERAGE=1
- stage: tests
# - _pytest.unittest._handle_skip (via pexpect).
env: TOXENV=py27-pexpect,py27-twisted
python: '2.7'
- env: TOXENV=py35-xdist
python: '3.5.9'
- env: TOXENV=py36-xdist PYTEST_REORDER_TESTS=0
python: '3.6.9'
- env: TOXENV=py37-numpy-pexpect-twisted
python: '3.7.4'
# - test_sys_breakpoint_interception (via pexpect).
- env: TOXENV=py37-pexpect,py37-twisted
python: '3.7.4'
# Run also non-verbosely, to gain coverage
- env: TOXENV=py38-xdist PYTEST_ADDOPTS=""
python: '3.8'
- env: TOXENV=linting,docs,doctesting
cache: cache:
directories: directories:
- $HOME/.cache/pre-commit - $HOME/.cache/pre-commit
- stage: deploy
python: '3.6'
install: pip install -U setuptools setuptools_scm tox
script: skip
# token to upload github release notes: GH_RELEASE_NOTES_TOKEN
env:
- secure: "OjOeL7/0JUDkV00SsTs732e8vQjHynpbG9FKTNtZZJ+1Zn4Cib+hAlwmlBnvVukML0X60YpcfjnC4quDOIGLPsh5zeXnvJmYtAIIUNQXjWz8NhcGYrhyzuP1rqV22U68RTCdmOq3lMYU/W2acwHP7T49PwJtOiUM5kF120UAQ0Zi5EmkqkIvH8oM5mO9Dlver+/U7Htpz9rhKrHBXQNCMZI6yj2aUyukqB2PN2fjAlDbCF//+FmvYw9NjT4GeFOSkTCf4ER9yfqs7yglRfwiLtOCZ2qKQhWZNsSJDB89rxIRXWavJUjJKeY2EW2/NkomYJDpqJLIF4JeFRw/HhA47CYPeo6BJqyyNV+0CovL1frpWfi9UQw2cMbgFUkUIUk3F6DD59PHNIOX2R/HX56dQsw7WKl3QuHlCOkICXYg8F7Ta684IoKjeTX03/6QNOkURfDBwfGszY0FpbxrjCSWKom6RyZdyidnESaxv9RzjcIRZVh1rp8KMrwS1OrwRSdG0zjlsPr49hWMenN/8fKgcHTV4/r1Tj6mip0dorSRCrgUNIeRBKgmui6FS8642ab5JNKOxMteVPVR2sFuhjOQ0Jy+PmvceYY9ZMWc3+/B/KVh0dZ3hwvLGZep/vxDS2PwCA5/xw31714vT5LxidKo8yECjBynMU/wUTTS695D3NY="
addons:
apt:
packages:
# required by publish_gh_release_notes
- pandoc
after_deploy: tox -e publish_gh_release_notes
deploy:
provider: pypi
user: nicoddemus
distributions: sdist bdist_wheel
skip_upload_docs: true
password:
secure: xanTgTUu6XDQVqB/0bwJQXoDMnU5tkwZc5koz6mBkkqZhKdNOi2CLoC1XhiSZ+ah24l4V1E0GAqY5kBBcy9d7NVe4WNg4tD095LsHw+CRU6/HCVIFfyk2IZ+FPAlguesCcUiJSXOrlBF+Wj68wEvLoK7EoRFbJeiZ/f91Ww1sbtDlqXABWGHrmhPJL5Wva7o7+wG7JwJowqdZg1pbQExsCc7b53w4v2RBu3D6TJaTAzHiVsW+nUSI67vKI/uf+cR/OixsTfy37wlHgSwihYmrYLFls3V0bSpahCim3bCgMaFZx8S8xrdgJ++PzBCof2HeflFKvW+VCkoYzGEG4NrTWJoNz6ni4red9GdvfjGH3YCjAKS56h9x58zp2E5rpsb/kVq5/45xzV+dq6JRuhQ1nJWjBC6fSKAc/bfwnuFK3EBxNLkvBssLHvsNjj5XG++cB8DdS9wVGUqjpoK4puaXUWFqy4q3S9F86HEsKNgExtieA9qNx+pCIZVs6JCXZNjr0I5eVNzqJIyggNgJG6RyravsU35t9Zd9doL5g4Y7UKmAGTn1Sz24HQ4sMQgXdm2SyD8gEK5je4tlhUvfGtDvMSlstq71kIn9nRpFnqB6MFlbYSEAZmo8dGbCquoUc++6Rum208wcVbrzzVtGlXB/Ow9AbFMYeAGA0+N/K1e59c=
on:
tags: true
repo: pytest-dev/pytest
matrix:
allow_failures:
- python: '3.8-dev'
env: TOXENV=py38-xdist
# Temporary (https://github.com/pytest-dev/pytest/pull/5334).
- env: TOXENV=pypy3-xdist
python: 'pypy3'
before_script: before_script:
- | - |
# Do not (re-)upload coverage with cron runs. # Do not (re-)upload coverage with cron runs.
@@ -142,27 +68,13 @@ before_script:
export _PYTEST_TOX_COVERAGE_RUN="coverage run -m" export _PYTEST_TOX_COVERAGE_RUN="coverage run -m"
export _PYTEST_TOX_EXTRA_DEP=coverage-enable-subprocess export _PYTEST_TOX_EXTRA_DEP=coverage-enable-subprocess
fi fi
script: env COLUMNS=120 python -m tox
script: tox
after_success: after_success:
- | - |
if [[ "$PYTEST_COVERAGE" = 1 ]]; then if [[ "$PYTEST_COVERAGE" = 1 ]]; then
set -e env CODECOV_NAME="$TOXENV-$TRAVIS_OS_NAME" scripts/report-coverage.sh
# Add last TOXENV to $PATH.
PATH="$PWD/.tox/${TOXENV##*,}/bin:$PATH"
coverage combine
coverage xml
coverage report -m
bash <(curl -s https://codecov.io/bash) -Z -X gcov -X coveragepy -X search -X xcode -X gcovout -X fix -f coverage.xml -n $TOXENV-$TRAVIS_OS_NAME
fi fi
branches:
notifications: only:
irc: - 4.6.x
channels:
- "chat.freenode.net#pytest"
on_success: change
on_failure: change
skip_join: true
email:
- pytest-commit@python.org

View File

@@ -92,6 +92,7 @@ Evan Kepner
Fabien Zarifian Fabien Zarifian
Fabio Zadrozny Fabio Zadrozny
Feng Ma Feng Ma
Fernando Mezzabotta Rey
Florian Bruhin Florian Bruhin
Floris Bruynooghe Floris Bruynooghe
Gabriel Reis Gabriel Reis

View File

@@ -18,6 +18,22 @@ with advance notice in the **Deprecations** section of releases.
.. towncrier release notes start .. towncrier release notes start
pytest 4.6.10 (2020-05-08)
==========================
Features
--------
- `#6870 <https://github.com/pytest-dev/pytest/issues/6870>`_: New ``Config.invocation_args`` attribute containing the unchanged arguments passed to ``pytest.main()``.
Remark: while this is technically a new feature and according to our `policy <https://docs.pytest.org/en/latest/py27-py34-deprecation.html#what-goes-into-4-6-x-releases>`_ it should not have been backported, we have opened an exception in this particular case because it fixes a serious interaction with ``pytest-xdist``, so it can also be considered a bugfix.
Trivial/Internal Changes
------------------------
- `#6404 <https://github.com/pytest-dev/pytest/issues/6404>`_: Remove usage of ``parser`` module, deprecated in Python 3.9.
pytest 4.6.9 (2020-01-04) pytest 4.6.9 (2020-01-04)
========================= =========================

View File

@@ -6,6 +6,7 @@ Release announcements
:maxdepth: 2 :maxdepth: 2
release-4.6.10
release-4.6.9 release-4.6.9
release-4.6.8 release-4.6.8
release-4.6.7 release-4.6.7

View File

@@ -0,0 +1,20 @@
pytest-4.6.10
=======================================
pytest 4.6.10 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Anthony Sottile
* Bruno Oliveira
* Fernando Mez
Happy testing,
The pytest Development Team

View File

@@ -434,10 +434,11 @@ Running it results in some skips if we don't have all the python interpreters in
.. code-block:: pytest .. code-block:: pytest
. $ pytest -rs -q multipython.py . $ pytest -rs -q multipython.py
......sss......ssssssssssss [100%] ...ssssssssssssssssssssssss [100%]
========================= short test summary info ========================== ========================= short test summary info ==========================
SKIPPED [15] $REGENDOC_TMPDIR/CWD/multipython.py:31: 'python3.5' not found SKIPPED [12] $REGENDOC_TMPDIR/CWD/multipython.py:31: 'python3.4' not found
12 passed, 15 skipped in 0.12 seconds SKIPPED [12] $REGENDOC_TMPDIR/CWD/multipython.py:31: 'python3.5' not found
3 passed, 24 skipped in 0.12 seconds
Indirect parametrization of optional implementations/imports Indirect parametrization of optional implementations/imports
-------------------------------------------------------------------- --------------------------------------------------------------------

View File

@@ -436,7 +436,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
items = [1, 2, 3] items = [1, 2, 3]
print("items is %r" % items) print("items is %r" % items)
> a, b = items.pop() > a, b = items.pop()
E TypeError: 'int' object is not iterable E TypeError: cannot unpack non-iterable int object
failure_demo.py:182: TypeError failure_demo.py:182: TypeError
--------------------------- Captured stdout call --------------------------- --------------------------- Captured stdout call ---------------------------
@@ -515,7 +515,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
def test_z2_type_error(self): def test_z2_type_error(self):
items = 3 items = 3
> a, b = items > a, b = items
E TypeError: 'int' object is not iterable E TypeError: cannot unpack non-iterable int object
failure_demo.py:222: TypeError failure_demo.py:222: TypeError
______________________ TestMoreErrors.test_startswith ______________________ ______________________ TestMoreErrors.test_startswith ______________________

View File

@@ -28,7 +28,7 @@ Install ``pytest``
.. code-block:: bash .. code-block:: bash
$ pytest --version $ pytest --version
This is pytest version 4.x.y, imported from $PYTHON_PREFIX/lib/python3.6/site-packages/pytest.py This is pytest version 4.x.y, imported from $PYTHON_PREFIX/lib/python3.7/site-packages/pytest.py
.. _`simpletest`: .. _`simpletest`:

View File

@@ -17,9 +17,9 @@ are available on PyPI.
While pytest ``5.0`` will be the new mainstream and development version, until **January 2020** While pytest ``5.0`` will be the new mainstream and development version, until **January 2020**
the pytest core team plans to make bug-fix releases of the pytest ``4.6`` series by the pytest core team plans to make bug-fix releases of the pytest ``4.6`` series by
back-porting patches to the ``4.6-maintenance`` branch that affect Python 2 users. back-porting patches to the ``4.6.x`` branch that affect Python 2 users.
**After 2020**, the core team will no longer actively backport patches, but the ``4.6-maintenance`` **After 2020**, the core team will no longer actively backport patches, but the ``4.6.x``
branch will continue to exist so the community itself can contribute patches. The core team will branch will continue to exist so the community itself can contribute patches. The core team will
be happy to accept those patches and make new ``4.6`` releases **until mid-2020**. be happy to accept those patches and make new ``4.6`` releases **until mid-2020**.

View File

@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
"""
Appends the codecov token to the 'codecov.yml' file at the root of the repository.
This is done by CI during PRs and builds on the pytest-dev repository so we can upload coverage, at least
until codecov grows some native integration like it has with Travis and AppVeyor.
See discussion in https://github.com/pytest-dev/pytest/pull/6441 for more information.
"""
import os.path
from textwrap import dedent
def main():
this_dir = os.path.dirname(__file__)
cov_file = os.path.join(this_dir, "..", "codecov.yml")
assert os.path.isfile(cov_file), "{cov_file} does not exist".format(
cov_file=cov_file
)
with open(cov_file, "a") as f:
# token from: https://codecov.io/gh/pytest-dev/pytest/settings
# use same URL to regenerate it if needed
text = dedent(
"""
codecov:
token: "1eca3b1f-31a2-4fb8-a8c3-138b441b50a7"
"""
)
f.write(text)
print("Token updated:", cov_file)
if __name__ == "__main__":
main()

18
scripts/report-coverage.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -e
set -x
if [ -z "$TOXENV" ]; then
python -m pip install coverage
else
# Add last TOXENV to $PATH.
PATH="$PWD/.tox/${TOXENV##*,}/bin:$PATH"
fi
python -m coverage combine
python -m coverage xml
python -m coverage report -m
# Set --connect-timeout to work around https://github.com/curl/curl/issues/4461
curl -S -L --connect-timeout 5 --retry 6 -s https://codecov.io/bash -o codecov-upload.sh
bash codecov-upload.sh -Z -X fix -f coverage.xml "$@"

View File

@@ -30,6 +30,8 @@ classifiers =
Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
platforms = unix, linux, osx, cygwin, win32 platforms = unix, linux, osx, cygwin, win32
[options] [options]

View File

@@ -123,18 +123,13 @@ class Source(object):
""" return True if source is parseable, heuristically """ return True if source is parseable, heuristically
deindenting it by default. deindenting it by default.
""" """
from parser import suite as syntax_checker
if deindent: if deindent:
source = str(self.deindent()) source = str(self.deindent())
else: else:
source = str(self) source = str(self)
try: try:
# compile(source+'\n', "x", "exec") ast.parse(source)
syntax_checker(source + "\n") except (SyntaxError, ValueError, TypeError):
except KeyboardInterrupt:
raise
except Exception:
return False return False
else: else:
return True return True

View File

@@ -13,6 +13,7 @@ import sys
import types import types
import warnings import warnings
import attr
import py import py
import six import six
from packaging.version import Version from packaging.version import Version
@@ -35,6 +36,7 @@ from _pytest.compat import lru_cache
from _pytest.compat import safe_str from _pytest.compat import safe_str
from _pytest.outcomes import fail from _pytest.outcomes import fail
from _pytest.outcomes import Skipped from _pytest.outcomes import Skipped
from _pytest.pathlib import Path
from _pytest.warning_types import PytestConfigWarning from _pytest.warning_types import PytestConfigWarning
hookimpl = HookimplMarker("pytest") hookimpl = HookimplMarker("pytest")
@@ -154,10 +156,15 @@ builtin_plugins = set(default_plugins)
builtin_plugins.add("pytester") builtin_plugins.add("pytester")
def get_config(args=None): def get_config(args=None, plugins=None):
# subsequent calls to main will create a fresh instance # subsequent calls to main will create a fresh instance
pluginmanager = PytestPluginManager() pluginmanager = PytestPluginManager()
config = Config(pluginmanager) config = Config(
pluginmanager,
invocation_params=Config.InvocationParams(
args=args, plugins=plugins, dir=Path().resolve()
),
)
if args is not None: if args is not None:
# Handle any "-p no:plugin" args. # Handle any "-p no:plugin" args.
@@ -190,7 +197,7 @@ def _prepareconfig(args=None, plugins=None):
msg = "`args` parameter expected to be a list or tuple of strings, got: {!r} (type: {})" msg = "`args` parameter expected to be a list or tuple of strings, got: {!r} (type: {})"
raise TypeError(msg.format(args, type(args))) raise TypeError(msg.format(args, type(args)))
config = get_config(args) config = get_config(args, plugins)
pluginmanager = config.pluginmanager pluginmanager = config.pluginmanager
try: try:
if plugins: if plugins:
@@ -686,13 +693,52 @@ def _iter_rewritable_modules(package_files):
class Config(object): class Config(object):
""" access to configuration values, pluginmanager and plugin hooks. """ """
Access to configuration values, pluginmanager and plugin hooks.
:ivar PytestPluginManager pluginmanager: the plugin manager handles plugin registration and hook invocation.
:ivar argparse.Namespace option: access to command line option as attributes.
:ivar InvocationParams invocation_params:
Object containing the parameters regarding the ``pytest.main``
invocation.
Contains the followinig read-only attributes:
* ``args``: list of command-line arguments as passed to ``pytest.main()``.
* ``plugins``: list of extra plugins, might be None
* ``dir``: directory where ``pytest.main()`` was invoked from.
"""
@attr.s(frozen=True)
class InvocationParams(object):
"""Holds parameters passed during ``pytest.main()``
.. note::
Currently the environment variable PYTEST_ADDOPTS is also handled by
pytest implicitly, not being part of the invocation.
Plugins accessing ``InvocationParams`` must be aware of that.
"""
args = attr.ib()
plugins = attr.ib()
dir = attr.ib()
def __init__(self, pluginmanager, invocation_params=None, *args):
from .argparsing import Parser, FILE_OR_DIR
if invocation_params is None:
invocation_params = self.InvocationParams(
args=(), plugins=None, dir=Path().resolve()
)
def __init__(self, pluginmanager):
#: access to command line option as attributes. #: access to command line option as attributes.
#: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead #: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead
self.option = argparse.Namespace() self.option = argparse.Namespace()
from .argparsing import Parser, FILE_OR_DIR
self.invocation_params = invocation_params
_a = FILE_OR_DIR _a = FILE_OR_DIR
self._parser = Parser( self._parser = Parser(
@@ -709,9 +755,13 @@ class Config(object):
self._cleanup = [] self._cleanup = []
self.pluginmanager.register(self, "pytestconfig") self.pluginmanager.register(self, "pytestconfig")
self._configured = False self._configured = False
self.invocation_dir = py.path.local()
self.hook.pytest_addoption.call_historic(kwargs=dict(parser=self._parser)) self.hook.pytest_addoption.call_historic(kwargs=dict(parser=self._parser))
@property
def invocation_dir(self):
"""Backward compatibility"""
return py.path.local(str(self.invocation_params.dir))
def add_cleanup(self, func): def add_cleanup(self, func):
""" Add a function to be called when the config object gets out of """ Add a function to be called when the config object gets out of
use (usually coninciding with pytest_unconfigure).""" use (usually coninciding with pytest_unconfigure)."""

View File

@@ -501,7 +501,7 @@ def test_getfslineno():
class B(object): class B(object):
pass pass
B.__name__ = "B2" B.__name__ = B.__qualname__ = "B2"
assert getfslineno(B)[1] == -1 assert getfslineno(B)[1] == -1

View File

@@ -19,6 +19,7 @@ from _pytest.main import EXIT_NOTESTSCOLLECTED
from _pytest.main import EXIT_OK from _pytest.main import EXIT_OK
from _pytest.main import EXIT_TESTSFAILED from _pytest.main import EXIT_TESTSFAILED
from _pytest.main import EXIT_USAGEERROR from _pytest.main import EXIT_USAGEERROR
from _pytest.pathlib import Path
class TestParseIni(object): class TestParseIni(object):
@@ -1222,6 +1223,29 @@ def test_config_does_not_load_blocked_plugin_from_args(testdir):
assert result.ret == EXIT_USAGEERROR assert result.ret == EXIT_USAGEERROR
def test_invocation_args(testdir):
"""Ensure that Config.invocation_* arguments are correctly defined"""
class DummyPlugin(object):
pass
p = testdir.makepyfile("def test(): pass")
plugin = DummyPlugin()
rec = testdir.inline_run(p, "-v", plugins=[plugin])
calls = rec.getcalls("pytest_runtest_protocol")
assert len(calls) == 1
call = calls[0]
config = call.item.config
assert config.invocation_params.args == [p, "-v"]
assert config.invocation_params.dir == Path(str(testdir.tmpdir))
plugins = config.invocation_params.plugins
assert len(plugins) == 2
assert plugins[0] is plugin
assert type(plugins[1]).__name__ == "Collect" # installed by testdir.inline_run()
@pytest.mark.parametrize( @pytest.mark.parametrize(
"plugin", "plugin",
[ [

View File

@@ -11,6 +11,7 @@ envlist =
py36 py36
py37 py37
py38 py38
py39
pypy pypy
pypy3 pypy3
{py27,py37}-{pexpect,xdist,twisted,numpy,pluggymaster} {py27,py37}-{pexpect,xdist,twisted,numpy,pluggymaster}
@@ -119,6 +120,7 @@ changedir = testing/freeze
# Disable PEP 517 with pip, which does not work with PyInstaller currently. # Disable PEP 517 with pip, which does not work with PyInstaller currently.
deps = deps =
pyinstaller pyinstaller
setuptools < 45.0.0
commands = commands =
{envpython} create_executable.py {envpython} create_executable.py
{envpython} tox_run.py {envpython} tox_run.py