From f80f2c0f4e13b6bb77c8b160fdb890224df62160 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 16 Feb 2020 14:53:09 +0100 Subject: [PATCH 01/71] README: review badges and update PyPI URL. --- README.rst | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 947a268..6e3940b 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,16 @@ -.. image:: https://travis-ci.org/RKrahl/pytest-dependency.svg?branch=master - :target: https://travis-ci.org/RKrahl/pytest-dependency +|travis| |rtd| |pypi| + +.. |travis| image:: https://img.shields.io/travis/com/RKrahl/pytest-dependency + :target: https://travis-ci.com/RKrahl/pytest-dependency + :alt: Travis build status + +.. |rtd| image:: https://img.shields.io/readthedocs/pytest-dependency/latest + :target: https://pytest-dependency.readthedocs.io/en/latest/ + :alt: Documentation build status + +.. |pypi| image:: https://img.shields.io/pypi/v/pytest-dependency + :target: https://pypi.org/project/pytest-dependency/ + :alt: PyPI version pytest-dependency - Manage dependencies of tests ================================================ @@ -14,7 +25,7 @@ Download The latest release version can be found at PyPI, see - https://pypi.python.org/pypi/pytest_dependency + https://pypi.org/project/pytest-dependency/ System requirements From e623b42322b245fb9809caa635e53a1cbad1e920 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 29 Mar 2020 17:47:53 +0200 Subject: [PATCH 02/71] Use python3 in Makefile. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7d086ac..1a25ca5 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PYTHON = python +PYTHON = python3 BUILDDIR = $(CURDIR)/build From a811464c5ff39db6dde78331c75915a8e4f0b213 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 29 Mar 2020 18:12:52 +0200 Subject: [PATCH 03/71] Review Sphinx config. --- Makefile | 1 - doc/Makefile | 55 ++++------- doc/src/conf.py | 252 +++++++++++++++++------------------------------- 3 files changed, 103 insertions(+), 205 deletions(-) diff --git a/Makefile b/Makefile index 1a25ca5..3f28e86 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,6 @@ doc-html: .version clean: rm -f *~ tests/*~ rm -rf build - $(MAKE) -C doc clean distclean: clean rm -rf .cache tests/.cache .pytest_cache tests/.pytest_cache diff --git a/doc/Makefile b/doc/Makefile index 308a023..2d289ba 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -1,48 +1,27 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build -PAPER = a4 - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) src - -# Subdirectories of src that are supposed to be there but that may be -# empty and may thus be missing after a git checkout. -SRCDIRS = src/_static src/_templates - +SPHINXPROJ = pytest-dependency +SOURCEDIR = src +BUILDDIR = . +BUILDERS = html dirhtml singlehtml htmlhelp qthelp devhelp epub \ + latex latexpdf man texinfo text gettext linkcheck xml \ + json pickle -html: $(SRCDIRS) - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) html +# Subdirectories of the source directory that are supposed to be there +# but that may be empty and may thus be missing after a git checkout. +STATIC_SOURCEDIRS = $(SOURCEDIR)/_static $(SOURCEDIR)/_templates -latex: $(SRCDIRS) - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) latex -latexpdf: latex - $(MAKE) -C latex all-pdf +help: + $(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -linkcheck: $(SRCDIRS) - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) linkcheck +$(BUILDERS): $(STATIC_SOURCEDIRS) + $(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -doctest: $(SRCDIRS) - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) doctest - -clean: - rm -f *~ examples/*~ src/*~ - -distclean: clean - rm -rf doctrees html latex linkcheck doctest - rm -f examples/*.pyc - rm -rf examples/__pycache__ - -src/_static: - mkdir $@ +distclean: + rm -rf doctrees $(BUILDERS) -src/_templates: +$(STATIC_SOURCEDIRS): mkdir $@ -.PHONY: html latex latexpdf linkcheck doctest clean distclean +.PHONY: help distclean $(BUILDERS) diff --git a/doc/src/conf.py b/doc/src/conf.py index 15eb749..5a4ae99 100644 --- a/doc/src/conf.py +++ b/doc/src/conf.py @@ -1,244 +1,164 @@ +# -*- coding: utf-8 -*- # -# pytest-dependency documentation build configuration file. +# Configuration file for the Sphinx documentation builder. # -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +from pathlib import Path +import sys +topdir = Path("../..").resolve() +sys.path.insert(0, str(topdir)) -import sys, os -import os.path -# The top source directory. This file is exec'ed with its directory -# as cwd. This is "doc/src" relativ to the top source directory. So -# we need to go 2 dirs up. -topdir = os.path.dirname(os.path.dirname(os.getcwd())) +# -- Project information ----------------------------------------------------- -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +project = 'pytest-dependency' +copyright = '2016–2020, Rolf Krahl' +author = 'Rolf Krahl' + +# The full version, including alpha/beta/rc tags +with (topdir / ".version").open("rt") as f: + release = f.read() +# The short X.Y version +version = ".".join(release.split(".")[0:2]) -# -- General configuration ----------------------------------------------------- + +# -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# +# needs_sphinx = '1.0' -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest'] +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', +] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] -# The suffix of source filenames. +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] source_suffix = '.rst' -# The encoding of source files. -#source_encoding = 'utf-8-sig' - # The master toctree document. master_doc = 'index' -# General information about the project. -project = u'pytest-dependency' -copyright = u'2016-2020, Rolf Krahl' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -with open(os.path.join(topdir, ".version"), "rt") as f: - release = f.read() -version = ".".join(release.split(".")[0:2]) - # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path . exclude_patterns = [] -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# -- Options for autodoc extension ------------------------------------------- -# -- Options for HTML output --------------------------------------------------- +autodoc_member_order = 'bysource' + +# -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +# +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None +# +# html_theme_options = {} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} # If true, links to the reST sources are added to the pages. html_show_sourcelink = False -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. -htmlhelp_basename = 'pytest-dependency-doc' +htmlhelp_basename = '%s-doc' % project -# -- Options for LaTeX output -------------------------------------------------- +# -- Options for LaTeX output ------------------------------------------------ latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', + # The paper size ('letterpaper' or 'a4paper'). + # + 'papersize': 'a4paper', -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', -# Additional stuff for the LaTeX preamble. -#'preamble': '', + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). latex_documents = [ - ('index', 'pytest-dependency.tex', u'pytest-dependency Documentation', - u'Rolf Krahl', 'manual'), + (master_doc, '%s.tex' % project, '%s Documentation' % project, + author, 'manual'), ] -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- +# -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'pytest-dependency', u'pytest-dependency Documentation', - [u'Rolf Krahl'], 1) + (master_doc, project, '%s Documentation' % project, + [author], 1) ] -# If true, show URL addresses after external links. -#man_show_urls = False - -# -- Options for Texinfo output ------------------------------------------------ +# -- Options for Texinfo output ---------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'pytest-dependency', u'pytest-dependency Documentation', - u'Rolf Krahl', 'pytest-dependency', - 'Call pytest from a distutils setup.py script.', 'Miscellaneous'), + (master_doc, project, '%s Documentation' % project, + author, project, 'One line description of project.', + 'Miscellaneous'), ] -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# -- Extension configuration ------------------------------------------------- From 1ea80e4ecd4a59fe5166f4f4ae39d91317f4a16f Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 29 Mar 2020 18:38:09 +0200 Subject: [PATCH 04/71] Update copyright, use en dash for date range. --- doc/src/about.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/about.rst b/doc/src/about.rst index b46b4e2..d480b69 100644 --- a/doc/src/about.rst +++ b/doc/src/about.rst @@ -69,9 +69,9 @@ those results that really matter. Copyright and License --------------------- -- Copyright 2013-2015 +- Copyright 2013–2015 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH -- Copyright 2016-2018 Rolf Krahl +- Copyright 2016–2020 Rolf Krahl Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may From 2b8df76fdd8313381ed7427896de17a3e8258ffc Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 29 Mar 2020 18:47:58 +0200 Subject: [PATCH 05/71] Fix travis build. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f5745fa..543a750 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ python: - "3.7" - "3.8" install: pip install -r requirements.txt -script: make test +script: make test PYTHON=python # Local Variables: # mode: yaml From be1051bf81825e1e57b7f94d91e702059415c1e0 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Fri, 10 Apr 2020 11:16:09 +0200 Subject: [PATCH 06/71] Minor tweaks in the README. --- README.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/README.rst b/README.rst index 6e3940b..2719144 100644 --- a/README.rst +++ b/README.rst @@ -12,7 +12,7 @@ :target: https://pypi.org/project/pytest-dependency/ :alt: PyPI version -pytest-dependency - Manage dependencies of tests +pytest-dependency – Manage dependencies of tests ================================================ This pytest plugin manages dependencies of tests. It allows to mark @@ -23,9 +23,9 @@ skipped if any of the dependencies did fail or has been skipped. Download -------- -The latest release version can be found at PyPI, see +The latest release version can be found `at PyPI`__. - https://pypi.org/project/pytest-dependency/ +.. __: `PyPI site`_ System requirements @@ -70,20 +70,20 @@ the site-packages directory of your Python installation. Documentation ------------- -The documentation can be found at - - https://pytest-dependency.readthedocs.io/ +See the `online documentation`__. The example test modules used in the documentation can be found in doc/examples in the source distribution. +.. __: `Read the Docs site`_ + Copyright and License --------------------- -- Copyright 2013-2015 +- Copyright 2013–2015 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH -- Copyright 2016-2020 Rolf Krahl +- Copyright 2016–2020 Rolf Krahl Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may @@ -98,6 +98,8 @@ implied. See the License for the specific language governing permissions and limitations under the License. +.. _PyPI site: https://pypi.org/project/pytest-dependency/ .. _setuptools: http://pypi.python.org/pypi/setuptools/ .. _pytest: http://pytest.org/ .. _setuptools_scm: https://github.com/pypa/setuptools_scm/ +.. _Read the Docs site: https://pytest-dependency.readthedocs.io/ From 286cbf02c36b7d5117514f64d0067f8a870d3b59 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 11 Apr 2020 15:12:40 +0200 Subject: [PATCH 07/71] Do the substitutions of the doc string and version into pytest_dependency.py also also for setup.py build. --- setup.py | 59 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/setup.py b/setup.py index ad74b46..7dbdaeb 100755 --- a/setup.py +++ b/setup.py @@ -6,13 +6,16 @@ skipped if any of the dependencies did fail or has been skipped. """ +from distutils.cmd import Command as du_cmd import distutils.log import os import os.path import re +import stat import string from setuptools import setup -import setuptools.command.sdist as st_sdist +import setuptools.command.build_py +import setuptools.command.sdist try: import setuptools_scm version = setuptools_scm.get_version() @@ -26,19 +29,47 @@ distutils.log.warn("warning: cannot determine version number") version = "UNKNOWN" +doc_string = __doc__ -class sdist(st_sdist.sdist): - def make_release_tree(self, base_dir, files): - st_sdist.sdist.make_release_tree(self, base_dir, files) - if not self.dry_run: - src = "pytest_dependency.py" - dest = os.path.join(base_dir, src) - if hasattr(os, 'link') and os.path.exists(dest): - os.unlink(dest) - subst = {'DOC': __doc__, 'VERSION': version} - with open(src, "rt") as sf, open(dest, "wt") as df: - df.write(string.Template(sf.read()).substitute(subst)) +class copy_file_mixin: + """Distutils copy_file() mixin. + Inject a custom version version of the copy_file() method that + does some substitutions on the fly into distutils command class + hierarchy. + """ + Subst_srcs = {"pytest_dependency.py"} + Subst = {'DOC': doc_string, 'VERSION': version} + def copy_file(self, infile, outfile, preserve_mode=1, preserve_times=1, + link=None, level=1): + if infile in self.Subst_srcs: + fstat = os.stat(infile) + if os.path.basename(outfile) == os.path.basename(infile): + distutils.log.info("copying (with substitutions) %s -> %s", + infile, os.path.dirname(outfile)) + else: + distutils.log.info("copying (with substitutions) %s -> %s", + infile, outfile) + if not self.dry_run: + if os.path.exists(outfile): + os.unlink(outfile) + with open(infile, "rt") as sf, open(outfile, "wt") as df: + df.write(string.Template(sf.read()).substitute(self.Subst)) + if preserve_mode: + os.chmod(outfile, stat.S_IMODE(fstat[stat.ST_MODE])) + return (outfile, 1) + else: + # Note: can't use super() with Python 2. + return du_cmd.copy_file(self, infile, outfile, + preserve_mode=preserve_mode, + preserve_times=preserve_times, + link=link, level=level) + +class build_py(copy_file_mixin, setuptools.command.build_py.build_py): + pass + +class sdist(copy_file_mixin, setuptools.command.sdist.sdist): + pass setup( name='pytest-dependency', @@ -50,7 +81,7 @@ def make_release_tree(self, base_dir, files): maintainer_email='rolf@rotkraut.de', url='https://github.com/RKrahl/pytest-dependency', license='Apache Software License 2.0', - long_description=__doc__, + long_description=doc_string, project_urls={ 'Documentation': 'https://pytest-dependency.readthedocs.io/', 'Source Code': 'https://github.com/RKrahl/pytest-dependency', @@ -79,5 +110,5 @@ def make_release_tree(self, base_dir, files): 'dependency = pytest_dependency', ], }, - cmdclass = {'sdist': sdist}, + cmdclass = {'build_py': build_py, 'sdist': sdist}, ) From ddf2bdb09d88fe07c2ff0d6faa404f6155798764 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 11 Apr 2020 16:19:25 +0200 Subject: [PATCH 08/71] Fix source distribution: use distutils rather then setuptools for the 'sdist' command. --- setup.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 7dbdaeb..94de125 100755 --- a/setup.py +++ b/setup.py @@ -7,6 +7,7 @@ """ from distutils.cmd import Command as du_cmd +import distutils.command.sdist import distutils.log import os import os.path @@ -15,7 +16,6 @@ import string from setuptools import setup import setuptools.command.build_py -import setuptools.command.sdist try: import setuptools_scm version = setuptools_scm.get_version() @@ -68,7 +68,10 @@ def copy_file(self, infile, outfile, preserve_mode=1, preserve_times=1, class build_py(copy_file_mixin, setuptools.command.build_py.build_py): pass -class sdist(copy_file_mixin, setuptools.command.sdist.sdist): +# Note: Do not use setuptools for making the source distribution, +# rather use the good old distutils instead. +# Rationale: https://rhodesmill.org/brandon/2009/eby-magic/ +class sdist(copy_file_mixin, distutils.command.sdist.sdist): pass setup( From 5952588db354baa7b0736e3baabda87ca25d5078 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 11 Apr 2020 16:26:30 +0200 Subject: [PATCH 09/71] Rename requirements.txt to .req. --- requirements.txt => .req | 0 .travis.yml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename requirements.txt => .req (100%) diff --git a/requirements.txt b/.req similarity index 100% rename from requirements.txt rename to .req diff --git a/.travis.yml b/.travis.yml index 543a750..4f82760 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ python: - "3.6" - "3.7" - "3.8" -install: pip install -r requirements.txt +install: pip install -r .req script: make test PYTHON=python # Local Variables: From cf8473dbcfdd582749b195ee2562e772e7b814f6 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 11 Apr 2020 16:52:58 +0200 Subject: [PATCH 10/71] Get the version from the pytest_dependency module rather then the .version file. --- Makefile | 11 ++++------- doc/src/conf.py | 11 ++--------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 3f28e86..e341c12 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,18 @@ PYTHON = python3 -BUILDDIR = $(CURDIR)/build +BUILDLIB = $(CURDIR)/build/lib build: $(PYTHON) setup.py build test: build - PYTHONPATH=$(BUILDDIR)/lib $(PYTHON) -m pytest tests + PYTHONPATH=$(BUILDLIB) $(PYTHON) -m pytest tests sdist: $(PYTHON) setup.py sdist -doc-html: .version - $(MAKE) -C doc html +doc-html: build + $(MAKE) -C doc html PYTHONPATH=$(BUILDLIB) clean: rm -f *~ tests/*~ @@ -27,7 +27,4 @@ distclean: clean rm -rf pytest_dependency.egg-info $(MAKE) -C doc distclean -.version: - $(PYTHON) setup.py check - .PHONY: build test sdist doc-html clean distclean diff --git a/doc/src/conf.py b/doc/src/conf.py index 5a4ae99..33d00ca 100644 --- a/doc/src/conf.py +++ b/doc/src/conf.py @@ -6,13 +6,7 @@ # full list see the documentation: # http://www.sphinx-doc.org/en/master/config -# -- Path setup -------------------------------------------------------------- - -from pathlib import Path -import sys -topdir = Path("../..").resolve() -sys.path.insert(0, str(topdir)) - +import pytest_dependency # -- Project information ----------------------------------------------------- @@ -21,8 +15,7 @@ author = 'Rolf Krahl' # The full version, including alpha/beta/rc tags -with (topdir / ".version").open("rt") as f: - release = f.read() +release = pytest_dependency.__version__ # The short X.Y version version = ".".join(release.split(".")[0:2]) From 38b9a7a233343bac2ef8a066ff5039fd726e3a1b Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 11 Apr 2020 18:26:36 +0200 Subject: [PATCH 11/71] Add sphinx.ext.intersphinx. --- doc/src/conf.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/src/conf.py b/doc/src/conf.py index 33d00ca..a86fa40 100644 --- a/doc/src/conf.py +++ b/doc/src/conf.py @@ -31,6 +31,7 @@ # ones. extensions = [ 'sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', ] # Add any paths that contain templates here, relative to this directory. @@ -65,6 +66,15 @@ autodoc_member_order = 'bysource' + +# -- Options for intersphinx extension --------------------------------------- + +intersphinx_mapping = { + 'python': ('https://docs.python.org/3', None), + 'pytest': ('https://docs.pytest.org/en/stable/', None), +} + + # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for From c8e19d8a82a734b910ccef2ae9c40e67804ee9d2 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 10 May 2020 21:38:49 +0200 Subject: [PATCH 12/71] Review formatting of the changelog and include it in the source distribution. --- CHANGES.rst | 176 ++++++++++++++++++++++++++++++++++++++++++ MANIFEST.in | 1 + doc/src/changelog.rst | 130 +------------------------------ 3 files changed, 178 insertions(+), 129 deletions(-) create mode 100644 CHANGES.rst diff --git a/CHANGES.rst b/CHANGES.rst new file mode 100644 index 0000000..30ffb47 --- /dev/null +++ b/CHANGES.rst @@ -0,0 +1,176 @@ +Changelog +========= + +0.5.1 (2020-02-14) +~~~~~~~~~~~~~~~~~~ + +Bug fixes and minor changes +--------------------------- + ++ Fix failing documentation build. + +0.5.0 (2020-02-14) +~~~~~~~~~~~~~~~~~~ + +New features +------------ + ++ `#3`_, `#35`_: add a scope to dependencies. + (Thanks to JoeSc and selenareneephillips!) + +Bug fixes and minor changes +--------------------------- + ++ `#34`_: failing test with pytest 4.2.0 and newer. + ++ Use setuptools_scm to manage the version number. + +.. _#35: https://github.com/RKrahl/pytest-dependency/pull/35 +.. _#34: https://github.com/RKrahl/pytest-dependency/issues/34 +.. _#3: https://github.com/RKrahl/pytest-dependency/issues/3 + +0.4.0 (2018-12-02) +~~~~~~~~~~~~~~~~~~ + +Incompatible changes +-------------------- + ++ Require pytest version 3.6.0 or newer. This implicitly drops + support for Python 2.6 and for Python 3.3 and older. + +Bug fixes and minor changes +--------------------------- + ++ `#24`_, `#25`_: get_marker no longer available in pytest 4.0.0. + (Thanks to Rogdham!) + ++ `#28`_: Applying markers directly in parametrize is no longer + available in 4.0. + +.. _#28: https://github.com/RKrahl/pytest-dependency/issues/28 +.. _#25: https://github.com/RKrahl/pytest-dependency/pull/25 +.. _#24: https://github.com/RKrahl/pytest-dependency/issues/24 + +0.3.2 (2018-01-17) +~~~~~~~~~~~~~~~~~~ + +Bug fixes and minor changes +--------------------------- + ++ `#5`_: properly register the dependency marker. + ++ Do not add the documentation to the source distribution. + +.. _#5: https://github.com/RKrahl/pytest-dependency/issues/5 + +0.3.1 (2017-12-26) +~~~~~~~~~~~~~~~~~~ + +Bug fixes and minor changes +--------------------------- + ++ `#17`_: Move the online documentation to Read the Docs. + ++ Some improvements in the documentation. + +.. _#17: https://github.com/RKrahl/pytest-dependency/issues/17 + +0.3 (2017-12-26) +~~~~~~~~~~~~~~~~ + +New features +------------ + ++ `#7`_: Add a configuration switch to implicitly mark all tests. + ++ `#10`_: Add an option to ignore unknown dependencies. + +Incompatible changes +-------------------- + ++ Prepend the class name to the default test name for test class + methods. This fixes a potential name conflict, see `#6`_. + + If your code uses test classes and you reference test methods by + their default name, you must add the class name. E.g. if you have + something like: + + .. code-block:: python + + class TestClass(object): + + @pytest.mark.dependency() + def test_a(): + pass + + @pytest.mark.dependency(depends=["test_a"]) + def test_b(): + pass + + you need to change this to: + + .. code-block:: python + + class TestClass(object): + + @pytest.mark.dependency() + def test_a(): + pass + + @pytest.mark.dependency(depends=["TestClass::test_a"]) + def test_b(): + pass + + If you override the test name in the :func:`pytest.mark.dependency` + marker, nothing need to be changed. + +Bug fixes and minor changes +--------------------------- + ++ `#11`_: show the name of the skipped test. + (Thanks asteriogonzalez!) + ++ `#13`_: Do not import pytest in setup.py to make it compatible with + pipenv. + ++ `#15`_: tests fail with pytest 3.3.0. + ++ `#8`_: document incompatibility with parallelization in + pytest-xdist. + ++ Clarify in the documentation that Python 3.1 is not officially + supported because pytest 2.8 does not support it. There is no known + issue with Python 3.1 though. + +.. _#15: https://github.com/RKrahl/pytest-dependency/issues/15 +.. _#13: https://github.com/RKrahl/pytest-dependency/issues/13 +.. _#11: https://github.com/RKrahl/pytest-dependency/pull/11 +.. _#10: https://github.com/RKrahl/pytest-dependency/issues/10 +.. _#8: https://github.com/RKrahl/pytest-dependency/issues/8 +.. _#7: https://github.com/RKrahl/pytest-dependency/issues/7 +.. _#6: https://github.com/RKrahl/pytest-dependency/issues/6 + +0.2 (2017-05-28) +~~~~~~~~~~~~~~~~ + +New features +------------ + ++ `#2`_: Add documentation. + ++ `#4`_: Add a depend() function to add a dependency to a test at + runtime. + +.. _#4: https://github.com/RKrahl/pytest-dependency/issues/4 +.. _#2: https://github.com/RKrahl/pytest-dependency/issues/2 + +0.1 (2017-01-29) +~~~~~~~~~~~~~~~~ + ++ Initial release as an independent Python module. + + This code was first developed as part of a larger package, + `python-icat`_, at Helmholtz-Zentrum Berlin für Materialien und + Energie. + +.. _python-icat: https://github.com/icatproject/python-icat diff --git a/MANIFEST.in b/MANIFEST.in index e5caef0..80a975b 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,5 @@ include .version +include CHANGES.rst include LICENSE.txt include MANIFEST.in include README.rst diff --git a/doc/src/changelog.rst b/doc/src/changelog.rst index ed371c1..d76c92b 100644 --- a/doc/src/changelog.rst +++ b/doc/src/changelog.rst @@ -1,129 +1 @@ -History of changes to pytest-dependency -======================================= - -0.5.1 (2020-02-14) - - Bug fixes and minor changes - + Fix failing documentation build. - -0.5.0 (2020-02-14) - New features - + `#3`_, `#35`_: add a scope to dependencies. - (Thanks to JoeSc and selenareneephillips!) - - Bug fixes and minor changes - + `#34`_: failing test with pytest 4.2.0 and newer. - + Use setuptools_scm to manage the version number. - -.. _#3: https://github.com/RKrahl/pytest-dependency/issues/3 -.. _#34: https://github.com/RKrahl/pytest-dependency/issues/34 -.. _#35: https://github.com/RKrahl/pytest-dependency/pull/35 - -0.4.0 (2018-12-02) - Incompatible changes - + Require pytest version 3.6.0 or newer. This implicitly drops - support for Python 2.6 and for Python 3.3 and older. - - Bug fixes and minor changes - + `#24`_, `#25`_: get_marker no longer available in pytest 4.0.0. - (Thanks to Rogdham!) - + `#28`_: Applying markers directly in parametrize is no - longer available in 4.0. - -.. _#24: https://github.com/RKrahl/pytest-dependency/issues/24 -.. _#25: https://github.com/RKrahl/pytest-dependency/pull/25 -.. _#28: https://github.com/RKrahl/pytest-dependency/issues/28 - -0.3.2 (2018-01-17) - Bug fixes and minor changes - + `#5`_: properly register the dependency marker. - + Do not add the documentation to the source distribution. - -.. _#5: https://github.com/RKrahl/pytest-dependency/issues/5 - -0.3.1 (2017-12-26) - Bug fixes and minor changes - + `#17`_: Move the online documentation to Read the Docs. - + Some improvements in the documentation. - -.. _#17: https://github.com/RKrahl/pytest-dependency/issues/17 - -0.3 (2017-12-26) - New features - + `#7`_: Add a configuration switch to implicitly mark all - tests. - + `#10`_: Add an option to ignore unknown dependencies. - - Incompatible changes - + Prepend the class name to the default test name for test class - methods. This fixes a potential name conflict, see `#6`_. - - If your code uses test classes and you reference test methods - by their default name, you must add the class name. E.g. if - you have something like: - - .. code-block:: python - - class TestClass(object): - - @pytest.mark.dependency() - def test_a(): - pass - - @pytest.mark.dependency(depends=["test_a"]) - def test_b(): - pass - - you need to change this to: - - .. code-block:: python - - class TestClass(object): - - @pytest.mark.dependency() - def test_a(): - pass - - @pytest.mark.dependency(depends=["TestClass::test_a"]) - def test_b(): - pass - - If you override the test name in the pytest.mark.dependency() - marker, nothing need to be changed. - - Bug fixes and minor changes - + `#11`_: show the name of the skipped test. - (Thanks asteriogonzalez!) - + `#13`_: Do not import pytest in setup.py to make it - compatible with pipenv. - + `#15`_: tests fail with pytest 3.3.0. - + `#8`_: document incompatibility with parallelization in - pytest-xdist. - + Clarify in the documentation that Python 3.1 is not officially - supported because pytest 2.8 does not support it. There is no - known issue with Python 3.1 though. - -.. _#6: https://github.com/RKrahl/pytest-dependency/issues/6 -.. _#7: https://github.com/RKrahl/pytest-dependency/issues/7 -.. _#8: https://github.com/RKrahl/pytest-dependency/issues/8 -.. _#10: https://github.com/RKrahl/pytest-dependency/issues/10 -.. _#11: https://github.com/RKrahl/pytest-dependency/pull/11 -.. _#13: https://github.com/RKrahl/pytest-dependency/issues/13 -.. _#15: https://github.com/RKrahl/pytest-dependency/issues/15 - -0.2 (2017-05-28) - New features - + `#2`_: Add documentation. - + `#4`_: Add a depend() function to add a dependency to a - test at runtime. - -.. _#2: https://github.com/RKrahl/pytest-dependency/issues/2 -.. _#4: https://github.com/RKrahl/pytest-dependency/issues/4 - -0.1 (2017-01-29) - + Initial release as an independent Python module. - - This code was first developed as part of a larger package, - python-icat, at Helmholtz-Zentrum Berlin für Materialien und - Energie, see - https://icatproject.org/user-documentation/python-icat/ +.. include:: ../../CHANGES.rst From 0862cda8db6852be2a251d2f37fc36b327cdeeaa Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 10 May 2020 22:00:54 +0200 Subject: [PATCH 13/71] Minor changes to the documentation. --- README.rst | 8 +++----- doc/src/about.rst | 8 +++----- doc/src/install.rst | 6 +++--- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/README.rst b/README.rst index 2719144..de3b118 100644 --- a/README.rst +++ b/README.rst @@ -85,11 +85,8 @@ Copyright and License Helmholtz-Zentrum Berlin für Materialien und Energie GmbH - Copyright 2016–2020 Rolf Krahl -Licensed under the Apache License, Version 2.0 (the "License"); you -may not use this file except in compliance with the License. You may -obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 +Licensed under the `Apache License`_, Version 2.0 (the "License"); you +may not use this file except in compliance with the License. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -103,3 +100,4 @@ permissions and limitations under the License. .. _pytest: http://pytest.org/ .. _setuptools_scm: https://github.com/pypa/setuptools_scm/ .. _Read the Docs site: https://pytest-dependency.readthedocs.io/ +.. _Apache License: https://www.apache.org/licenses/LICENSE-2.0 diff --git a/doc/src/about.rst b/doc/src/about.rst index d480b69..24c680a 100644 --- a/doc/src/about.rst +++ b/doc/src/about.rst @@ -73,11 +73,8 @@ Copyright and License Helmholtz-Zentrum Berlin für Materialien und Energie GmbH - Copyright 2016–2020 Rolf Krahl -Licensed under the Apache License, Version 2.0 (the "License"); you -may not use this file except in compliance with the License. You may -obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 +Licensed under the `Apache License`_, Version 2.0 (the "License"); you +may not use this file except in compliance with the License. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -87,3 +84,4 @@ permissions and limitations under the License. .. _pytest: http://pytest.org/ +.. _Apache License: https://www.apache.org/licenses/LICENSE-2.0 diff --git a/doc/src/install.rst b/doc/src/install.rst index 9b6417a..2c06599 100644 --- a/doc/src/install.rst +++ b/doc/src/install.rst @@ -26,10 +26,10 @@ pytest-xdist Download -------- -The latest release version of pytest-dependency source can be found at -PyPI, see +The latest release version of pytest-dependency is available on the +`Python Package Index (PyPI)`__. - https://pypi.python.org/pypi/pytest_dependency +.. __: https://pypi.python.org/pypi/pytest_dependency/ Installation From 31ca28a2b7218f94750ce248164f38e9f0126b4e Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 17 May 2020 12:20:56 +0200 Subject: [PATCH 14/71] README: may need to set PYTHONPATH to run the tests. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 2719144..9fdfde2 100644 --- a/README.rst +++ b/README.rst @@ -57,7 +57,7 @@ Installation 3. Test (optional):: - $ python -m pytest + $ PYTHONPATH=build/lib python -m pytest 4. Install:: From 0ebc10fb689b84784e1c03a29a655d23f612d26c Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 17 May 2020 21:21:23 +0200 Subject: [PATCH 15/71] Add logging, close #40. --- doc/src/changelog.rst | 6 ++++++ pytest_dependency.py | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/doc/src/changelog.rst b/doc/src/changelog.rst index ed371c1..86d22bd 100644 --- a/doc/src/changelog.rst +++ b/doc/src/changelog.rst @@ -1,6 +1,12 @@ History of changes to pytest-dependency ======================================= +dev (not yet released) + Bug fixes and minor changes + + `#40`_: add logging. + +.. _#40: https://github.com/RKrahl/pytest-dependency/issues/40 + 0.5.1 (2020-02-14) Bug fixes and minor changes diff --git a/pytest_dependency.py b/pytest_dependency.py index 83362ae..9ebf94a 100644 --- a/pytest_dependency.py +++ b/pytest_dependency.py @@ -2,8 +2,11 @@ __version__ = "$VERSION" +import logging import pytest +logger = logging.getLogger(__name__) + _automark = False _ignore_unknown = False @@ -85,16 +88,25 @@ def addResult(self, item, name, rep): raise RuntimeError("Internal error: invalid scope '%s'" % self.scope) status = self.results.setdefault(name, DependencyItemStatus()) + logger.debug("register %s %s %s in %s scope", + rep.when, name, rep.outcome, self.scope) status.addResult(rep) def checkDepend(self, depends, item): + logger.debug("check dependencies of %s in %s scope ...", + item.name, self.scope) for i in depends: if i in self.results: if self.results[i].isSuccess(): + logger.debug("... %s succeeded", i) continue + else: + logger.debug("... %s has not succeeded", i) else: + logger.debug("... %s is unknown", i) if _ignore_unknown: continue + logger.info("skip %s because it depends on %s", item.name, i) pytest.skip("%s depends on %s" % (item.name, i)) From 7a4f8b756c0c47dbe82a9bafa0ddedfe56d8144a Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 20 Feb 2021 16:01:49 +0100 Subject: [PATCH 16/71] - Fix requirements: it turns out that we require pytest 3.7.0 already since version 0.5.0 - Claim to support Python 3.9 --- .req | 2 +- .travis.yml | 1 + README.rst | 2 +- doc/src/changelog.rst | 4 +++- doc/src/configuration.rst | 4 ++-- doc/src/install.rst | 2 +- setup.py | 3 ++- tests/pytest.ini | 2 +- 8 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.req b/.req index 04f6903..d8b46d9 100644 --- a/.req +++ b/.req @@ -1,2 +1,2 @@ -pytest >=3.6.0 +pytest >=3.7.0 setuptools_scm diff --git a/.travis.yml b/.travis.yml index 4f82760..7553bdd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ python: - "3.6" - "3.7" - "3.8" + - "3.9" install: pip install -r .req script: make test PYTHON=python diff --git a/README.rst b/README.rst index 9fdfde2..f611646 100644 --- a/README.rst +++ b/README.rst @@ -33,7 +33,7 @@ System requirements + Python 2.7 or 3.4 and newer. + `setuptools`_. -+ `pytest`_ 3.6.0 or newer. ++ `pytest`_ 3.7.0 or newer. Optional library packages: diff --git a/doc/src/changelog.rst b/doc/src/changelog.rst index 86d22bd..2483aa3 100644 --- a/doc/src/changelog.rst +++ b/doc/src/changelog.rst @@ -8,7 +8,6 @@ dev (not yet released) .. _#40: https://github.com/RKrahl/pytest-dependency/issues/40 0.5.1 (2020-02-14) - Bug fixes and minor changes + Fix failing documentation build. @@ -17,6 +16,9 @@ dev (not yet released) + `#3`_, `#35`_: add a scope to dependencies. (Thanks to JoeSc and selenareneephillips!) + Incompatible changes + + Require pytest version 3.7.0 or newer. + Bug fixes and minor changes + `#34`_: failing test with pytest 4.2.0 and newer. + Use setuptools_scm to manage the version number. diff --git a/doc/src/configuration.rst b/doc/src/configuration.rst index b917047..151a1ec 100644 --- a/doc/src/configuration.rst +++ b/doc/src/configuration.rst @@ -21,8 +21,8 @@ Configuration file options can be set in the `ini file`. minversion This is a builtin configuration option of pytest itself. Since - pytest-dependency requires pytest 3.6.0 or newer, it is recommended - to set this option accordingly, either to 3.6.0 or to a newer + pytest-dependency requires pytest 3.7.0 or newer, it is recommended + to set this option accordingly, either to 3.7.0 or to a newer version, if required by your test code. automark_dependency diff --git a/doc/src/install.rst b/doc/src/install.rst index 9b6417a..482b33e 100644 --- a/doc/src/install.rst +++ b/doc/src/install.rst @@ -6,7 +6,7 @@ System requirements + Python 2.7 or 3.4 and newer. + `setuptools`_. -+ `pytest`_ 3.6.0 or newer. ++ `pytest`_ 3.7.0 or newer. .. _install-other-packages: diff --git a/setup.py b/setup.py index 94de125..7f6f19c 100755 --- a/setup.py +++ b/setup.py @@ -90,7 +90,7 @@ class sdist(copy_file_mixin, distutils.command.sdist.sdist): 'Source Code': 'https://github.com/RKrahl/pytest-dependency', }, py_modules=['pytest_dependency'], - install_requires=['pytest >= 3.6.0'], + install_requires=['pytest >= 3.7.0'], classifiers=[ 'Development Status :: 4 - Beta', 'Framework :: Pytest', @@ -105,6 +105,7 @@ class sdist(copy_file_mixin, distutils.command.sdist.sdist): 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Operating System :: OS Independent', 'License :: OSI Approved :: Apache Software License', ], diff --git a/tests/pytest.ini b/tests/pytest.ini index 1f80c58..7cec0d1 100644 --- a/tests/pytest.ini +++ b/tests/pytest.ini @@ -1,2 +1,2 @@ [pytest] -minversion = 3.6 +minversion = 3.7 From 0930889a13e2b9baa7617f05dc9b55abede5209d Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 21 Feb 2021 13:06:35 +0100 Subject: [PATCH 17/71] Adapt matching of expected output in the tests to adapt to changes in pytest 6.2.0 and newer, fix #50 --- tests/test_02_simple_dependency.py | 54 ++++++++++++------------ tests/test_03_class.py | 32 +++++++------- tests/test_03_multiple_dependency.py | 24 +++++------ tests/test_03_param.py | 28 ++++++------- tests/test_03_runtime.py | 10 ++--- tests/test_03_scope.py | 62 ++++++++++++++-------------- tests/test_03_skipmsgs.py | 10 ++--- tests/test_04_automark.py | 18 ++++---- tests/test_04_ignore_unknown.py | 8 ++-- 9 files changed, 123 insertions(+), 123 deletions(-) diff --git a/tests/test_02_simple_dependency.py b/tests/test_02_simple_dependency.py index a010f80..3c45f2c 100644 --- a/tests/test_02_simple_dependency.py +++ b/tests/test_02_simple_dependency.py @@ -29,11 +29,11 @@ def test_d(): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=3, skipped=1, failed=0) - result.stdout.fnmatch_lines(""" - *::test_a SKIPPED - *::test_b PASSED - *::test_c PASSED - *::test_d PASSED + result.stdout.re_match_lines(r""" + .*::test_a SKIPPED(?:\s+\(.*\))? + .*::test_b PASSED + .*::test_c PASSED + .*::test_d PASSED """) @@ -62,11 +62,11 @@ def test_d(): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=1, skipped=3, failed=0) - result.stdout.fnmatch_lines(""" - *::test_a PASSED - *::test_b SKIPPED - *::test_c SKIPPED - *::test_d SKIPPED + result.stdout.re_match_lines(r""" + .*::test_a PASSED + .*::test_b SKIPPED(?:\s+\(.*\))? + .*::test_c SKIPPED(?:\s+\(.*\))? + .*::test_d SKIPPED(?:\s+\(.*\))? """) @@ -95,11 +95,11 @@ def test_d(): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=1, skipped=2, failed=1) - result.stdout.fnmatch_lines(""" - *::test_a PASSED - *::test_b FAILED - *::test_c SKIPPED - *::test_d SKIPPED + result.stdout.re_match_lines(r""" + .*::test_a PASSED + .*::test_b FAILED + .*::test_c SKIPPED(?:\s+\(.*\))? + .*::test_d SKIPPED(?:\s+\(.*\))? """) @@ -127,11 +127,11 @@ def test_d(): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=1, skipped=2, failed=1) - result.stdout.fnmatch_lines(""" - *::test_a PASSED - *::test_b FAILED - *::test_c SKIPPED - *::test_d SKIPPED + result.stdout.re_match_lines(r""" + .*::test_a PASSED + .*::test_b FAILED + .*::test_c SKIPPED(?:\s+\(.*\))? + .*::test_d SKIPPED(?:\s+\(.*\))? """) @@ -162,8 +162,8 @@ def test_d(): """) result = ctestdir.runpytest("--verbose", "test_explicit_select.py::test_d") result.assert_outcomes(passed=0, skipped=1, failed=0) - result.stdout.fnmatch_lines(""" - *::test_d SKIPPED + result.stdout.re_match_lines(r""" + .*::test_d SKIPPED(?:\s+\(.*\))? """) @@ -195,9 +195,9 @@ def test_d(): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=3, skipped=1, failed=0) - result.stdout.fnmatch_lines(""" - *::test_a PASSED - *::test_b PASSED - *::test_c PASSED - *::test_d SKIPPED + result.stdout.re_match_lines(r""" + .*::test_a PASSED + .*::test_b PASSED + .*::test_c PASSED + .*::test_d SKIPPED(?:\s+\(.*\))? """) diff --git a/tests/test_03_class.py b/tests/test_03_class.py index 2ebf811..168b634 100644 --- a/tests/test_03_class.py +++ b/tests/test_03_class.py @@ -36,12 +36,12 @@ def test_e(self): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=2, skipped=2, failed=1) - result.stdout.fnmatch_lines(""" - *::TestClass::test_a FAILED - *::TestClass::test_b PASSED - *::TestClass::test_c SKIPPED - *::TestClass::test_d PASSED - *::TestClass::test_e SKIPPED + result.stdout.re_match_lines(r""" + .*::TestClass::test_a FAILED + .*::TestClass::test_b PASSED + .*::TestClass::test_c SKIPPED(?:\s+\(.*\))? + .*::TestClass::test_d PASSED + .*::TestClass::test_e SKIPPED(?:\s+\(.*\))? """) @@ -76,12 +76,12 @@ def test_e(self): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=2, skipped=2, failed=1) - result.stdout.fnmatch_lines(""" - *::TestClassNamed::test_a FAILED - *::TestClassNamed::test_b PASSED - *::TestClassNamed::test_c SKIPPED - *::TestClassNamed::test_d PASSED - *::TestClassNamed::test_e SKIPPED + result.stdout.re_match_lines(r""" + .*::TestClassNamed::test_a FAILED + .*::TestClassNamed::test_b PASSED + .*::TestClassNamed::test_c SKIPPED(?:\s+\(.*\))? + .*::TestClassNamed::test_d PASSED + .*::TestClassNamed::test_e SKIPPED(?:\s+\(.*\))? """) @@ -114,8 +114,8 @@ def test_b(): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=1, skipped=1, failed=1) - result.stdout.fnmatch_lines(""" - *::test_a FAILED - *::TestClass::test_a PASSED - *::test_b SKIPPED + result.stdout.re_match_lines(r""" + .*::test_a FAILED + .*::TestClass::test_a PASSED + .*::test_b SKIPPED(?:\s+\(.*\))? """) diff --git a/tests/test_03_multiple_dependency.py b/tests/test_03_multiple_dependency.py index aaea86b..a5e585a 100644 --- a/tests/test_03_multiple_dependency.py +++ b/tests/test_03_multiple_dependency.py @@ -54,16 +54,16 @@ def test_k(): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=5, skipped=5, failed=1) - result.stdout.fnmatch_lines(""" - *::test_a SKIPPED - *::test_b FAILED - *::test_c PASSED - *::test_d PASSED - *::test_e PASSED - *::test_f SKIPPED - *::test_g SKIPPED - *::test_h PASSED - *::test_i SKIPPED - *::test_j PASSED - *::test_k SKIPPED + result.stdout.re_match_lines(r""" + .*::test_a SKIPPED(?:\s+\(.*\))? + .*::test_b FAILED + .*::test_c PASSED + .*::test_d PASSED + .*::test_e PASSED + .*::test_f SKIPPED(?:\s+\(.*\))? + .*::test_g SKIPPED(?:\s+\(.*\))? + .*::test_h PASSED + .*::test_i SKIPPED(?:\s+\(.*\))? + .*::test_j PASSED + .*::test_k SKIPPED(?:\s+\(.*\))? """) diff --git a/tests/test_03_param.py b/tests/test_03_param.py index 8c0e53d..a7a31b0 100644 --- a/tests/test_03_param.py +++ b/tests/test_03_param.py @@ -40,18 +40,18 @@ def test_c(w): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=7, skipped=5, failed=1) - result.stdout.fnmatch_lines(""" - *::test_a?0-0? PASSED - *::test_a?0-1? PASSED - *::test_a?1-0? PASSED - *::test_a?1-1? FAILED - *::test_b?1-2? PASSED - *::test_b?1-3? PASSED - *::test_b?1-4? SKIPPED - *::test_b?2-3? PASSED - *::test_b?2-4? SKIPPED - *::test_b?3-4? SKIPPED - *::test_c?1? SKIPPED - *::test_c?2? SKIPPED - *::test_c?3? PASSED + result.stdout.re_match_lines(r""" + .*::test_a\[0-0\] PASSED + .*::test_a\[0-1\] PASSED + .*::test_a\[1-0\] PASSED + .*::test_a\[1-1\] FAILED + .*::test_b\[1-2\] PASSED + .*::test_b\[1-3\] PASSED + .*::test_b\[1-4\] SKIPPED(?:\s+\(.*\))? + .*::test_b\[2-3\] PASSED + .*::test_b\[2-4\] SKIPPED(?:\s+\(.*\))? + .*::test_b\[3-4\] SKIPPED(?:\s+\(.*\))? + .*::test_c\[1\] SKIPPED(?:\s+\(.*\))? + .*::test_c\[2\] SKIPPED(?:\s+\(.*\))? + .*::test_c\[3\] PASSED """) diff --git a/tests/test_03_runtime.py b/tests/test_03_runtime.py index fd35b2b..fb23e2c 100644 --- a/tests/test_03_runtime.py +++ b/tests/test_03_runtime.py @@ -32,9 +32,9 @@ def test_d(request): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=1, skipped=3, failed=0) - result.stdout.fnmatch_lines(""" - *::test_a PASSED - *::test_b SKIPPED - *::test_c SKIPPED - *::test_d SKIPPED + result.stdout.re_match_lines(r""" + .*::test_a PASSED + .*::test_b SKIPPED(?:\s+\(.*\))? + .*::test_c SKIPPED(?:\s+\(.*\))? + .*::test_d SKIPPED(?:\s+\(.*\))? """) diff --git a/tests/test_03_scope.py b/tests/test_03_scope.py index ba28377..58aad89 100644 --- a/tests/test_03_scope.py +++ b/tests/test_03_scope.py @@ -33,12 +33,12 @@ def test_e(): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=2, skipped=2, failed=1) - result.stdout.fnmatch_lines(""" + result.stdout.re_match_lines(r""" test_scope_module.py::test_a FAILED test_scope_module.py::test_b PASSED - test_scope_module.py::test_c SKIPPED + test_scope_module.py::test_c SKIPPED(?:\s+\(.*\))? test_scope_module.py::test_d PASSED - test_scope_module.py::test_e SKIPPED + test_scope_module.py::test_e SKIPPED(?:\s+\(.*\))? """) def test_scope_session(ctestdir): @@ -102,14 +102,14 @@ def test_h(): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=6, skipped=1, failed=2) - result.stdout.fnmatch_lines(""" + result.stdout.re_match_lines(r""" test_scope_session_01.py::test_a PASSED test_scope_session_01.py::test_b FAILED test_scope_session_01.py::test_c PASSED test_scope_session_01.py::TestClass::test_b PASSED test_scope_session_02.py::test_a FAILED test_scope_session_02.py::test_e PASSED - test_scope_session_02.py::test_f SKIPPED + test_scope_session_02.py::test_f SKIPPED(?:\s+\(.*\))? test_scope_session_02.py::test_g PASSED test_scope_session_02.py::test_h PASSED """) @@ -174,14 +174,14 @@ def test_h(): ctestdir.makepyfile(**srcs) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=4, skipped=2, failed=1) - result.stdout.fnmatch_lines(""" + result.stdout.re_match_lines(r""" test_scope_package_a/test_01.py::test_a PASSED test_scope_package_b/test_02.py::test_c PASSED test_scope_package_b/test_02.py::test_d FAILED test_scope_package_b/test_03.py::test_e PASSED - test_scope_package_b/test_03.py::test_f SKIPPED + test_scope_package_b/test_03.py::test_f SKIPPED(?:\s+\(.*\))? test_scope_package_b/test_03.py::test_g PASSED - test_scope_package_b/test_03.py::test_h SKIPPED + test_scope_package_b/test_03.py::test_h SKIPPED(?:\s+\(.*\))? """) def test_scope_class(ctestdir): @@ -236,17 +236,17 @@ def test_h(self): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=5, skipped=3, failed=2) - result.stdout.fnmatch_lines(""" + result.stdout.re_match_lines(r""" test_scope_class.py::test_a FAILED test_scope_class.py::test_b PASSED test_scope_class.py::TestClass1::test_c PASSED test_scope_class.py::TestClass2::test_a PASSED test_scope_class.py::TestClass2::test_b FAILED - test_scope_class.py::TestClass2::test_d SKIPPED + test_scope_class.py::TestClass2::test_d SKIPPED(?:\s+\(.*\))? test_scope_class.py::TestClass2::test_e PASSED test_scope_class.py::TestClass2::test_f PASSED - test_scope_class.py::TestClass2::test_g SKIPPED - test_scope_class.py::TestClass2::test_h SKIPPED + test_scope_class.py::TestClass2::test_g SKIPPED(?:\s+\(.*\))? + test_scope_class.py::TestClass2::test_h SKIPPED(?:\s+\(.*\))? """) def test_scope_nodeid(ctestdir): @@ -360,21 +360,21 @@ def test_o(self): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=7, skipped=8, failed=0) - result.stdout.fnmatch_lines(""" + result.stdout.re_match_lines(r""" test_scope_nodeid.py::test_a PASSED test_scope_nodeid.py::test_b PASSED - test_scope_nodeid.py::test_c SKIPPED - test_scope_nodeid.py::test_d SKIPPED + test_scope_nodeid.py::test_c SKIPPED(?:\s+\(.*\))? + test_scope_nodeid.py::test_d SKIPPED(?:\s+\(.*\))? test_scope_nodeid.py::test_e PASSED test_scope_nodeid.py::TestClass::test_f PASSED test_scope_nodeid.py::TestClass::test_g PASSED - test_scope_nodeid.py::TestClass::test_h SKIPPED - test_scope_nodeid.py::TestClass::test_i SKIPPED - test_scope_nodeid.py::TestClass::test_j SKIPPED + test_scope_nodeid.py::TestClass::test_h SKIPPED(?:\s+\(.*\))? + test_scope_nodeid.py::TestClass::test_i SKIPPED(?:\s+\(.*\))? + test_scope_nodeid.py::TestClass::test_j SKIPPED(?:\s+\(.*\))? test_scope_nodeid.py::TestClass::test_k PASSED - test_scope_nodeid.py::TestClass::test_l SKIPPED - test_scope_nodeid.py::TestClass::test_m SKIPPED - test_scope_nodeid.py::TestClass::test_n SKIPPED + test_scope_nodeid.py::TestClass::test_l SKIPPED(?:\s+\(.*\))? + test_scope_nodeid.py::TestClass::test_m SKIPPED(?:\s+\(.*\))? + test_scope_nodeid.py::TestClass::test_n SKIPPED(?:\s+\(.*\))? test_scope_nodeid.py::TestClass::test_o PASSED """) @@ -467,19 +467,19 @@ def test_l(self): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=7, skipped=5, failed=0) - result.stdout.fnmatch_lines(""" + result.stdout.re_match_lines(r""" test_scope_named.py::test_a PASSED test_scope_named.py::test_b PASSED - test_scope_named.py::test_c SKIPPED + test_scope_named.py::test_c SKIPPED(?:\s+\(.*\))? test_scope_named.py::test_d PASSED - test_scope_named.py::test_e SKIPPED + test_scope_named.py::test_e SKIPPED(?:\s+\(.*\))? test_scope_named.py::TestClass::test_f PASSED test_scope_named.py::TestClass::test_g PASSED - test_scope_named.py::TestClass::test_h SKIPPED + test_scope_named.py::TestClass::test_h SKIPPED(?:\s+\(.*\))? test_scope_named.py::TestClass::test_i PASSED - test_scope_named.py::TestClass::test_j SKIPPED + test_scope_named.py::TestClass::test_j SKIPPED(?:\s+\(.*\))? test_scope_named.py::TestClass::test_k PASSED - test_scope_named.py::TestClass::test_l SKIPPED + test_scope_named.py::TestClass::test_l SKIPPED(?:\s+\(.*\))? """) def test_scope_dependsfunc(ctestdir): @@ -578,7 +578,7 @@ def test_d(self, request): """) result = ctestdir.runpytest("--verbose") result.assert_outcomes(passed=10, skipped=3, failed=3) - result.stdout.fnmatch_lines(""" + result.stdout.re_match_lines(r""" test_scope_dependsfunc_01.py::test_a PASSED test_scope_dependsfunc_01.py::test_b FAILED test_scope_dependsfunc_01.py::test_c PASSED @@ -586,13 +586,13 @@ def test_d(self, request): test_scope_dependsfunc_02.py::test_a FAILED test_scope_dependsfunc_02.py::test_b PASSED test_scope_dependsfunc_02.py::test_e PASSED - test_scope_dependsfunc_02.py::test_f SKIPPED + test_scope_dependsfunc_02.py::test_f SKIPPED(?:\s+\(.*\))? test_scope_dependsfunc_02.py::test_g PASSED test_scope_dependsfunc_02.py::test_h PASSED - test_scope_dependsfunc_02.py::test_i SKIPPED + test_scope_dependsfunc_02.py::test_i SKIPPED(?:\s+\(.*\))? test_scope_dependsfunc_02.py::test_j PASSED test_scope_dependsfunc_02.py::TestClass::test_a PASSED test_scope_dependsfunc_02.py::TestClass::test_b FAILED test_scope_dependsfunc_02.py::TestClass::test_c PASSED - test_scope_dependsfunc_02.py::TestClass::test_d SKIPPED + test_scope_dependsfunc_02.py::TestClass::test_d SKIPPED(?:\s+\(.*\))? """) diff --git a/tests/test_03_skipmsgs.py b/tests/test_03_skipmsgs.py index d501285..bfdc833 100644 --- a/tests/test_03_skipmsgs.py +++ b/tests/test_03_skipmsgs.py @@ -29,11 +29,11 @@ def test_d(): """) result = ctestdir.runpytest("--verbose", "-rs") result.assert_outcomes(passed=1, skipped=2, failed=1) - result.stdout.fnmatch_lines(""" - *::test_a PASSED - *::test_b FAILED - *::test_c SKIPPED - *::test_d SKIPPED + result.stdout.re_match_lines(r""" + .*::test_a PASSED + .*::test_b FAILED + .*::test_c SKIPPED(?:\s+\(.*\))? + .*::test_d SKIPPED(?:\s+\(.*\))? """) result.stdout.fnmatch_lines_random(""" SKIP* test_c depends on test_b diff --git a/tests/test_04_automark.py b/tests/test_04_automark.py index bcc2810..7251405 100644 --- a/tests/test_04_automark.py +++ b/tests/test_04_automark.py @@ -23,9 +23,9 @@ def test_b(): """) result = ctestdir.runpytest("--verbose", "-rs") result.assert_outcomes(passed=1, skipped=1, failed=0) - result.stdout.fnmatch_lines(""" - *::test_a PASSED - *::test_b SKIPPED + result.stdout.re_match_lines(r""" + .*::test_a PASSED + .*::test_b SKIPPED(?:\s+\(.*\))? """) @@ -53,9 +53,9 @@ def test_b(): """) result = ctestdir.runpytest("--verbose", "-rs") result.assert_outcomes(passed=1, skipped=1, failed=0) - result.stdout.fnmatch_lines(""" - *::test_a PASSED - *::test_b SKIPPED + result.stdout.re_match_lines(r""" + .*::test_a PASSED + .*::test_b SKIPPED(?:\s+\(.*\))? """) @@ -83,7 +83,7 @@ def test_b(): """) result = ctestdir.runpytest("--verbose", "-rs") result.assert_outcomes(passed=2, skipped=0, failed=0) - result.stdout.fnmatch_lines(""" - *::test_a PASSED - *::test_b PASSED + result.stdout.re_match_lines(r""" + .*::test_a PASSED + .*::test_b PASSED """) diff --git a/tests/test_04_ignore_unknown.py b/tests/test_04_ignore_unknown.py index 3cee600..bc145e5 100644 --- a/tests/test_04_ignore_unknown.py +++ b/tests/test_04_ignore_unknown.py @@ -32,8 +32,8 @@ def test_d(): """) result = ctestdir.runpytest("--verbose", "test_no_ignore.py::test_d") result.assert_outcomes(passed=0, skipped=1, failed=0) - result.stdout.fnmatch_lines(""" - *::test_d SKIPPED + result.stdout.re_match_lines(r""" + .*::test_d SKIPPED(?:\s+\(.*\))? """) @@ -67,6 +67,6 @@ def test_d(): result = ctestdir.runpytest("--verbose", "--ignore-unknown-dependency", "test_ignore.py::test_d") result.assert_outcomes(passed=1, skipped=0, failed=0) - result.stdout.fnmatch_lines(""" - *::test_d PASSED + result.stdout.re_match_lines(r""" + .*::test_d PASSED """) From f784ab6dcff2693eaef38f8462e3b143b6c26c46 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 21 Feb 2021 13:36:50 +0100 Subject: [PATCH 18/71] Update changelog --- doc/src/changelog.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/src/changelog.rst b/doc/src/changelog.rst index 2483aa3..9b1c2de 100644 --- a/doc/src/changelog.rst +++ b/doc/src/changelog.rst @@ -4,8 +4,11 @@ History of changes to pytest-dependency dev (not yet released) Bug fixes and minor changes + `#40`_: add logging. + + `#50`_, `#51`_: test suite incompatibility with pytest 6.2.0. .. _#40: https://github.com/RKrahl/pytest-dependency/issues/40 +.. _#50: https://github.com/RKrahl/pytest-dependency/issues/50 +.. _#51: https://github.com/RKrahl/pytest-dependency/pull/51 0.5.1 (2020-02-14) Bug fixes and minor changes From 1e01358b272ef7d1b2bae0eb7c9d4e33f657da35 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 21 Feb 2021 16:51:55 +0100 Subject: [PATCH 19/71] Get rid of a warning from setuptools in setup.py --- setup.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 7f6f19c..46c02e6 100755 --- a/setup.py +++ b/setup.py @@ -6,14 +6,15 @@ skipped if any of the dependencies did fail or has been skipped. """ -from distutils.cmd import Command as du_cmd -import distutils.command.sdist -import distutils.log import os import os.path import re import stat import string +import setuptools +from distutils.cmd import Command as du_cmd +import distutils.command.sdist +import distutils.log from setuptools import setup import setuptools.command.build_py try: From 886c254fe86062a75b739539afac6e57b0e42971 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Fri, 24 Dec 2021 17:23:29 +0100 Subject: [PATCH 20/71] Add an example on how to implement an or-like dependency. Ref. #53, #57 --- doc/examples/or_dependency.py | 63 +++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 doc/examples/or_dependency.py diff --git a/doc/examples/or_dependency.py b/doc/examples/or_dependency.py new file mode 100644 index 0000000..a06aac8 --- /dev/null +++ b/doc/examples/or_dependency.py @@ -0,0 +1,63 @@ +import pytest +from pytest_dependency import depends + +def depends_or(request, other, scope='module'): + """Add dependency on any of the other tests. + + Call pytest.skip() unless a successful outcome of any of the tests + in other has been registered previously. This helper is similar + to `pytest_dependency.depends()`. It takes the same arguments. + But while `pytest_dependency.depends()` combines the tests in + `other` in an and-like manner, it skips the current test unless + all other tests did succeed, this function combines them in an + or-like manner, it runs the current test if at least one of the + other tests did succeed. + """ + item = request.node + for o in other: + try: + depends(request, [o], scope) + except pytest.skip.Exception: + continue + else: + return + pytest.skip("%s depends on any of %s" % (item.name, ", ".join(other))) + + +@pytest.mark.dependency() +def test_ap(): + pass + +@pytest.mark.dependency() +@pytest.mark.xfail(reason="deliberate fail") +def test_ax(): + assert False + +@pytest.mark.dependency() +def test_bp(): + pass + +@pytest.mark.dependency() +@pytest.mark.xfail(reason="deliberate fail") +def test_bx(): + assert False + +@pytest.mark.dependency() +def test_c(request): + depends_or(request, ["test_ax", "test_bx"]) + pass + +@pytest.mark.dependency() +def test_d(request): + depends_or(request, ["test_ax", "test_bp"]) + pass + +@pytest.mark.dependency() +def test_e(request): + depends_or(request, ["test_ap", "test_bx"]) + pass + +@pytest.mark.dependency() +def test_f(request): + depends_or(request, ["test_ap", "test_bp"]) + pass From 2ad740b5392a12018323e5902a51afc5bbe9df10 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Fri, 24 Dec 2021 17:52:24 +0100 Subject: [PATCH 21/71] Minor edit in docstring --- doc/examples/or_dependency.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/examples/or_dependency.py b/doc/examples/or_dependency.py index a06aac8..655ec61 100644 --- a/doc/examples/or_dependency.py +++ b/doc/examples/or_dependency.py @@ -5,7 +5,7 @@ def depends_or(request, other, scope='module'): """Add dependency on any of the other tests. Call pytest.skip() unless a successful outcome of any of the tests - in other has been registered previously. This helper is similar + in `other` has been registered previously. This helper is similar to `pytest_dependency.depends()`. It takes the same arguments. But while `pytest_dependency.depends()` combines the tests in `other` in an and-like manner, it skips the current test unless From 8b05acf9c5aceb54ab34efe172449cdbacec676b Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Fri, 24 Dec 2021 20:03:13 +0100 Subject: [PATCH 22/71] Switch from Travis CI to GitHub Actions --- .req => .github/requirements.txt | 0 .github/workflows/run-tests.yaml | 35 ++++++++++++++++++++++++++++++++ .travis.yml | 15 -------------- README.rst | 10 ++++----- 4 files changed, 40 insertions(+), 20 deletions(-) rename .req => .github/requirements.txt (100%) create mode 100644 .github/workflows/run-tests.yaml delete mode 100644 .travis.yml diff --git a/.req b/.github/requirements.txt similarity index 100% rename from .req rename to .github/requirements.txt diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml new file mode 100644 index 0000000..771d7fe --- /dev/null +++ b/.github/workflows/run-tests.yaml @@ -0,0 +1,35 @@ +name: Run Test +on: [push, pull_request] +jobs: + Test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + python-version: + - '2.7' + - '3.5' + - '3.6' + - '3.7' + - '3.8' + - '3.9' + - '3.10' + os: [ubuntu-latest] + steps: + - name: Check out repository code + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + pip install -r .github/requirements.txt + - name: Build + run: | + python setup.py build + - name: Test with pytest + run: | + export PYTHONPATH=$(pwd)/build/lib + python -m pytest diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7553bdd..0000000 --- a/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: python -python: - - "2.7" - - "3.4" - - "3.5" - - "3.6" - - "3.7" - - "3.8" - - "3.9" -install: pip install -r .req -script: make test PYTHON=python - -# Local Variables: -# mode: yaml -# End: diff --git a/README.rst b/README.rst index f611646..be4cb7c 100644 --- a/README.rst +++ b/README.rst @@ -1,9 +1,9 @@ -|travis| |rtd| |pypi| - -.. |travis| image:: https://img.shields.io/travis/com/RKrahl/pytest-dependency - :target: https://travis-ci.com/RKrahl/pytest-dependency - :alt: Travis build status +|gh-test| |rtd| |pypi| +.. |gh-test| image:: https://github.com/RKrahl/pytest-dependency/actions/workflows/run-tests.yaml/badge.svg + :target: https://github.com/RKrahl/pytest-dependency/actions/workflows/run-tests.yaml + :alt: GitHub Workflow Status + .. |rtd| image:: https://img.shields.io/readthedocs/pytest-dependency/latest :target: https://pytest-dependency.readthedocs.io/en/latest/ :alt: Documentation build status From a2dfbc05a7f80bfb88de2465a268b608edf38594 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Fri, 24 Dec 2021 21:42:19 +0100 Subject: [PATCH 23/71] Tested successfully with Python 3.10 --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 46c02e6..65b17b2 100755 --- a/setup.py +++ b/setup.py @@ -107,6 +107,7 @@ class sdist(copy_file_mixin, distutils.command.sdist.sdist): 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', 'Operating System :: OS Independent', 'License :: OSI Approved :: Apache Software License', ], From e96cc5cc1da77f17bd2d023b313dcefa7fb0dc74 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Fri, 24 Dec 2021 21:25:56 +0100 Subject: [PATCH 24/71] Move the source into a src subdirectory --- setup.py | 3 ++- pytest_dependency.py => src/pytest_dependency.py | 0 2 files changed, 2 insertions(+), 1 deletion(-) rename pytest_dependency.py => src/pytest_dependency.py (100%) diff --git a/setup.py b/setup.py index 65b17b2..f62b3ac 100755 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ class copy_file_mixin: does some substitutions on the fly into distutils command class hierarchy. """ - Subst_srcs = {"pytest_dependency.py"} + Subst_srcs = {"src/pytest_dependency.py"} Subst = {'DOC': doc_string, 'VERSION': version} def copy_file(self, infile, outfile, preserve_mode=1, preserve_times=1, link=None, level=1): @@ -90,6 +90,7 @@ class sdist(copy_file_mixin, distutils.command.sdist.sdist): 'Documentation': 'https://pytest-dependency.readthedocs.io/', 'Source Code': 'https://github.com/RKrahl/pytest-dependency', }, + package_dir = {'': 'src'}, py_modules=['pytest_dependency'], install_requires=['pytest >= 3.7.0'], classifiers=[ diff --git a/pytest_dependency.py b/src/pytest_dependency.py similarity index 100% rename from pytest_dependency.py rename to src/pytest_dependency.py From f6a43ac0b2b95075b0adc0769ee2bb3ffd6b0c52 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 25 Dec 2021 00:07:01 +0100 Subject: [PATCH 25/71] Fix: must add the tests dir explicitely when calling pytest --- .github/workflows/run-tests.yaml | 2 +- README.rst | 2 +- doc/src/install.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 771d7fe..117d3c2 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -32,4 +32,4 @@ jobs: - name: Test with pytest run: | export PYTHONPATH=$(pwd)/build/lib - python -m pytest + python -m pytest tests diff --git a/README.rst b/README.rst index be4cb7c..47bb24a 100644 --- a/README.rst +++ b/README.rst @@ -57,7 +57,7 @@ Installation 3. Test (optional):: - $ PYTHONPATH=build/lib python -m pytest + $ PYTHONPATH=build/lib python -m pytest tests 4. Install:: diff --git a/doc/src/install.rst b/doc/src/install.rst index 482b33e..719a401 100644 --- a/doc/src/install.rst +++ b/doc/src/install.rst @@ -43,7 +43,7 @@ Installation 3. Test (optional):: - $ python -m pytest + $ python -m pytest tests 4. Install:: From 118ac57dc030a1d6919c9575ab420803a595612a Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 25 Dec 2021 04:17:19 +0100 Subject: [PATCH 26/71] Add testing of documentation examples --- tests/conftest.py | 15 ++++ tests/test_09_examples_advanced.py | 135 +++++++++++++++++++++++++++++ tests/test_09_examples_names.py | 25 ++++++ tests/test_09_examples_scope.py | 66 ++++++++++++++ tests/test_09_examples_usage.py | 99 +++++++++++++++++++++ 5 files changed, 340 insertions(+) create mode 100644 tests/test_09_examples_advanced.py create mode 100644 tests/test_09_examples_names.py create mode 100644 tests/test_09_examples_scope.py create mode 100644 tests/test_09_examples_usage.py diff --git a/tests/conftest.py b/tests/conftest.py index 26cdc0b..4955d3f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,22 @@ +import packaging.version +from pathlib import Path import pytest pytest_plugins = "pytester" +example_dir = (Path(__file__).parent / "../doc/examples").resolve() + +def require_pytest_version(minversion): + pytest_version = packaging.version.parse(pytest.__version__) + if pytest_version < packaging.version.parse(minversion): + pytest.skip("need pytest version %s or newer" % minversion, + allow_module_level=True) + +def get_example(fname): + path = example_dir / fname + assert path.is_file() + return path + @pytest.fixture def ctestdir(testdir): diff --git a/tests/test_09_examples_advanced.py b/tests/test_09_examples_advanced.py new file mode 100644 index 0000000..3b2f482 --- /dev/null +++ b/tests/test_09_examples_advanced.py @@ -0,0 +1,135 @@ +"""Test the included examples. +""" + +import pytest +from conftest import get_example, require_pytest_version + +require_pytest_version("4.2.0") + + +def test_dyn_parametrized(ctestdir): + """Dynamic compilation of marked parameters + """ + with get_example("dyn-parametrized.py").open("rt") as f: + ctestdir.makepyfile(f.read()) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=11, skipped=1, failed=0, xfailed=1) + result.stdout.re_match_lines(r""" + .*::test_child\[c0\] PASSED + .*::test_child\[c1\] PASSED + .*::test_child\[c2\] PASSED + .*::test_child\[c3\] PASSED + .*::test_child\[c4\] PASSED + .*::test_child\[c5\] PASSED + .*::test_child\[c6\] PASSED + .*::test_child\[c7\] XFAIL(?:\s+\(.*\))? + .*::test_child\[c8\] PASSED + .*::test_parent\[p0\] PASSED + .*::test_parent\[p1\] PASSED + .*::test_parent\[p2\] PASSED + .*::test_parent\[p3\] SKIPPED(?:\s+\(.*\))? + """) + + +def test_group_fixture1(ctestdir): + """Grouping tests using fixtures 1 + """ + with get_example("group-fixture.py").open("rt") as f: + ctestdir.makepyfile(f.read()) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=16, skipped=1, failed=0, xfailed=1) + result.stdout.re_match_lines(r""" + .*::test_a\[1\] PASSED + .*::test_b\[1\] PASSED + .*::test_a\[2\] PASSED + .*::test_b\[2\] PASSED + .*::test_a\[3\] PASSED + .*::test_b\[3\] PASSED + .*::test_a\[4\] PASSED + .*::test_b\[4\] PASSED + .*::test_a\[5\] PASSED + .*::test_b\[5\] PASSED + .*::test_a\[6\] PASSED + .*::test_b\[6\] PASSED + .*::test_a\[7\] XFAIL(?:\s+\(.*\))? + .*::test_b\[7\] SKIPPED(?:\s+\(.*\))? + .*::test_a\[8\] PASSED + .*::test_b\[8\] PASSED + .*::test_a\[9\] PASSED + .*::test_b\[9\] PASSED + """) + + +def test_group_fixture2(ctestdir): + """Grouping tests using fixtures 2 + """ + with get_example("group-fixture2.py").open("rt") as f: + ctestdir.makepyfile(f.read()) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=24, skipped=2, failed=0, xfailed=1) + result.stdout.re_match_lines(r""" + .*::test_a\[1\] PASSED + .*::test_b\[1\] PASSED + .*::test_c\[1\] PASSED + .*::test_a\[2\] PASSED + .*::test_b\[2\] PASSED + .*::test_c\[2\] PASSED + .*::test_a\[3\] PASSED + .*::test_b\[3\] PASSED + .*::test_c\[3\] PASSED + .*::test_a\[4\] PASSED + .*::test_b\[4\] PASSED + .*::test_c\[4\] PASSED + .*::test_a\[5\] PASSED + .*::test_b\[5\] PASSED + .*::test_c\[5\] PASSED + .*::test_a\[6\] PASSED + .*::test_b\[6\] PASSED + .*::test_c\[6\] PASSED + .*::test_a\[7\] XFAIL(?:\s+\(.*\))? + .*::test_b\[7\] SKIPPED(?:\s+\(.*\))? + .*::test_c\[7\] SKIPPED(?:\s+\(.*\))? + .*::test_a\[8\] PASSED + .*::test_b\[8\] PASSED + .*::test_c\[8\] PASSED + .*::test_a\[9\] PASSED + .*::test_b\[9\] PASSED + .*::test_c\[9\] PASSED + """) + + +def test_all_params(ctestdir): + """Depend on all instances of a parametrized test at once + """ + with get_example("all_params.py").open("rt") as f: + ctestdir.makepyfile(f.read()) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=20, skipped=3, failed=0, xfailed=3) + result.stdout.re_match_lines(r""" + .*::test_a\[0\] PASSED + .*::test_a\[1\] PASSED + .*::test_a\[2\] PASSED + .*::test_a\[3\] PASSED + .*::test_a\[4\] PASSED + .*::test_a\[5\] PASSED + .*::test_a\[6\] PASSED + .*::test_a\[7\] PASSED + .*::test_a\[8\] PASSED + .*::test_a\[9\] PASSED + .*::test_a\[10\] PASSED + .*::test_a\[11\] PASSED + .*::test_a\[12\] PASSED + .*::test_a\[13\] XFAIL(?:\s+\(.*\))? + .*::test_a\[14\] PASSED + .*::test_a\[15\] PASSED + .*::test_a\[16\] PASSED + .*::test_b SKIPPED(?:\s+\(.*\))? + .*::test_c\[0-2\] PASSED + .*::test_c\[2-3\] PASSED + .*::test_c\[4-4\] PASSED + .*::test_c\[6-5\] XFAIL(?:\s+\(.*\))? + .*::test_d SKIPPED(?:\s+\(.*\))? + .*::test_e\[abc\] PASSED + .*::test_e\[def\] XFAIL(?:\s+\(.*\))? + .*::test_f SKIPPED(?:\s+\(.*\))? + """) diff --git a/tests/test_09_examples_names.py b/tests/test_09_examples_names.py new file mode 100644 index 0000000..e56afc9 --- /dev/null +++ b/tests/test_09_examples_names.py @@ -0,0 +1,25 @@ +"""Test the included examples. +""" + +import pytest +from conftest import get_example, require_pytest_version + +require_pytest_version("4.2.0") + + +def test_nodeid(ctestdir): + """Node ids + """ + with get_example("nodeid.py").open("rt") as f: + ctestdir.makepyfile(f.read()) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=6, skipped=0, failed=0, xfailed=1) + result.stdout.re_match_lines(r""" + .*::test_a PASSED + .*::test_b\[7-True\] PASSED + .*::test_b\[0-False\] PASSED + .*::test_b\[-1-False\] XFAIL(?:\s+\(.*\))? + .*::TestClass::test_c PASSED + .*::TestClass::test_d\[order\] PASSED + .*::TestClass::test_d\[disorder\] PASSED + """) diff --git a/tests/test_09_examples_scope.py b/tests/test_09_examples_scope.py new file mode 100644 index 0000000..ed45cad --- /dev/null +++ b/tests/test_09_examples_scope.py @@ -0,0 +1,66 @@ +"""Test the included examples. +""" + +from pathlib import Path +import pytest +from conftest import get_example, require_pytest_version + +require_pytest_version("4.2.0") + + +def test_scope_module(ctestdir): + """Explicitely specifying the scope + """ + with get_example("scope_module.py").open("rt") as f: + ctestdir.makepyfile(f.read()) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=2, skipped=2, failed=0, xfailed=1) + result.stdout.re_match_lines(r""" + .*::test_a XFAIL(?:\s+\(.*\))? + .*::test_b PASSED + .*::test_c SKIPPED(?:\s+\(.*\))? + .*::test_d PASSED + .*::test_e SKIPPED(?:\s+\(.*\))? + """) + + +def test_scope_session(ctestdir): + """Dependencies in session scope + """ + subdir = Path(ctestdir.tmpdir) / "tests" + subdir.mkdir() + with get_example("scope_session_mod_01.py").open("rt") as sf: + with (subdir / "test_mod_01.py").open("wt") as df: + df.write(sf.read()) + with get_example("scope_session_mod_02.py").open("rt") as sf: + with (subdir / "test_mod_02.py").open("wt") as df: + df.write(sf.read()) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=5, skipped=1, failed=0, xfailed=2) + result.stdout.re_match_lines(r""" + tests/test_mod_01.py::test_a PASSED + tests/test_mod_01.py::test_b XFAIL(?:\s+\(.*\))? + tests/test_mod_01.py::test_c PASSED + tests/test_mod_01.py::TestClass::test_b PASSED + tests/test_mod_02.py::test_a XFAIL(?:\s+\(.*\))? + tests/test_mod_02.py::test_e PASSED + tests/test_mod_02.py::test_f SKIPPED(?:\s+\(.*\))? + tests/test_mod_02.py::test_g PASSED + """) + + +def test_scope_class(ctestdir): + """The class scope + """ + with get_example("scope_class.py").open("rt") as f: + ctestdir.makepyfile(f.read()) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=3, skipped=2, failed=0, xfailed=1) + result.stdout.re_match_lines(r""" + .*::test_a XFAIL(?:\s+\(.*\))? + .*::TestClass1::test_b PASSED + .*::TestClass2::test_a PASSED + .*::TestClass2::test_c SKIPPED(?:\s+\(.*\))? + .*::TestClass2::test_d PASSED + .*::TestClass2::test_e SKIPPED(?:\s+\(.*\))? + """) diff --git a/tests/test_09_examples_usage.py b/tests/test_09_examples_usage.py new file mode 100644 index 0000000..357e2c2 --- /dev/null +++ b/tests/test_09_examples_usage.py @@ -0,0 +1,99 @@ +"""Test the included examples. +""" + +import pytest +from conftest import get_example, require_pytest_version + +require_pytest_version("4.2.0") + + +def test_basic(ctestdir): + """Basic usage + """ + with get_example("basic.py").open("rt") as f: + ctestdir.makepyfile(f.read()) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=2, skipped=2, failed=0, xfailed=1) + result.stdout.re_match_lines(r""" + .*::test_a XFAIL(?:\s+\(.*\))? + .*::test_b PASSED + .*::test_c SKIPPED(?:\s+\(.*\))? + .*::test_d PASSED + .*::test_e SKIPPED(?:\s+\(.*\))? + """) + + +def test_named(ctestdir): + """Naming tests + """ + with get_example("named.py").open("rt") as f: + ctestdir.makepyfile(f.read()) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=2, skipped=2, failed=0, xfailed=1) + result.stdout.re_match_lines(r""" + .*::test_a XFAIL(?:\s+\(.*\))? + .*::test_b PASSED + .*::test_c SKIPPED(?:\s+\(.*\))? + .*::test_d PASSED + .*::test_e SKIPPED(?:\s+\(.*\))? + """) + + +def test_testclass(ctestdir): + """Using test classes + """ + with get_example("testclass.py").open("rt") as f: + ctestdir.makepyfile(f.read()) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=4, skipped=4, failed=0, xfailed=2) + result.stdout.re_match_lines(r""" + .*::TestClass::test_a XFAIL(?:\s+\(.*\))? + .*::TestClass::test_b PASSED + .*::TestClass::test_c SKIPPED(?:\s+\(.*\))? + .*::TestClass::test_d PASSED + .*::TestClass::test_e SKIPPED(?:\s+\(.*\))? + .*::TestClassNamed::test_a XFAIL(?:\s+\(.*\))? + .*::TestClassNamed::test_b PASSED + .*::TestClassNamed::test_c SKIPPED(?:\s+\(.*\))? + .*::TestClassNamed::test_d PASSED + .*::TestClassNamed::test_e SKIPPED(?:\s+\(.*\))? + """) + + +def test_parametrized(ctestdir): + """Parametrized tests + """ + with get_example("parametrized.py").open("rt") as f: + ctestdir.makepyfile(f.read()) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=7, skipped=5, failed=0, xfailed=1) + result.stdout.re_match_lines(r""" + .*::test_a\[0-0\] PASSED + .*::test_a\[0-1\] XFAIL(?:\s+\(.*\))? + .*::test_a\[1-0\] PASSED + .*::test_a\[1-1\] PASSED + .*::test_b\[1-2\] SKIPPED(?:\s+\(.*\))? + .*::test_b\[1-3\] PASSED + .*::test_b\[1-4\] PASSED + .*::test_b\[2-3\] SKIPPED(?:\s+\(.*\))? + .*::test_b\[2-4\] SKIPPED(?:\s+\(.*\))? + .*::test_b\[3-4\] PASSED + .*::test_c\[1\] SKIPPED(?:\s+\(.*\))? + .*::test_c\[2\] PASSED + .*::test_c\[3\] SKIPPED(?:\s+\(.*\))? + """) + + +def test_runtime(ctestdir): + """Marking dependencies at runtime + """ + with get_example("runtime.py").open("rt") as f: + ctestdir.makepyfile(f.read()) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=1, skipped=2, failed=0, xfailed=1) + result.stdout.re_match_lines(r""" + .*::test_a PASSED + .*::test_b XFAIL(?:\s+\(.*\))? + .*::test_c SKIPPED(?:\s+\(.*\))? + .*::test_d SKIPPED(?:\s+\(.*\))? + """) From 4cf2e79c9a09bd81b35e1ec04bc8822d3ca27a2e Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 25 Dec 2021 04:37:22 +0100 Subject: [PATCH 27/71] Fix compatibility issues in tests --- .github/requirements.txt | 1 + tests/test_09_examples_scope.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/requirements.txt b/.github/requirements.txt index d8b46d9..3b3dd3d 100644 --- a/.github/requirements.txt +++ b/.github/requirements.txt @@ -1,2 +1,3 @@ +pathlib ; python_version == '2.7' pytest >=3.7.0 setuptools_scm diff --git a/tests/test_09_examples_scope.py b/tests/test_09_examples_scope.py index ed45cad..e004823 100644 --- a/tests/test_09_examples_scope.py +++ b/tests/test_09_examples_scope.py @@ -27,7 +27,7 @@ def test_scope_module(ctestdir): def test_scope_session(ctestdir): """Dependencies in session scope """ - subdir = Path(ctestdir.tmpdir) / "tests" + subdir = Path(str(ctestdir.tmpdir)) / "tests" subdir.mkdir() with get_example("scope_session_mod_01.py").open("rt") as sf: with (subdir / "test_mod_01.py").open("wt") as df: From 77b9c1e41696374e4d9b82d2cc0542adf4c80632 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 25 Dec 2021 12:01:02 +0100 Subject: [PATCH 28/71] Fix typos in the documentation --- doc/src/advanced.rst | 2 +- doc/src/configuration.rst | 2 +- doc/src/usage.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/src/advanced.rst b/doc/src/advanced.rst index f5ef02a..9af47d6 100644 --- a/doc/src/advanced.rst +++ b/doc/src/advanced.rst @@ -18,7 +18,7 @@ Consider the following example test module: In principle, this example works the very same way as the basic example for :ref:`usage-parametrized`. The only difference is that -the lists of paramters are dynamically compiled beforehand. The test +the lists of parameters are dynamically compiled beforehand. The test for child `l` deliberately fails, just to show the effect. As a consequence, the test for its parent `d` will be skipped. diff --git a/doc/src/configuration.rst b/doc/src/configuration.rst index 151a1ec..d89cb31 100644 --- a/doc/src/configuration.rst +++ b/doc/src/configuration.rst @@ -47,7 +47,7 @@ The following command line options are added by pytest.dependency: if any of the dependencies has been skipped or failed. E.g. dependencies that have not been run at all will be ignored. - This may be useful if you run only a subset of the testsuite and + This may be useful if you run only a subset of the test suite and some tests in the selected set are marked to depend on other tests that have not been selected. diff --git a/doc/src/usage.rst b/doc/src/usage.rst index be97ef2..09308bd 100644 --- a/doc/src/usage.rst +++ b/doc/src/usage.rst @@ -21,7 +21,7 @@ test, we will get the following result: .. literalinclude:: ../examples/basic.out The first test has deliberately been set to fail to illustrate the -effect. We will get the following resuts: +effect. We will get the following results: `test_a` deliberately fails. From 5adffde58a63a759c300320fb0ff95e7457c63f0 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 25 Dec 2021 12:02:54 +0100 Subject: [PATCH 29/71] Add a documentation section on logical combinations of dependencies --- doc/examples/or_dependency.py | 11 ----------- doc/src/advanced.rst | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/doc/examples/or_dependency.py b/doc/examples/or_dependency.py index 655ec61..99b288b 100644 --- a/doc/examples/or_dependency.py +++ b/doc/examples/or_dependency.py @@ -2,17 +2,6 @@ from pytest_dependency import depends def depends_or(request, other, scope='module'): - """Add dependency on any of the other tests. - - Call pytest.skip() unless a successful outcome of any of the tests - in `other` has been registered previously. This helper is similar - to `pytest_dependency.depends()`. It takes the same arguments. - But while `pytest_dependency.depends()` combines the tests in - `other` in an and-like manner, it skips the current test unless - all other tests did succeed, this function combines them in an - or-like manner, it runs the current test if at least one of the - other tests did succeed. - """ item = request.node for o in other: try: diff --git a/doc/src/advanced.rst b/doc/src/advanced.rst index 9af47d6..0eb937f 100644 --- a/doc/src/advanced.rst +++ b/doc/src/advanced.rst @@ -80,3 +80,31 @@ It requires the parameter values to be scalars that can easily be converted to strings. And it will fail if the same list of parameters is passed to the same test more then once, because then, pytest will add an index to the name to disambiguate the parameter values. + +Logical combinations of dependencies +------------------------------------ + +The dependencies passed as in the `depends` argument to the +:func:`pytest.mark.dependency` marker are combined in an and-like +manner: the current test is skipped unless *all* dependencies did +succeed. Sometimes one may want to combine the dependencies in a +different way. This is not supported by pytest-dependency out of the +box, but it is not difficult to implement. Consider the following +example: + +.. literalinclude:: ../examples/or_dependency.py + +The helper function `depends_or()` is similar to +:func:`pytest_dependency.depends`, it takes the same arguments. The +only difference is that it combines the dependencies passed in the +`other` argument in an or-like manner: the current test will be run if +*at least one* of the other tests did succeed. + +The tests `test_c`, `test_d`, `test_e`, and `test_f` in this example +all depend on two other tests. Only `test_c` will be skipped, because +all tests in its dependency list fail. The other ones are run, +because they have at least one succeeding test in their dependency +list. + +Other logical combinations of dependencies are conceivable and may be +implemented in a similar way, according to the use case at hand. From a8cb125e833143524c25384e920b892ab30de3bc Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 25 Dec 2021 12:13:15 +0100 Subject: [PATCH 30/71] Add test for the logical combinations of dependencies example --- tests/test_09_examples_advanced.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/test_09_examples_advanced.py b/tests/test_09_examples_advanced.py index 3b2f482..9e72b57 100644 --- a/tests/test_09_examples_advanced.py +++ b/tests/test_09_examples_advanced.py @@ -133,3 +133,22 @@ def test_all_params(ctestdir): .*::test_e\[def\] XFAIL(?:\s+\(.*\))? .*::test_f SKIPPED(?:\s+\(.*\))? """) + + +def test_or_dependency(ctestdir): + """Logical combinations of dependencies + """ + with get_example("or_dependency.py").open("rt") as f: + ctestdir.makepyfile(f.read()) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=5, skipped=1, failed=0, xfailed=2) + result.stdout.re_match_lines(r""" + .*::test_ap PASSED + .*::test_ax XFAIL(?:\s+\(.*\))? + .*::test_bp PASSED + .*::test_bx XFAIL(?:\s+\(.*\))? + .*::test_c SKIPPED(?:\s+\(.*\))? + .*::test_d PASSED + .*::test_e PASSED + .*::test_f PASSED + """) From 65dc1f575c6a6572ca63f6357e8c0dcdac967b1b Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 25 Dec 2021 12:48:38 +0100 Subject: [PATCH 31/71] Document that the dependency marker may be applied to a class as a whole. Close #39. --- doc/examples/mark-class.py | 21 +++++++++++++++++++++ doc/src/usage.rst | 16 ++++++++++++++++ tests/test_09_examples_usage.py | 15 +++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 doc/examples/mark-class.py diff --git a/doc/examples/mark-class.py b/doc/examples/mark-class.py new file mode 100644 index 0000000..7cb944a --- /dev/null +++ b/doc/examples/mark-class.py @@ -0,0 +1,21 @@ +import pytest + + +@pytest.mark.dependency() +@pytest.mark.xfail(reason="deliberate fail") +def test_f(): + assert False + + +@pytest.mark.dependency(depends=["test_f"]) +class TestClass(object): + + def test_a(self): + pass + + @pytest.mark.dependency() + def test_b(self): + pass + + def test_c(self): + pass diff --git a/doc/src/usage.rst b/doc/src/usage.rst index 09308bd..047244e 100644 --- a/doc/src/usage.rst +++ b/doc/src/usage.rst @@ -73,6 +73,22 @@ explicit `name` argument to the :func:`pytest.mark.dependency` marker. The name of the class is prepended to the method name to form the default name for the test. +Applying the dependency marker to a class as a whole +---------------------------------------------------- + +The :func:`pytest.mark.dependency` marker may also be applied to a test +class as a whole. This has the same effect as applying that marker +with the same arguments to each method of the class individually. +Consider: + +.. literalinclude:: ../examples/mark-class.py + +The tests `TestClass::test_a` and `TestClass::test_c` will be skipped, +because they depend on `test_f`. But `TestClass::test_b` will be run, +because it is individually marked. The marker on the test method +overrides the marker on the class and thus effectively clears the +dependency list for `TestClass::test_b`. + .. _usage-parametrized: Parametrized tests diff --git a/tests/test_09_examples_usage.py b/tests/test_09_examples_usage.py index 357e2c2..70a9859 100644 --- a/tests/test_09_examples_usage.py +++ b/tests/test_09_examples_usage.py @@ -60,6 +60,21 @@ def test_testclass(ctestdir): """) +def test_mark_class(ctestdir): + """Applying the dependency marker to a class as a whole + """ + with get_example("mark-class.py").open("rt") as f: + ctestdir.makepyfile(f.read()) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=1, skipped=2, failed=0, xfailed=1) + result.stdout.re_match_lines(r""" + .*::test_f XFAIL(?:\s+\(.*\))? + .*::TestClass::test_a SKIPPED(?:\s+\(.*\))? + .*::TestClass::test_b PASSED + .*::TestClass::test_c SKIPPED(?:\s+\(.*\))? + """) + + def test_parametrized(ctestdir): """Parametrized tests """ From b945b9576ffcd537db7aa9fd4774ee7948833054 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Mon, 27 Dec 2021 13:40:47 +0100 Subject: [PATCH 32/71] Add a warning that the documented solution for logical combinations of dependencies is based on undocumented pytest features --- doc/src/advanced.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/src/advanced.rst b/doc/src/advanced.rst index 0eb937f..77c67d9 100644 --- a/doc/src/advanced.rst +++ b/doc/src/advanced.rst @@ -108,3 +108,11 @@ list. Other logical combinations of dependencies are conceivable and may be implemented in a similar way, according to the use case at hand. + +.. note:: + The `depends_or()` helper function above is based on pytest + internals: skipping of tests works by raising an exception and the + exception class is exposed as :attr:`pytest.skip.Exception`. This + is not documented in pytest. It has been tested to work for pytest + versions 3.7.0 through 6.2.5, but it is not guaranteed to be stable + for future pytest versions. From 0667826704242b4e7549747aeba4de719140d625 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Mon, 27 Dec 2021 17:39:56 +0100 Subject: [PATCH 33/71] Try out several different truth values for the automark ini-option in the tests --- tests/test_04_automark.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/test_04_automark.py b/tests/test_04_automark.py index 7251405..09fbc17 100644 --- a/tests/test_04_automark.py +++ b/tests/test_04_automark.py @@ -29,7 +29,10 @@ def test_b(): """) -def test_set_false(ctestdir): +@pytest.mark.parametrize( + "false_value", ["0", "no", "n", "False", "false", "f", "off"] +) +def test_set_false(ctestdir, false_value): """A pytest.ini is present, automark_dependency is set to false. Since automark_dependency is set to false and test_a is not @@ -38,9 +41,9 @@ def test_set_false(ctestdir): """ ctestdir.makefile('.ini', pytest=""" [pytest] - automark_dependency = false + automark_dependency = %s console_output_style = classic - """) + """ % false_value) ctestdir.makepyfile(""" import pytest @@ -59,7 +62,10 @@ def test_b(): """) -def test_set_true(ctestdir): +@pytest.mark.parametrize( + "true_value", ["1", "yes", "y", "True", "true", "t", "on"] +) +def test_set_true(ctestdir, true_value): """A pytest.ini is present, automark_dependency is set to false. Since automark_dependency is set to true, the outcome of test_a @@ -68,9 +74,9 @@ def test_set_true(ctestdir): """ ctestdir.makefile('.ini', pytest=""" [pytest] - automark_dependency = true + automark_dependency = %s console_output_style = classic - """) + """ % true_value) ctestdir.makepyfile(""" import pytest From f6bfa5c55921743a4bb4e1873182cc79089c5251 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Mon, 27 Dec 2021 17:43:43 +0100 Subject: [PATCH 34/71] Declare the type of the automark_dependency ini-option as bool, rather than trying to parse boolean from a string value --- src/pytest_dependency.py | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/pytest_dependency.py b/src/pytest_dependency.py index 9ebf94a..43224ee 100644 --- a/src/pytest_dependency.py +++ b/src/pytest_dependency.py @@ -11,20 +11,6 @@ _ignore_unknown = False -def _get_bool(value): - """Evaluate string representation of a boolean value. - """ - if value: - if value.lower() in ["0", "no", "n", "false", "f", "off"]: - return False - elif value.lower() in ["1", "yes", "y", "true", "t", "on"]: - return True - else: - raise ValueError("Invalid truth value '%s'" % value) - else: - return False - - class DependencyItemStatus(object): """Status of a test item in a dependency manager. """ @@ -142,7 +128,7 @@ def depends(request, other, scope='module'): def pytest_addoption(parser): parser.addini("automark_dependency", "Add the dependency marker to all tests automatically", - default=False) + type="bool", default=False) parser.addoption("--ignore-unknown-dependency", action="store_true", default=False, help="ignore dependencies whose outcome is not known") @@ -150,7 +136,7 @@ def pytest_addoption(parser): def pytest_configure(config): global _automark, _ignore_unknown - _automark = _get_bool(config.getini("automark_dependency")) + _automark = config.getini("automark_dependency") _ignore_unknown = config.getoption("--ignore-unknown-dependency") config.addinivalue_line("markers", "dependency(name=None, depends=[]): " From 686055b8e7e87a4858f42020212e8cc3f0a12ba7 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Mon, 27 Dec 2021 18:01:32 +0100 Subject: [PATCH 35/71] Update changelog --- doc/src/changelog.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/src/changelog.rst b/doc/src/changelog.rst index 9b1c2de..e46138a 100644 --- a/doc/src/changelog.rst +++ b/doc/src/changelog.rst @@ -5,10 +5,13 @@ dev (not yet released) Bug fixes and minor changes + `#40`_: add logging. + `#50`_, `#51`_: test suite incompatibility with pytest 6.2.0. + + `#58`_: declare the type of automark_dependency ini-option + correctly as bool. .. _#40: https://github.com/RKrahl/pytest-dependency/issues/40 .. _#50: https://github.com/RKrahl/pytest-dependency/issues/50 .. _#51: https://github.com/RKrahl/pytest-dependency/pull/51 +.. _#58: https://github.com/RKrahl/pytest-dependency/pull/58 0.5.1 (2020-02-14) Bug fixes and minor changes From 6835cf4369630ea8d98aa3c4bd3addb6c0e2713e Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Wed, 29 Dec 2021 13:43:36 +0100 Subject: [PATCH 36/71] Remove dependency on the pytest version in tests of documentation examples --- tests/conftest.py | 7 ----- tests/test_09_examples_advanced.py | 36 ++++++++++++++++---------- tests/test_09_examples_names.py | 11 ++++---- tests/test_09_examples_scope.py | 27 ++++++++++++-------- tests/test_09_examples_usage.py | 41 ++++++++++++++++++++---------- 5 files changed, 73 insertions(+), 49 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 4955d3f..388dcc7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,3 @@ -import packaging.version from pathlib import Path import pytest @@ -6,12 +5,6 @@ example_dir = (Path(__file__).parent / "../doc/examples").resolve() -def require_pytest_version(minversion): - pytest_version = packaging.version.parse(pytest.__version__) - if pytest_version < packaging.version.parse(minversion): - pytest.skip("need pytest version %s or newer" % minversion, - allow_module_level=True) - def get_example(fname): path = example_dir / fname assert path.is_file() diff --git a/tests/test_09_examples_advanced.py b/tests/test_09_examples_advanced.py index 3b2f482..f2a9f95 100644 --- a/tests/test_09_examples_advanced.py +++ b/tests/test_09_examples_advanced.py @@ -2,9 +2,7 @@ """ import pytest -from conftest import get_example, require_pytest_version - -require_pytest_version("4.2.0") +from conftest import get_example def test_dyn_parametrized(ctestdir): @@ -13,7 +11,10 @@ def test_dyn_parametrized(ctestdir): with get_example("dyn-parametrized.py").open("rt") as f: ctestdir.makepyfile(f.read()) result = ctestdir.runpytest("--verbose") - result.assert_outcomes(passed=11, skipped=1, failed=0, xfailed=1) + try: + result.assert_outcomes(passed=11, skipped=1, failed=0, xfailed=1) + except TypeError: + result.assert_outcomes(passed=11, skipped=1, failed=0) result.stdout.re_match_lines(r""" .*::test_child\[c0\] PASSED .*::test_child\[c1\] PASSED @@ -22,7 +23,7 @@ def test_dyn_parametrized(ctestdir): .*::test_child\[c4\] PASSED .*::test_child\[c5\] PASSED .*::test_child\[c6\] PASSED - .*::test_child\[c7\] XFAIL(?:\s+\(.*\))? + .*::test_child\[c7\] (?:XFAIL(?:\s+\(.*\))?|xfail) .*::test_child\[c8\] PASSED .*::test_parent\[p0\] PASSED .*::test_parent\[p1\] PASSED @@ -37,7 +38,10 @@ def test_group_fixture1(ctestdir): with get_example("group-fixture.py").open("rt") as f: ctestdir.makepyfile(f.read()) result = ctestdir.runpytest("--verbose") - result.assert_outcomes(passed=16, skipped=1, failed=0, xfailed=1) + try: + result.assert_outcomes(passed=16, skipped=1, failed=0, xfailed=1) + except TypeError: + result.assert_outcomes(passed=16, skipped=1, failed=0) result.stdout.re_match_lines(r""" .*::test_a\[1\] PASSED .*::test_b\[1\] PASSED @@ -51,7 +55,7 @@ def test_group_fixture1(ctestdir): .*::test_b\[5\] PASSED .*::test_a\[6\] PASSED .*::test_b\[6\] PASSED - .*::test_a\[7\] XFAIL(?:\s+\(.*\))? + .*::test_a\[7\] (?:XFAIL(?:\s+\(.*\))?|xfail) .*::test_b\[7\] SKIPPED(?:\s+\(.*\))? .*::test_a\[8\] PASSED .*::test_b\[8\] PASSED @@ -66,7 +70,10 @@ def test_group_fixture2(ctestdir): with get_example("group-fixture2.py").open("rt") as f: ctestdir.makepyfile(f.read()) result = ctestdir.runpytest("--verbose") - result.assert_outcomes(passed=24, skipped=2, failed=0, xfailed=1) + try: + result.assert_outcomes(passed=24, skipped=2, failed=0, xfailed=1) + except TypeError: + result.assert_outcomes(passed=24, skipped=2, failed=0) result.stdout.re_match_lines(r""" .*::test_a\[1\] PASSED .*::test_b\[1\] PASSED @@ -86,7 +93,7 @@ def test_group_fixture2(ctestdir): .*::test_a\[6\] PASSED .*::test_b\[6\] PASSED .*::test_c\[6\] PASSED - .*::test_a\[7\] XFAIL(?:\s+\(.*\))? + .*::test_a\[7\] (?:XFAIL(?:\s+\(.*\))?|xfail) .*::test_b\[7\] SKIPPED(?:\s+\(.*\))? .*::test_c\[7\] SKIPPED(?:\s+\(.*\))? .*::test_a\[8\] PASSED @@ -104,7 +111,10 @@ def test_all_params(ctestdir): with get_example("all_params.py").open("rt") as f: ctestdir.makepyfile(f.read()) result = ctestdir.runpytest("--verbose") - result.assert_outcomes(passed=20, skipped=3, failed=0, xfailed=3) + try: + result.assert_outcomes(passed=20, skipped=3, failed=0, xfailed=3) + except TypeError: + result.assert_outcomes(passed=20, skipped=3, failed=0) result.stdout.re_match_lines(r""" .*::test_a\[0\] PASSED .*::test_a\[1\] PASSED @@ -119,7 +129,7 @@ def test_all_params(ctestdir): .*::test_a\[10\] PASSED .*::test_a\[11\] PASSED .*::test_a\[12\] PASSED - .*::test_a\[13\] XFAIL(?:\s+\(.*\))? + .*::test_a\[13\] (?:XFAIL(?:\s+\(.*\))?|xfail) .*::test_a\[14\] PASSED .*::test_a\[15\] PASSED .*::test_a\[16\] PASSED @@ -127,9 +137,9 @@ def test_all_params(ctestdir): .*::test_c\[0-2\] PASSED .*::test_c\[2-3\] PASSED .*::test_c\[4-4\] PASSED - .*::test_c\[6-5\] XFAIL(?:\s+\(.*\))? + .*::test_c\[6-5\] (?:XFAIL(?:\s+\(.*\))?|xfail) .*::test_d SKIPPED(?:\s+\(.*\))? .*::test_e\[abc\] PASSED - .*::test_e\[def\] XFAIL(?:\s+\(.*\))? + .*::test_e\[def\] (?:XFAIL(?:\s+\(.*\))?|xfail) .*::test_f SKIPPED(?:\s+\(.*\))? """) diff --git a/tests/test_09_examples_names.py b/tests/test_09_examples_names.py index e56afc9..7d45ba7 100644 --- a/tests/test_09_examples_names.py +++ b/tests/test_09_examples_names.py @@ -2,9 +2,7 @@ """ import pytest -from conftest import get_example, require_pytest_version - -require_pytest_version("4.2.0") +from conftest import get_example def test_nodeid(ctestdir): @@ -13,12 +11,15 @@ def test_nodeid(ctestdir): with get_example("nodeid.py").open("rt") as f: ctestdir.makepyfile(f.read()) result = ctestdir.runpytest("--verbose") - result.assert_outcomes(passed=6, skipped=0, failed=0, xfailed=1) + try: + result.assert_outcomes(passed=6, skipped=0, failed=0, xfailed=1) + except TypeError: + result.assert_outcomes(passed=6, skipped=0, failed=0) result.stdout.re_match_lines(r""" .*::test_a PASSED .*::test_b\[7-True\] PASSED .*::test_b\[0-False\] PASSED - .*::test_b\[-1-False\] XFAIL(?:\s+\(.*\))? + .*::test_b\[-1-False\] (?:XFAIL(?:\s+\(.*\))?|xfail) .*::TestClass::test_c PASSED .*::TestClass::test_d\[order\] PASSED .*::TestClass::test_d\[disorder\] PASSED diff --git a/tests/test_09_examples_scope.py b/tests/test_09_examples_scope.py index e004823..98a2400 100644 --- a/tests/test_09_examples_scope.py +++ b/tests/test_09_examples_scope.py @@ -3,9 +3,7 @@ from pathlib import Path import pytest -from conftest import get_example, require_pytest_version - -require_pytest_version("4.2.0") +from conftest import get_example def test_scope_module(ctestdir): @@ -14,9 +12,12 @@ def test_scope_module(ctestdir): with get_example("scope_module.py").open("rt") as f: ctestdir.makepyfile(f.read()) result = ctestdir.runpytest("--verbose") - result.assert_outcomes(passed=2, skipped=2, failed=0, xfailed=1) + try: + result.assert_outcomes(passed=2, skipped=2, failed=0, xfailed=1) + except TypeError: + result.assert_outcomes(passed=2, skipped=2, failed=0) result.stdout.re_match_lines(r""" - .*::test_a XFAIL(?:\s+\(.*\))? + .*::test_a (?:XFAIL(?:\s+\(.*\))?|xfail) .*::test_b PASSED .*::test_c SKIPPED(?:\s+\(.*\))? .*::test_d PASSED @@ -36,13 +37,16 @@ def test_scope_session(ctestdir): with (subdir / "test_mod_02.py").open("wt") as df: df.write(sf.read()) result = ctestdir.runpytest("--verbose") - result.assert_outcomes(passed=5, skipped=1, failed=0, xfailed=2) + try: + result.assert_outcomes(passed=5, skipped=1, failed=0, xfailed=2) + except TypeError: + result.assert_outcomes(passed=5, skipped=1, failed=0) result.stdout.re_match_lines(r""" tests/test_mod_01.py::test_a PASSED - tests/test_mod_01.py::test_b XFAIL(?:\s+\(.*\))? + tests/test_mod_01.py::test_b (?:XFAIL(?:\s+\(.*\))?|xfail) tests/test_mod_01.py::test_c PASSED tests/test_mod_01.py::TestClass::test_b PASSED - tests/test_mod_02.py::test_a XFAIL(?:\s+\(.*\))? + tests/test_mod_02.py::test_a (?:XFAIL(?:\s+\(.*\))?|xfail) tests/test_mod_02.py::test_e PASSED tests/test_mod_02.py::test_f SKIPPED(?:\s+\(.*\))? tests/test_mod_02.py::test_g PASSED @@ -55,9 +59,12 @@ def test_scope_class(ctestdir): with get_example("scope_class.py").open("rt") as f: ctestdir.makepyfile(f.read()) result = ctestdir.runpytest("--verbose") - result.assert_outcomes(passed=3, skipped=2, failed=0, xfailed=1) + try: + result.assert_outcomes(passed=3, skipped=2, failed=0, xfailed=1) + except TypeError: + result.assert_outcomes(passed=3, skipped=2, failed=0) result.stdout.re_match_lines(r""" - .*::test_a XFAIL(?:\s+\(.*\))? + .*::test_a (?:XFAIL(?:\s+\(.*\))?|xfail) .*::TestClass1::test_b PASSED .*::TestClass2::test_a PASSED .*::TestClass2::test_c SKIPPED(?:\s+\(.*\))? diff --git a/tests/test_09_examples_usage.py b/tests/test_09_examples_usage.py index 357e2c2..85db269 100644 --- a/tests/test_09_examples_usage.py +++ b/tests/test_09_examples_usage.py @@ -2,9 +2,7 @@ """ import pytest -from conftest import get_example, require_pytest_version - -require_pytest_version("4.2.0") +from conftest import get_example def test_basic(ctestdir): @@ -13,9 +11,12 @@ def test_basic(ctestdir): with get_example("basic.py").open("rt") as f: ctestdir.makepyfile(f.read()) result = ctestdir.runpytest("--verbose") - result.assert_outcomes(passed=2, skipped=2, failed=0, xfailed=1) + try: + result.assert_outcomes(passed=2, skipped=2, failed=0, xfailed=1) + except TypeError: + result.assert_outcomes(passed=2, skipped=2, failed=0) result.stdout.re_match_lines(r""" - .*::test_a XFAIL(?:\s+\(.*\))? + .*::test_a (?:XFAIL(?:\s+\(.*\))?|xfail) .*::test_b PASSED .*::test_c SKIPPED(?:\s+\(.*\))? .*::test_d PASSED @@ -29,9 +30,12 @@ def test_named(ctestdir): with get_example("named.py").open("rt") as f: ctestdir.makepyfile(f.read()) result = ctestdir.runpytest("--verbose") - result.assert_outcomes(passed=2, skipped=2, failed=0, xfailed=1) + try: + result.assert_outcomes(passed=2, skipped=2, failed=0, xfailed=1) + except TypeError: + result.assert_outcomes(passed=2, skipped=2, failed=0) result.stdout.re_match_lines(r""" - .*::test_a XFAIL(?:\s+\(.*\))? + .*::test_a (?:XFAIL(?:\s+\(.*\))?|xfail) .*::test_b PASSED .*::test_c SKIPPED(?:\s+\(.*\))? .*::test_d PASSED @@ -45,14 +49,17 @@ def test_testclass(ctestdir): with get_example("testclass.py").open("rt") as f: ctestdir.makepyfile(f.read()) result = ctestdir.runpytest("--verbose") - result.assert_outcomes(passed=4, skipped=4, failed=0, xfailed=2) + try: + result.assert_outcomes(passed=4, skipped=4, failed=0, xfailed=2) + except TypeError: + result.assert_outcomes(passed=4, skipped=4, failed=0) result.stdout.re_match_lines(r""" - .*::TestClass::test_a XFAIL(?:\s+\(.*\))? + .*::TestClass::test_a (?:XFAIL(?:\s+\(.*\))?|xfail) .*::TestClass::test_b PASSED .*::TestClass::test_c SKIPPED(?:\s+\(.*\))? .*::TestClass::test_d PASSED .*::TestClass::test_e SKIPPED(?:\s+\(.*\))? - .*::TestClassNamed::test_a XFAIL(?:\s+\(.*\))? + .*::TestClassNamed::test_a (?:XFAIL(?:\s+\(.*\))?|xfail) .*::TestClassNamed::test_b PASSED .*::TestClassNamed::test_c SKIPPED(?:\s+\(.*\))? .*::TestClassNamed::test_d PASSED @@ -66,10 +73,13 @@ def test_parametrized(ctestdir): with get_example("parametrized.py").open("rt") as f: ctestdir.makepyfile(f.read()) result = ctestdir.runpytest("--verbose") - result.assert_outcomes(passed=7, skipped=5, failed=0, xfailed=1) + try: + result.assert_outcomes(passed=7, skipped=5, failed=0, xfailed=1) + except TypeError: + result.assert_outcomes(passed=7, skipped=5, failed=0) result.stdout.re_match_lines(r""" .*::test_a\[0-0\] PASSED - .*::test_a\[0-1\] XFAIL(?:\s+\(.*\))? + .*::test_a\[0-1\] (?:XFAIL(?:\s+\(.*\))?|xfail) .*::test_a\[1-0\] PASSED .*::test_a\[1-1\] PASSED .*::test_b\[1-2\] SKIPPED(?:\s+\(.*\))? @@ -90,10 +100,13 @@ def test_runtime(ctestdir): with get_example("runtime.py").open("rt") as f: ctestdir.makepyfile(f.read()) result = ctestdir.runpytest("--verbose") - result.assert_outcomes(passed=1, skipped=2, failed=0, xfailed=1) + try: + result.assert_outcomes(passed=1, skipped=2, failed=0, xfailed=1) + except TypeError: + result.assert_outcomes(passed=1, skipped=2, failed=0) result.stdout.re_match_lines(r""" .*::test_a PASSED - .*::test_b XFAIL(?:\s+\(.*\))? + .*::test_b (?:XFAIL(?:\s+\(.*\))?|xfail) .*::test_c SKIPPED(?:\s+\(.*\))? .*::test_d SKIPPED(?:\s+\(.*\))? """) From 1d88f4d193b972dce4490c595cc468852ad58384 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 26 Dec 2021 21:35:16 +0100 Subject: [PATCH 37/71] Start writing a debugging guide --- doc/examples/debugging-logging.out | 72 ++++++++++++++++++++++++++++++ doc/examples/debugging-summary.out | 13 ++++++ doc/examples/debugging-verbose.out | 15 +++++++ doc/examples/debugging.py | 22 +++++++++ doc/src/debugging.rst | 46 +++++++++++++++++++ doc/src/index.rst | 1 + 6 files changed, 169 insertions(+) create mode 100644 doc/examples/debugging-logging.out create mode 100644 doc/examples/debugging-summary.out create mode 100644 doc/examples/debugging-verbose.out create mode 100644 doc/examples/debugging.py create mode 100644 doc/src/debugging.rst diff --git a/doc/examples/debugging-logging.out b/doc/examples/debugging-logging.out new file mode 100644 index 0000000..ca208dc --- /dev/null +++ b/doc/examples/debugging-logging.out @@ -0,0 +1,72 @@ +$ pytest --log-cli-format='%(levelname)s: %(message)s' --log-cli-level=DEBUG debugging.py +============================= test session starts ============================== +platform linux -- Python 3.10.1, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 +rootdir: /home/user +plugins: dependency-0.5.1 +collected 5 items + +debugging.py::test_a +-------------------------------- live log setup -------------------------------- +DEBUG: register setup debugging.py::test_a passed in session scope +DEBUG: register setup test_a passed in module scope +-------------------------------- live log call --------------------------------- +DEBUG: register call debugging.py::test_a skipped in session scope +DEBUG: register call test_a skipped in module scope +XFAIL (deliberate fail) [ 20%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_a passed in session scope +DEBUG: register teardown test_a passed in module scope + +debugging.py::test_b +-------------------------------- live log setup -------------------------------- +DEBUG: register setup debugging.py::test_b passed in session scope +DEBUG: register setup test_b passed in module scope +-------------------------------- live log call --------------------------------- +DEBUG: register call debugging.py::test_b passed in session scope +DEBUG: register call test_b passed in module scope +PASSED [ 40%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_b passed in session scope +DEBUG: register teardown test_b passed in module scope + +debugging.py::test_c +-------------------------------- live log setup -------------------------------- +DEBUG: check dependencies of test_c in module scope ... +DEBUG: ... test_a has not succeeded +INFO: skip test_c because it depends on test_a +DEBUG: register setup debugging.py::test_c skipped in session scope +DEBUG: register setup test_c skipped in module scope +SKIPPED (test_c depends on test_a) [ 60%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_c passed in session scope +DEBUG: register teardown test_c passed in module scope + +debugging.py::test_d +-------------------------------- live log setup -------------------------------- +DEBUG: check dependencies of test_d in module scope ... +DEBUG: ... test_b succeeded +DEBUG: register setup debugging.py::test_d passed in session scope +DEBUG: register setup test_d passed in module scope +-------------------------------- live log call --------------------------------- +DEBUG: register call debugging.py::test_d passed in session scope +DEBUG: register call test_d passed in module scope +PASSED [ 80%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_d passed in session scope +DEBUG: register teardown test_d passed in module scope + +debugging.py::test_e +-------------------------------- live log setup -------------------------------- +DEBUG: check dependencies of test_e in module scope ... +DEBUG: ... test_b succeeded +DEBUG: ... test_c has not succeeded +INFO: skip test_e because it depends on test_c +DEBUG: register setup debugging.py::test_e skipped in session scope +DEBUG: register setup test_e skipped in module scope +SKIPPED (test_e depends on test_c) [100%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_e passed in session scope +DEBUG: register teardown test_e passed in module scope + + +=================== 2 passed, 2 skipped, 1 xfailed in 0.03s ==================== diff --git a/doc/examples/debugging-summary.out b/doc/examples/debugging-summary.out new file mode 100644 index 0000000..aaeabb6 --- /dev/null +++ b/doc/examples/debugging-summary.out @@ -0,0 +1,13 @@ +$ pytest -rs debugging.py +============================= test session starts ============================== +platform linux -- Python 3.10.1, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 +rootdir: /home/user +plugins: dependency-0.5.1 +collected 5 items + +debugging.py x.s.s [100%] + +=========================== short test summary info ============================ +SKIPPED [1] /usr/lib/python3.10/site-packages/pytest_dependency.py:103: test_c depends on test_a +SKIPPED [1] /usr/lib/python3.10/site-packages/pytest_dependency.py:103: test_e depends on test_c +=================== 2 passed, 2 skipped, 1 xfailed in 0.02s ==================== diff --git a/doc/examples/debugging-verbose.out b/doc/examples/debugging-verbose.out new file mode 100644 index 0000000..780eee4 --- /dev/null +++ b/doc/examples/debugging-verbose.out @@ -0,0 +1,15 @@ +$ pytest --verbose debugging.py +============================= test session starts ============================== +platform linux -- Python 3.10.1, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 -- /usr/bin/python3 +cachedir: .pytest_cache +rootdir: /home/user +plugins: dependency-0.5.1 +collecting ... collected 5 items + +debugging.py::test_a XFAIL (deliberate fail) [ 20%] +debugging.py::test_b PASSED [ 40%] +debugging.py::test_c SKIPPED (test_c depends on test_a) [ 60%] +debugging.py::test_d PASSED [ 80%] +debugging.py::test_e SKIPPED (test_e depends on test_c) [100%] + +=================== 2 passed, 2 skipped, 1 xfailed in 0.03s ==================== diff --git a/doc/examples/debugging.py b/doc/examples/debugging.py new file mode 100644 index 0000000..af05dce --- /dev/null +++ b/doc/examples/debugging.py @@ -0,0 +1,22 @@ +import pytest + +@pytest.mark.dependency() +@pytest.mark.xfail(reason="deliberate fail") +def test_a(): + assert False + +@pytest.mark.dependency() +def test_b(): + pass + +@pytest.mark.dependency(depends=["test_a"]) +def test_c(): + pass + +@pytest.mark.dependency(depends=["test_b"]) +def test_d(): + pass + +@pytest.mark.dependency(depends=["test_b", "test_c"]) +def test_e(): + pass diff --git a/doc/src/debugging.rst b/doc/src/debugging.rst new file mode 100644 index 0000000..495e351 --- /dev/null +++ b/doc/src/debugging.rst @@ -0,0 +1,46 @@ +Debugging guide +=============== + +This section is supposed to provide hints on what to check if +pytest-dependency does not seem to behave as expected. + +Example +------- + +Throughout this debugging guide, we will consider the following +example: + +.. literalinclude:: ../examples/debugging.py + +Diagnostic tools +---------------- + +pytest summary +.............. + +You can request a short summary from pytest including information on +skipped tests using the ``-rs`` `command line option`__: + +.. literalinclude:: ../examples/debugging-summary.out + +.. __: https://docs.pytest.org/en/stable/usage.html#detailed-summary-report + +Verbose pytest output +..................... + +A list of all tests with their respective outcome will be displayed if +you call pytest with the ``--verbose`` command line option: + +.. literalinclude:: ../examples/debugging-verbose.out + +Logging +....... + +pytest-dependency emits log messages when registering test results and +when checking dependencies for a test. You can request these log +messages to be displayed at runtime using `log command line options`__ +in the pytest call: + +.. literalinclude:: ../examples/debugging-logging.out + +.. __: https://docs.pytest.org/en/stable/logging.html#live-logs diff --git a/doc/src/index.rst b/doc/src/index.rst index 0f034d1..790b277 100644 --- a/doc/src/index.rst +++ b/doc/src/index.rst @@ -17,6 +17,7 @@ Content of the documentation scope advanced names + debugging configuration changelog reference From 58ff4ffa113f77e0813fb99ef9438c6c0376be57 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Mon, 27 Dec 2021 17:27:28 +0100 Subject: [PATCH 38/71] Expand the debugging example, including several samples of potential issues --- doc/examples/debugging-logging.out | 269 ++++++++++++++++++++++++++++- doc/examples/debugging-summary.out | 21 ++- doc/examples/debugging-verbose.out | 36 +++- doc/examples/debugging.py | 91 ++++++++++ 4 files changed, 395 insertions(+), 22 deletions(-) diff --git a/doc/examples/debugging-logging.out b/doc/examples/debugging-logging.out index ca208dc..5fe0db0 100644 --- a/doc/examples/debugging-logging.out +++ b/doc/examples/debugging-logging.out @@ -2,8 +2,8 @@ $ pytest --log-cli-format='%(levelname)s: %(message)s' --log-cli-level=DEBUG deb ============================= test session starts ============================== platform linux -- Python 3.10.1, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 rootdir: /home/user -plugins: dependency-0.5.1 -collected 5 items +plugins: dependency-0.6.0 +collected 25 items debugging.py::test_a -------------------------------- live log setup -------------------------------- @@ -12,7 +12,7 @@ DEBUG: register setup test_a passed in module scope -------------------------------- live log call --------------------------------- DEBUG: register call debugging.py::test_a skipped in session scope DEBUG: register call test_a skipped in module scope -XFAIL (deliberate fail) [ 20%] +XFAIL (deliberate fail) [ 4%] ------------------------------ live log teardown ------------------------------- DEBUG: register teardown debugging.py::test_a passed in session scope DEBUG: register teardown test_a passed in module scope @@ -24,7 +24,7 @@ DEBUG: register setup test_b passed in module scope -------------------------------- live log call --------------------------------- DEBUG: register call debugging.py::test_b passed in session scope DEBUG: register call test_b passed in module scope -PASSED [ 40%] +PASSED [ 8%] ------------------------------ live log teardown ------------------------------- DEBUG: register teardown debugging.py::test_b passed in session scope DEBUG: register teardown test_b passed in module scope @@ -36,7 +36,7 @@ DEBUG: ... test_a has not succeeded INFO: skip test_c because it depends on test_a DEBUG: register setup debugging.py::test_c skipped in session scope DEBUG: register setup test_c skipped in module scope -SKIPPED (test_c depends on test_a) [ 60%] +SKIPPED (test_c depends on test_a) [ 12%] ------------------------------ live log teardown ------------------------------- DEBUG: register teardown debugging.py::test_c passed in session scope DEBUG: register teardown test_c passed in module scope @@ -50,7 +50,7 @@ DEBUG: register setup test_d passed in module scope -------------------------------- live log call --------------------------------- DEBUG: register call debugging.py::test_d passed in session scope DEBUG: register call test_d passed in module scope -PASSED [ 80%] +PASSED [ 16%] ------------------------------ live log teardown ------------------------------- DEBUG: register teardown debugging.py::test_d passed in session scope DEBUG: register teardown test_d passed in module scope @@ -63,10 +63,263 @@ DEBUG: ... test_c has not succeeded INFO: skip test_e because it depends on test_c DEBUG: register setup debugging.py::test_e skipped in session scope DEBUG: register setup test_e skipped in module scope -SKIPPED (test_e depends on test_c) [100%] +SKIPPED (test_e depends on test_c) [ 20%] ------------------------------ live log teardown ------------------------------- DEBUG: register teardown debugging.py::test_e passed in session scope DEBUG: register teardown test_e passed in module scope +debugging.py::TestClass::test_a +-------------------------------- live log setup -------------------------------- +DEBUG: register setup debugging.py::TestClass::test_a passed in session scope +DEBUG: register setup TestClass::test_a passed in module scope +DEBUG: register setup test_a passed in class scope +-------------------------------- live log call --------------------------------- +DEBUG: register call debugging.py::TestClass::test_a passed in session scope +DEBUG: register call TestClass::test_a passed in module scope +DEBUG: register call test_a passed in class scope +PASSED [ 24%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::TestClass::test_a passed in session scope +DEBUG: register teardown TestClass::test_a passed in module scope +DEBUG: register teardown test_a passed in class scope + +debugging.py::TestClass::test_b +-------------------------------- live log setup -------------------------------- +DEBUG: register setup debugging.py::TestClass::test_b passed in session scope +DEBUG: register setup TestClass::test_b passed in module scope +DEBUG: register setup test_b passed in class scope +-------------------------------- live log call --------------------------------- +DEBUG: register call debugging.py::TestClass::test_b skipped in session scope +DEBUG: register call TestClass::test_b skipped in module scope +DEBUG: register call test_b skipped in class scope +XFAIL (deliberate fail) [ 28%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::TestClass::test_b passed in session scope +DEBUG: register teardown TestClass::test_b passed in module scope +DEBUG: register teardown test_b passed in class scope + +debugging.py::TestClass::test_c +-------------------------------- live log setup -------------------------------- +DEBUG: check dependencies of test_c in module scope ... +DEBUG: ... test_b succeeded +DEBUG: register setup debugging.py::TestClass::test_c passed in session scope +DEBUG: register setup TestClass::test_c passed in module scope +DEBUG: register setup test_c passed in class scope +-------------------------------- live log call --------------------------------- +DEBUG: register call debugging.py::TestClass::test_c passed in session scope +DEBUG: register call TestClass::test_c passed in module scope +DEBUG: register call test_c passed in class scope +PASSED [ 32%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::TestClass::test_c passed in session scope +DEBUG: register teardown TestClass::test_c passed in module scope +DEBUG: register teardown test_c passed in class scope + +debugging.py::test_colors[RED] +-------------------------------- live log setup -------------------------------- +DEBUG: register setup debugging.py::test_colors[RED] passed in session scope +DEBUG: register setup test_colors[RED] passed in module scope +-------------------------------- live log call --------------------------------- +DEBUG: register call debugging.py::test_colors[RED] passed in session scope +DEBUG: register call test_colors[RED] passed in module scope +PASSED [ 36%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_colors[RED] passed in session scope +DEBUG: register teardown test_colors[RED] passed in module scope + +debugging.py::test_colors[GREEN] +-------------------------------- live log setup -------------------------------- +DEBUG: register setup debugging.py::test_colors[GREEN] passed in session scope +DEBUG: register setup test_colors[GREEN] passed in module scope +-------------------------------- live log call --------------------------------- +DEBUG: register call debugging.py::test_colors[GREEN] passed in session scope +DEBUG: register call test_colors[GREEN] passed in module scope +PASSED [ 40%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_colors[GREEN] passed in session scope +DEBUG: register teardown test_colors[GREEN] passed in module scope + +debugging.py::test_colors[BLUE] +-------------------------------- live log setup -------------------------------- +DEBUG: register setup debugging.py::test_colors[BLUE] passed in session scope +DEBUG: register setup test_colors[BLUE] passed in module scope +-------------------------------- live log call --------------------------------- +DEBUG: register call debugging.py::test_colors[BLUE] passed in session scope +DEBUG: register call test_colors[BLUE] passed in module scope +PASSED [ 44%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_colors[BLUE] passed in session scope +DEBUG: register teardown test_colors[BLUE] passed in module scope + +debugging.py::test_multicolored +-------------------------------- live log setup -------------------------------- +DEBUG: check dependencies of test_multicolored in module scope ... +DEBUG: ... test_colors is unknown +INFO: skip test_multicolored because it depends on test_colors +DEBUG: register setup debugging.py::test_multicolored skipped in session scope +DEBUG: register setup test_multicolored skipped in module scope +SKIPPED (test_multicolored depends on test_colors) [ 48%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_multicolored passed in session scope +DEBUG: register teardown test_multicolored passed in module scope + +debugging.py::test_alert +-------------------------------- live log setup -------------------------------- +DEBUG: check dependencies of test_alert in module scope ... +DEBUG: ... test_colors[Color.RED] is unknown +INFO: skip test_alert because it depends on test_colors[Color.RED] +DEBUG: register setup debugging.py::test_alert skipped in session scope +DEBUG: register setup test_alert skipped in module scope +SKIPPED (test_alert depends on test_colors[Color.RED]) [ 52%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_alert passed in session scope +DEBUG: register teardown test_alert passed in module scope + +debugging.py::test_g +-------------------------------- live log setup -------------------------------- +DEBUG: check dependencies of test_g in module scope ... +DEBUG: ... test_f is unknown +INFO: skip test_g because it depends on test_f +DEBUG: register setup debugging.py::test_g skipped in session scope +DEBUG: register setup test_g skipped in module scope +SKIPPED (test_g depends on test_f) [ 56%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_g passed in session scope +DEBUG: register teardown test_g passed in module scope + +debugging.py::test_h +-------------------------------- live log setup -------------------------------- +DEBUG: register setup h passed in session scope +DEBUG: register setup h passed in module scope +-------------------------------- live log call --------------------------------- +DEBUG: register call h passed in session scope +DEBUG: register call h passed in module scope +PASSED [ 60%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown h passed in session scope +DEBUG: register teardown h passed in module scope + +debugging.py::test_k +-------------------------------- live log setup -------------------------------- +DEBUG: check dependencies of test_k in module scope ... +DEBUG: ... test_b succeeded +DEBUG: register setup debugging.py::test_k passed in session scope +DEBUG: register setup test_k passed in module scope +-------------------------------- live log call --------------------------------- +DEBUG: register call debugging.py::test_k skipped in session scope +DEBUG: register call test_k skipped in module scope +SKIPPED (could not import 'fleet': No module named 'fleet') [ 64%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_k passed in session scope +DEBUG: register teardown test_k passed in module scope + +debugging.py::test_l[0] +-------------------------------- live log setup -------------------------------- +DEBUG: register setup debugging.py::test_l[0] passed in session scope +DEBUG: register setup test_l[0] passed in module scope +-------------------------------- live log call --------------------------------- +DEBUG: register call debugging.py::test_l[0] passed in session scope +DEBUG: register call test_l[0] passed in module scope +PASSED [ 68%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_l[0] passed in session scope +DEBUG: register teardown test_l[0] passed in module scope + +debugging.py::test_q[0] +-------------------------------- live log setup -------------------------------- +DEBUG: check dependencies of test_q[0] in module scope ... +DEBUG: ... test_p is unknown +INFO: skip test_q[0] because it depends on test_p +DEBUG: register setup debugging.py::test_q[0] skipped in session scope +DEBUG: register setup test_q[0] skipped in module scope +SKIPPED (test_q[0] depends on test_p) [ 72%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_q[0] passed in session scope +DEBUG: register teardown test_q[0] passed in module scope + +debugging.py::test_l[1] +-------------------------------- live log setup -------------------------------- +DEBUG: register setup debugging.py::test_l[1] passed in session scope +DEBUG: register setup test_l[1] passed in module scope +-------------------------------- live log call --------------------------------- +DEBUG: register call debugging.py::test_l[1] passed in session scope +DEBUG: register call test_l[1] passed in module scope +PASSED [ 76%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_l[1] passed in session scope +DEBUG: register teardown test_l[1] passed in module scope + +debugging.py::test_q[1] +-------------------------------- live log setup -------------------------------- +DEBUG: check dependencies of test_q[1] in module scope ... +DEBUG: ... test_p is unknown +INFO: skip test_q[1] because it depends on test_p +DEBUG: register setup debugging.py::test_q[1] skipped in session scope +DEBUG: register setup test_q[1] skipped in module scope +SKIPPED (test_q[1] depends on test_p) [ 80%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_q[1] passed in session scope +DEBUG: register teardown test_q[1] passed in module scope + +debugging.py::test_m +-------------------------------- live log setup -------------------------------- +DEBUG: check dependencies of test_m in session scope ... +DEBUG: ... test_b is unknown +INFO: skip test_m because it depends on test_b +DEBUG: register setup debugging.py::test_m skipped in session scope +DEBUG: register setup test_m skipped in module scope +SKIPPED (test_m depends on test_b) [ 84%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_m passed in session scope +DEBUG: register teardown test_m passed in module scope + +debugging.py::test_o +-------------------------------- live log setup -------------------------------- +DEBUG: check dependencies of test_o in module scope ... +DEBUG: ... test_h is unknown +INFO: skip test_o because it depends on test_h +DEBUG: register setup debugging.py::test_o skipped in session scope +DEBUG: register setup test_o skipped in module scope +SKIPPED (test_o depends on test_h) [ 88%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_o passed in session scope +DEBUG: register teardown test_o passed in module scope + +debugging.py::test_p +-------------------------------- live log setup -------------------------------- +DEBUG: register setup debugging.py::test_p passed in session scope +DEBUG: register setup test_p passed in module scope +-------------------------------- live log call --------------------------------- +DEBUG: register call debugging.py::test_p passed in session scope +DEBUG: register call test_p passed in module scope +PASSED [ 92%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_p passed in session scope +DEBUG: register teardown test_p passed in module scope + +debugging.py::test_r +-------------------------------- live log setup -------------------------------- +DEBUG: register setup r passed in session scope +DEBUG: register setup r passed in module scope +-------------------------------- live log call --------------------------------- +DEBUG: register call r passed in session scope +DEBUG: register call r passed in module scope +PASSED [ 96%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown r passed in session scope +DEBUG: register teardown r passed in module scope + +debugging.py::test_s +-------------------------------- live log setup -------------------------------- +DEBUG: check dependencies of test_s in module scope ... +DEBUG: ... test_l is unknown +INFO: skip test_s because it depends on test_l +DEBUG: register setup debugging.py::test_s skipped in session scope +DEBUG: register setup test_s skipped in module scope +SKIPPED (test_s depends on test_l) [100%] +------------------------------ live log teardown ------------------------------- +DEBUG: register teardown debugging.py::test_s passed in session scope +DEBUG: register teardown test_s passed in module scope + -=================== 2 passed, 2 skipped, 1 xfailed in 0.03s ==================== +================== 12 passed, 11 skipped, 2 xfailed in 0.09s =================== diff --git a/doc/examples/debugging-summary.out b/doc/examples/debugging-summary.out index aaeabb6..9bd860a 100644 --- a/doc/examples/debugging-summary.out +++ b/doc/examples/debugging-summary.out @@ -2,12 +2,21 @@ $ pytest -rs debugging.py ============================= test session starts ============================== platform linux -- Python 3.10.1, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 rootdir: /home/user -plugins: dependency-0.5.1 -collected 5 items +plugins: dependency-0.6.0 +collected 25 items -debugging.py x.s.s [100%] +debugging.py x.s.s.x....sss.s.s.sss..s [100%] =========================== short test summary info ============================ -SKIPPED [1] /usr/lib/python3.10/site-packages/pytest_dependency.py:103: test_c depends on test_a -SKIPPED [1] /usr/lib/python3.10/site-packages/pytest_dependency.py:103: test_e depends on test_c -=================== 2 passed, 2 skipped, 1 xfailed in 0.02s ==================== +SKIPPED [1] /usr/lib/python3.10/site-packages/pytest_dependency.py:101: test_c depends on test_a +SKIPPED [1] /usr/lib/python3.10/site-packages/pytest_dependency.py:101: test_e depends on test_c +SKIPPED [1] /usr/lib/python3.10/site-packages/pytest_dependency.py:101: test_multicolored depends on test_colors +SKIPPED [1] /usr/lib/python3.10/site-packages/pytest_dependency.py:101: test_alert depends on test_colors[Color.RED] +SKIPPED [1] /usr/lib/python3.10/site-packages/pytest_dependency.py:101: test_g depends on test_f +SKIPPED [1] debugging.py:15: could not import 'fleet': No module named 'fleet' +SKIPPED [1] /usr/lib/python3.10/site-packages/pytest_dependency.py:101: test_q[0] depends on test_p +SKIPPED [1] /usr/lib/python3.10/site-packages/pytest_dependency.py:101: test_q[1] depends on test_p +SKIPPED [1] /usr/lib/python3.10/site-packages/pytest_dependency.py:101: test_m depends on test_b +SKIPPED [1] /usr/lib/python3.10/site-packages/pytest_dependency.py:101: test_o depends on test_h +SKIPPED [1] /usr/lib/python3.10/site-packages/pytest_dependency.py:101: test_s depends on test_l +================== 12 passed, 11 skipped, 2 xfailed in 0.05s =================== diff --git a/doc/examples/debugging-verbose.out b/doc/examples/debugging-verbose.out index 780eee4..2324b98 100644 --- a/doc/examples/debugging-verbose.out +++ b/doc/examples/debugging-verbose.out @@ -3,13 +3,33 @@ $ pytest --verbose debugging.py platform linux -- Python 3.10.1, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 -- /usr/bin/python3 cachedir: .pytest_cache rootdir: /home/user -plugins: dependency-0.5.1 -collecting ... collected 5 items +plugins: dependency-0.6.0 +collecting ... collected 25 items -debugging.py::test_a XFAIL (deliberate fail) [ 20%] -debugging.py::test_b PASSED [ 40%] -debugging.py::test_c SKIPPED (test_c depends on test_a) [ 60%] -debugging.py::test_d PASSED [ 80%] -debugging.py::test_e SKIPPED (test_e depends on test_c) [100%] +debugging.py::test_a XFAIL (deliberate fail) [ 4%] +debugging.py::test_b PASSED [ 8%] +debugging.py::test_c SKIPPED (test_c depends on test_a) [ 12%] +debugging.py::test_d PASSED [ 16%] +debugging.py::test_e SKIPPED (test_e depends on test_c) [ 20%] +debugging.py::TestClass::test_a PASSED [ 24%] +debugging.py::TestClass::test_b XFAIL (deliberate fail) [ 28%] +debugging.py::TestClass::test_c PASSED [ 32%] +debugging.py::test_colors[RED] PASSED [ 36%] +debugging.py::test_colors[GREEN] PASSED [ 40%] +debugging.py::test_colors[BLUE] PASSED [ 44%] +debugging.py::test_multicolored SKIPPED (test_multicolored depends o...) [ 48%] +debugging.py::test_alert SKIPPED (test_alert depends on test_colors[...) [ 52%] +debugging.py::test_g SKIPPED (test_g depends on test_f) [ 56%] +debugging.py::test_h PASSED [ 60%] +debugging.py::test_k SKIPPED (could not import 'fleet': No module na...) [ 64%] +debugging.py::test_l[0] PASSED [ 68%] +debugging.py::test_q[0] SKIPPED (test_q[0] depends on test_p) [ 72%] +debugging.py::test_l[1] PASSED [ 76%] +debugging.py::test_q[1] SKIPPED (test_q[1] depends on test_p) [ 80%] +debugging.py::test_m SKIPPED (test_m depends on test_b) [ 84%] +debugging.py::test_o SKIPPED (test_o depends on test_h) [ 88%] +debugging.py::test_p PASSED [ 92%] +debugging.py::test_r PASSED [ 96%] +debugging.py::test_s SKIPPED (test_s depends on test_l) [100%] -=================== 2 passed, 2 skipped, 1 xfailed in 0.03s ==================== +================== 12 passed, 11 skipped, 2 xfailed in 0.06s =================== diff --git a/doc/examples/debugging.py b/doc/examples/debugging.py index af05dce..1627015 100644 --- a/doc/examples/debugging.py +++ b/doc/examples/debugging.py @@ -1,5 +1,25 @@ +from enum import Enum import pytest + +class Color(Enum): + RED = 1 + GREEN = 2 + BLUE = 3 + + def __str__(self): + return self.name + + +def get_starship(name): + fleet = pytest.importorskip("fleet") + return fleet.get_ship(name) + + +@pytest.fixture(scope="module", params=range(2)) +def prepenv(request): + pass + @pytest.mark.dependency() @pytest.mark.xfail(reason="deliberate fail") def test_a(): @@ -20,3 +40,74 @@ def test_d(): @pytest.mark.dependency(depends=["test_b", "test_c"]) def test_e(): pass + + +class TestClass(object): + + @pytest.mark.dependency() + def test_a(self): + pass + + @pytest.mark.dependency() + @pytest.mark.xfail(reason="deliberate fail") + def test_b(self): + assert False + + @pytest.mark.dependency(depends=["test_b"]) + def test_c(self): + pass + + +@pytest.mark.dependency() +@pytest.mark.parametrize("c", [ Color.RED, Color.GREEN, Color.BLUE, ]) +def test_colors(c): + pass + +@pytest.mark.dependency(depends=["test_colors"]) +def test_multicolored(): + pass + +@pytest.mark.dependency(depends=["test_colors[Color.RED]"]) +def test_alert(): + pass + +@pytest.mark.dependency(depends=["test_f"]) +def test_g(): + pass + +@pytest.mark.dependency(name="h") +def test_h(): + pass + +@pytest.mark.dependency(depends=["test_b"]) +def test_k(): + s = get_starship("NCC-1701") + +@pytest.mark.dependency() +def test_l(prepenv): + pass + +@pytest.mark.dependency(depends=["test_b"], scope='session') +def test_m(): + pass + +@pytest.mark.dependency(depends=["test_h"]) +def test_o(): + pass + +@pytest.mark.dependency() +def test_p(): + pass + +@pytest.mark.dependency(depends=["test_p"]) +def test_q(prepenv): + pass + +@pytest.mark.dependency(depends=["test_a"]) +@pytest.mark.dependency(name="r") +def test_r(): + pass + +@pytest.mark.dependency(depends=["test_l"]) +def test_s(): + pass From 10f9e61e43baff6bddc293952aceba0cad072eb0 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Tue, 28 Dec 2021 18:42:41 +0100 Subject: [PATCH 39/71] Add detailed discussion of the example in the debugging guide --- doc/src/debugging.rst | 131 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 3 deletions(-) diff --git a/doc/src/debugging.rst b/doc/src/debugging.rst index 495e351..6f70676 100644 --- a/doc/src/debugging.rst +++ b/doc/src/debugging.rst @@ -7,14 +7,49 @@ pytest-dependency does not seem to behave as expected. Example ------- -Throughout this debugging guide, we will consider the following -example: +We consider the following example in this guide: .. literalinclude:: ../examples/debugging.py +This example contains several cases where the presumably intended +behavior of the code differs from what happens in practice. We will +show below how diagnostic tools in pytest may be used to unravel the +discrepancies. The results that may (or may not) be surprising +include: + ++ The test method `test_c` in class `TestClass` depending on `test_b` + is run, although the test method `test_b` fails. + ++ All instances of `test_colors` succeed. Yet `test_multicolored` + that only depends on `test_colors` is skipped. + ++ Similarly `test_alert` depending only on `test_colors[Color.RED]` is + skipped, although `test_colors` with the parameter value `Color.RED` + succeeds. + ++ `test_k` depending only on `test_b` is skipped, although `test_b` + succeeds. + ++ Same with `test_m` depending only on `test_b` is skipped. + ++ `test_o` depending only on `test_h` is skipped, although `test_h` + succeeds. + ++ `test_q` depending only on `test_p` is skipped, although `test_p` + succeeds. + ++ `test_r` is run, although `test_a` fails. + ++ `test_s` depending only on `test_l` is skipped, although `test_l` + succeeds. + Diagnostic tools ---------------- +There are different ways to request diagnostic output from pytest. We +will discuss how they may be used to better understand the behavior of +pytest-dependency. + pytest summary .............. @@ -23,6 +58,12 @@ skipped tests using the ``-rs`` `command line option`__: .. literalinclude:: ../examples/debugging-summary.out +This summary indicates if a test has been skipped by pytest-dependency +in the first place. In the present example, the summary hints that +`test_k` has been skipped due to another reason, unrelated to +pytest-dependency. If the test has been skipped by pytest-dependency, +the summary displays the name of the missing dependency. + .. __: https://docs.pytest.org/en/stable/usage.html#detailed-summary-report Verbose pytest output @@ -33,14 +74,98 @@ you call pytest with the ``--verbose`` command line option: .. literalinclude:: ../examples/debugging-verbose.out +The verbose listing is particular useful, because it shows the pytest +node id for each test, which is not always obvious. As explained in +Section :ref:`names`, this node id is the basis to form the default +test name that need to be used to reference the test in the +dependencies. + +From this list we can understand why `test_multicolored` has been +skipped: it depends on `test_colors`. But `test_colors` is +parametrized and thus the parameter value is included in the node id. +As a result, a dependency by the name `test_colors` can not be found. +The same thing happens in the case of `test_s`: it depends on +`test_l`, but the latter uses a parametrized fixture, so it indirectly +takes a parameter value and that value must be included in the +reference for the dependency. + +In the case of `test_alert`, the parameter value is included in the +dependency `test_colors[Color.RED]`. But in the node id as displayed +in the verbose list, that test appears as `test_colors[RED]`. Note +that `class Color` overrides the string representation operator and +that affects how the parameter value appears in the node id in this +case. + +The verbose list also displays the execution order of the tests. In +the present example, this order differs from the order in the source +code. That is the reason why both instances of `test_q` are skipped: +they are executed before the dependency `test_p`. So the outcome of +the latter is yet unknown at the moment that the dependency is +checked. + Logging ....... pytest-dependency emits log messages when registering test results and when checking dependencies for a test. You can request these log messages to be displayed at runtime using `log command line options`__ -in the pytest call: +in the pytest call. Beware that this may produce a large amount of +output, even for medium size test suites. We will present only a few +fragments of the output here. Consider the start of that output, +covering the first test `test_a`: + +.. literalinclude:: ../examples/debugging-logging.out + :end-before: debugging.py::test_b + +It is shown how the test outcome for each of the three test phases +(setup, call, and teardown) is registered in pytest-dependency. It is +also shown which name is used to register the test outcome depending +on the scope. + +Considering the relevant fragments of the output, we can check why +`TestClass::test_c` is not skipped: + +.. literalinclude:: ../examples/debugging-logging.out + :lines: 20-31,86-116 + +The dependency `test_b` is checked in module scope. If that +dependency was meant to reference the method of the same class, it +would either need to be referenced as `test_b` in class scope or as +`TestClass::test_b` in module scope or as +`debugging.py::TestClass::test_b` in session scope. The way it is +formulated in the example, it actually references the test function +`test_b`, which succeeds. + +A similar case is `test_m`: .. literalinclude:: ../examples/debugging-logging.out + :lines: 20-31,264-274 + +The dependency `test_b` is checked in session scope. There is no test +that matches this name. If that dependency was mean to reference the +test function `test_b` in the example, it would either need to be +referenced as `debugging.py::test_b` in session scope or as `test_b` +in module scope. + +A slightly different situation is given in the case of `test_o`: + +.. literalinclude:: ../examples/debugging-logging.out + :lines: 190-201,276-286 + +In the :func:`pytest.mark.dependency` marker for `test_h` in the +example, the name is overridden as `h`. The outcome of that test is +registered using that name. It can thus not be found by the name +`test_h`. + +Considering the case of `test_r`: + +.. literalinclude:: ../examples/debugging-logging.out + :lines: 300-310 + +That test has no dependencies. The error in the example is that the +:func:`pytest.mark.dependency` marker is applied twice to the test. +That doesn't work in pytest, only the last invocation is effective. +As a result, the second invocation setting a name, effectively clears +the dependency list that was set in the first invocation. .. __: https://docs.pytest.org/en/stable/logging.html#live-logs From 9bf329bd1f5108d7069c981f874d2ebd1101f31f Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Wed, 29 Dec 2021 14:47:43 +0100 Subject: [PATCH 40/71] Add test for the debugging example --- tests/test_09_examples_debugging.py | 44 +++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/test_09_examples_debugging.py diff --git a/tests/test_09_examples_debugging.py b/tests/test_09_examples_debugging.py new file mode 100644 index 0000000..8809a50 --- /dev/null +++ b/tests/test_09_examples_debugging.py @@ -0,0 +1,44 @@ +"""Test the included examples. +""" + +import pytest +from conftest import get_example + + +def test_debugging(ctestdir): + """Debugging example + """ + with get_example("debugging.py").open("rt") as f: + ctestdir.makepyfile(f.read()) + result = ctestdir.runpytest("--verbose") + try: + result.assert_outcomes(passed=12, skipped=11, failed=0, xfailed=2) + except TypeError: + result.assert_outcomes(passed=12, skipped=11, failed=0) + result.stdout.re_match_lines(r""" + .*::test_a (?:XFAIL(?:\s+\(.*\))?|xfail) + .*::test_b PASSED + .*::test_c SKIPPED(?:\s+\(.*\))? + .*::test_d PASSED + .*::test_e SKIPPED(?:\s+\(.*\))? + .*::TestClass::test_a PASSED + .*::TestClass::test_b (?:XFAIL(?:\s+\(.*\))?|xfail) + .*::TestClass::test_c PASSED + .*::test_colors\[RED\] PASSED + .*::test_colors\[GREEN\] PASSED + .*::test_colors\[BLUE\] PASSED + .*::test_multicolored SKIPPED(?:\s+\(.*\))? + .*::test_alert SKIPPED(?:\s+\(.*\))? + .*::test_g SKIPPED(?:\s+\(.*\))? + .*::test_h PASSED + .*::test_k SKIPPED(?:\s+\(.*\))? + .*::test_l\[0\] PASSED + .*::test_q\[0\] SKIPPED(?:\s+\(.*\))? + .*::test_l\[1\] PASSED + .*::test_q\[1\] SKIPPED(?:\s+\(.*\))? + .*::test_m SKIPPED(?:\s+\(.*\))? + .*::test_o SKIPPED(?:\s+\(.*\))? + .*::test_p PASSED + .*::test_r PASSED + .*::test_s SKIPPED(?:\s+\(.*\))? + """) From b9134038c6fe44f472c0063ac262dda8138745e1 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Fri, 31 Dec 2021 21:27:22 +0100 Subject: [PATCH 41/71] Skip test_debugging in Python 2.7 --- tests/test_09_examples_debugging.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_09_examples_debugging.py b/tests/test_09_examples_debugging.py index 8809a50..f81340d 100644 --- a/tests/test_09_examples_debugging.py +++ b/tests/test_09_examples_debugging.py @@ -8,6 +8,10 @@ def test_debugging(ctestdir): """Debugging example """ + # The debugging example requires the enum module which is has been + # added to the standard kibrary in Python 3.4. Skip this test if + # the module is not available. + _ = pytest.importorskip("enum") with get_example("debugging.py").open("rt") as f: ctestdir.makepyfile(f.read()) result = ctestdir.runpytest("--verbose") From 1a1cfda235f46c25c2b784556e23c94dbd3566b4 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Fri, 31 Dec 2021 22:02:14 +0100 Subject: [PATCH 42/71] Remove spurious white space --- doc/examples/or_dependency.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/examples/or_dependency.py b/doc/examples/or_dependency.py index 99b288b..803e2a7 100644 --- a/doc/examples/or_dependency.py +++ b/doc/examples/or_dependency.py @@ -33,20 +33,20 @@ def test_bx(): @pytest.mark.dependency() def test_c(request): - depends_or(request, ["test_ax", "test_bx"]) + depends_or(request, ["test_ax", "test_bx"]) pass @pytest.mark.dependency() def test_d(request): - depends_or(request, ["test_ax", "test_bp"]) + depends_or(request, ["test_ax", "test_bp"]) pass @pytest.mark.dependency() def test_e(request): - depends_or(request, ["test_ap", "test_bx"]) + depends_or(request, ["test_ap", "test_bx"]) pass @pytest.mark.dependency() def test_f(request): - depends_or(request, ["test_ap", "test_bp"]) + depends_or(request, ["test_ap", "test_bp"]) pass From 87c06c58390786431fbbcc4e20f3c06c1d147163 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Fri, 31 Dec 2021 23:36:13 +0100 Subject: [PATCH 43/71] Typo in comment --- tests/test_09_examples_debugging.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_09_examples_debugging.py b/tests/test_09_examples_debugging.py index f81340d..d27f447 100644 --- a/tests/test_09_examples_debugging.py +++ b/tests/test_09_examples_debugging.py @@ -9,7 +9,7 @@ def test_debugging(ctestdir): """Debugging example """ # The debugging example requires the enum module which is has been - # added to the standard kibrary in Python 3.4. Skip this test if + # added to the standard library in Python 3.4. Skip this test if # the module is not available. _ = pytest.importorskip("enum") with get_example("debugging.py").open("rt") as f: From c77ae89a306288ecf83a123b2539356c718ee86b Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Fri, 31 Dec 2021 23:42:19 +0100 Subject: [PATCH 44/71] Require enum34 for the tests with Python 2.7 --- .github/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/requirements.txt b/.github/requirements.txt index 3b3dd3d..71f8999 100644 --- a/.github/requirements.txt +++ b/.github/requirements.txt @@ -1,3 +1,4 @@ +enum34 ; python_version == '2.7' pathlib ; python_version == '2.7' pytest >=3.7.0 setuptools_scm From ebb19e2aff9d77b8f0ab8af02c34cd4cc6b74dc9 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 8 Jan 2022 18:09:11 +0100 Subject: [PATCH 45/71] Add a simple example of a parametrized test, ref. #43 --- tests/test_03_param.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/test_03_param.py b/tests/test_03_param.py index a7a31b0..62cb5ba 100644 --- a/tests/test_03_param.py +++ b/tests/test_03_param.py @@ -4,6 +4,38 @@ import pytest +def test_simple_params(ctestdir): + """Simple test for a dependency on a parametrized test. + + This example has been used in the discussion of PR #43. + """ + ctestdir.makepyfile(""" + import pytest + + _md = pytest.mark.dependency + + @pytest.mark.parametrize("x", [ 0, 1 ]) + @pytest.mark.dependency() + def test_a(x): + assert x == 0 + + @pytest.mark.parametrize("x", [ + pytest.param(0, marks=_md(depends=["test_a[0]"])), + pytest.param(1, marks=_md(depends=["test_a[1]"])), + ]) + def test_b(x): + pass + """) + result = ctestdir.runpytest("--verbose") + result.assert_outcomes(passed=2, skipped=1, failed=1) + result.stdout.re_match_lines(r""" + .*::test_a\[0\] PASSED + .*::test_a\[1\] FAILED + .*::test_b\[0\] PASSED + .*::test_b\[1\] SKIPPED(?:\s+\(.*\))? + """) + + def test_multiple(ctestdir): ctestdir.makepyfile(""" import pytest From e9b55fa24784f75a76c58ad63aa361ae1bbf6646 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 9 Jan 2022 18:38:50 +0100 Subject: [PATCH 46/71] Add a hint on pytest-order to the install instructions --- doc/src/install.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/src/install.rst b/doc/src/install.rst index 8b9f744..e1a417e 100644 --- a/doc/src/install.rst +++ b/doc/src/install.rst @@ -14,7 +14,14 @@ System requirements Interaction with other packages ------------------------------- -pytest-xdist +`pytest-order`_ + pytest-dependency is based on the assumption that dependencies are + run before the test that depends on them. If this assumption is + not satisfied in the default execution order in pytest, you may + want to have a look on pytest-order. It implements reordering of + tests and supports taking the dependencies into account. + +`pytest-xdist`_ pytest-xdist features test run parallelization, e.g. distributing tests over separate processes that run in parallel. This is based on the assumption that the tests can be run independent of each @@ -58,3 +65,5 @@ version from PyPI, see above. .. _setuptools: http://pypi.python.org/pypi/setuptools/ .. _pytest: http://pytest.org/ +.. _pytest-order: https://github.com/pytest-dev/pytest-order +.. _pytest-xdist: https://github.com/pytest-dev/pytest-xdist From 27b431e54c2b10a7dc8022f27f18c92a2d674ce8 Mon Sep 17 00:00:00 2001 From: Kian-Meng Ang Date: Thu, 17 Feb 2022 21:32:13 +0800 Subject: [PATCH 47/71] Fix typos --- doc/src/advanced.rst | 2 +- doc/src/scope.rst | 2 +- doc/src/usage.rst | 6 +++--- tests/test_03_class.py | 2 +- tests/test_03_scope.py | 4 ++-- tests/test_09_examples_scope.py | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/src/advanced.rst b/doc/src/advanced.rst index f5ef02a..9af47d6 100644 --- a/doc/src/advanced.rst +++ b/doc/src/advanced.rst @@ -18,7 +18,7 @@ Consider the following example test module: In principle, this example works the very same way as the basic example for :ref:`usage-parametrized`. The only difference is that -the lists of paramters are dynamically compiled beforehand. The test +the lists of parameters are dynamically compiled beforehand. The test for child `l` deliberately fails, just to show the effect. As a consequence, the test for its parent `d` will be skipped. diff --git a/doc/src/scope.rst b/doc/src/scope.rst index 1e78a29..728529d 100644 --- a/doc/src/scope.rst +++ b/doc/src/scope.rst @@ -16,7 +16,7 @@ or `'class'`. versions, all dependencies were implicitly in module scope. -Explicitely specifying the scope +Explicitly specifying the scope -------------------------------- The default value for the `scope` argument is `'module'`. Thus, the diff --git a/doc/src/usage.rst b/doc/src/usage.rst index be97ef2..ddbb03e 100644 --- a/doc/src/usage.rst +++ b/doc/src/usage.rst @@ -21,7 +21,7 @@ test, we will get the following result: .. literalinclude:: ../examples/basic.out The first test has deliberately been set to fail to illustrate the -effect. We will get the following resuts: +effect. We will get the following results: `test_a` deliberately fails. @@ -50,7 +50,7 @@ see Section :ref:`names` for details. In some cases, it's not easy to predict the names of the node ids. For this reason, the name of the tests can be overridden by an explicit `name` argument to the marker. The names must be unique. The following example works exactly as the -last one, only the test names are explicitely set: +last one, only the test names are explicitly set: .. literalinclude:: ../examples/named.py @@ -94,7 +94,7 @@ Marking dependencies at runtime ------------------------------- Sometimes, dependencies of test instances are too complicated to be -formulated explicitely beforehand using the +formulated explicitly beforehand using the :func:`pytest.mark.dependency` marker. It may be easier to compile the list of dependencies of a test at run time. In such cases, the function :func:`pytest_dependency.depends` comes handy. Consider the diff --git a/tests/test_03_class.py b/tests/test_03_class.py index 168b634..64bdb6d 100644 --- a/tests/test_03_class.py +++ b/tests/test_03_class.py @@ -47,7 +47,7 @@ def test_e(self): def test_class_simple_named(ctestdir): """Mostly the same as test_class_simple(), but name the test methods - now explicitely. + now explicitly. """ ctestdir.makepyfile(""" import pytest diff --git a/tests/test_03_scope.py b/tests/test_03_scope.py index 58aad89..17efe82 100644 --- a/tests/test_03_scope.py +++ b/tests/test_03_scope.py @@ -5,7 +5,7 @@ def test_scope_module(ctestdir): - """One single module, module scope is explicitely set in the + """One single module, module scope is explicitly set in the pytest.mark.dependency() marker. """ ctestdir.makepyfile(""" @@ -379,7 +379,7 @@ def test_o(self): """) def test_scope_named(ctestdir): - """Explicitely named tests are always referenced by that name, + """Explicitly named tests are always referenced by that name, regardless of the scope. """ ctestdir.makepyfile(""" diff --git a/tests/test_09_examples_scope.py b/tests/test_09_examples_scope.py index 98a2400..7975e5a 100644 --- a/tests/test_09_examples_scope.py +++ b/tests/test_09_examples_scope.py @@ -7,7 +7,7 @@ def test_scope_module(ctestdir): - """Explicitely specifying the scope + """Explicitly specifying the scope """ with get_example("scope_module.py").open("rt") as f: ctestdir.makepyfile(f.read()) From 4d6ac1c616ec1fe09438f8ab32dc12735831dddc Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Thu, 17 Feb 2022 18:05:09 +0100 Subject: [PATCH 48/71] Adapt underline rst-markup --- doc/src/scope.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/scope.rst b/doc/src/scope.rst index 728529d..5d71802 100644 --- a/doc/src/scope.rst +++ b/doc/src/scope.rst @@ -17,7 +17,7 @@ or `'class'`. Explicitly specifying the scope --------------------------------- +------------------------------- The default value for the `scope` argument is `'module'`. Thus, the very first example from Section :ref:`usage-basic` could also be From b40cda1efd8ee4c71bb3d640a22fe38b477bb132 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 30 Dec 2023 17:04:29 +0100 Subject: [PATCH 49/71] - General review of the setup script - Formally drop support for Python 2 --- README.rst | 2 +- setup.py | 146 +++++++++++++++++++++++++++-------------------------- 2 files changed, 76 insertions(+), 72 deletions(-) diff --git a/README.rst b/README.rst index 47bb24a..67192e4 100644 --- a/README.rst +++ b/README.rst @@ -31,7 +31,7 @@ The latest release version can be found `at PyPI`__. System requirements ------------------- -+ Python 2.7 or 3.4 and newer. ++ Python 3.4 and newer. + `setuptools`_. + `pytest`_ 3.7.0 or newer. diff --git a/setup.py b/setup.py index f62b3ac..fdcb4f8 100755 --- a/setup.py +++ b/setup.py @@ -1,4 +1,3 @@ -#! /usr/bin/python """pytest-dependency - Manage dependencies of tests This pytest plugin manages dependencies of tests. It allows to mark @@ -6,17 +5,16 @@ skipped if any of the dependencies did fail or has been skipped. """ -import os -import os.path -import re -import stat -import string import setuptools -from distutils.cmd import Command as du_cmd -import distutils.command.sdist -import distutils.log from setuptools import setup import setuptools.command.build_py +import distutils.command.sdist +import distutils.file_util +from distutils import log +import os +from pathlib import Path +from stat import ST_ATIME, ST_MTIME, ST_MODE, S_IMODE +import string try: import setuptools_scm version = setuptools_scm.get_version() @@ -27,10 +25,10 @@ with open(".version", "rt") as f: version = f.read() except (OSError, IOError): - distutils.log.warn("warning: cannot determine version number") + log.warn("warning: cannot determine version number") version = "UNKNOWN" -doc_string = __doc__ +docstring = __doc__ class copy_file_mixin: """Distutils copy_file() mixin. @@ -40,34 +38,36 @@ class copy_file_mixin: hierarchy. """ Subst_srcs = {"src/pytest_dependency.py"} - Subst = {'DOC': doc_string, 'VERSION': version} - def copy_file(self, infile, outfile, preserve_mode=1, preserve_times=1, - link=None, level=1): + Subst = {'DOC': docstring, 'VERSION': version} + def copy_file(self, infile, outfile, + preserve_mode=1, preserve_times=1, link=None, level=1): if infile in self.Subst_srcs: - fstat = os.stat(infile) - if os.path.basename(outfile) == os.path.basename(infile): - distutils.log.info("copying (with substitutions) %s -> %s", - infile, os.path.dirname(outfile)) + infile = Path(infile) + outfile = Path(outfile) + if outfile.name == infile.name: + log.info("copying (with substitutions) %s -> %s", + infile, outfile.parent) else: - distutils.log.info("copying (with substitutions) %s -> %s", - infile, outfile) + log.info("copying (with substitutions) %s -> %s", + infile, outfile) if not self.dry_run: - if os.path.exists(outfile): - os.unlink(outfile) - with open(infile, "rt") as sf, open(outfile, "wt") as df: + st = infile.stat() + try: + outfile.unlink() + except FileNotFoundError: + pass + with infile.open("rt") as sf, outfile.open("wt") as df: df.write(string.Template(sf.read()).substitute(self.Subst)) + if preserve_times: + os.utime(str(outfile), (st[ST_ATIME], st[ST_MTIME])) if preserve_mode: - os.chmod(outfile, stat.S_IMODE(fstat[stat.ST_MODE])) - return (outfile, 1) + outfile.chmod(S_IMODE(st[ST_MODE])) + return (str(outfile), 1) else: - # Note: can't use super() with Python 2. - return du_cmd.copy_file(self, infile, outfile, - preserve_mode=preserve_mode, - preserve_times=preserve_times, - link=link, level=level) - -class build_py(copy_file_mixin, setuptools.command.build_py.build_py): - pass + return distutils.file_util.copy_file(infile, outfile, + preserve_mode, preserve_times, + not self.force, link, + dry_run=self.dry_run) # Note: Do not use setuptools for making the source distribution, # rather use the good old distutils instead. @@ -75,46 +75,50 @@ class build_py(copy_file_mixin, setuptools.command.build_py.build_py): class sdist(copy_file_mixin, distutils.command.sdist.sdist): pass +class build_py(copy_file_mixin, setuptools.command.build_py.build_py): + pass + +with Path("README.rst").open("rt", encoding="utf8") as f: + readme = f.read() + setup( - name='pytest-dependency', - version=version, - description='Manage dependencies of tests', - author='Rolf Krahl', - author_email='rolf@rotkraut.de', - maintainer='Rolf Krahl', - maintainer_email='rolf@rotkraut.de', - url='https://github.com/RKrahl/pytest-dependency', - license='Apache Software License 2.0', - long_description=doc_string, - project_urls={ - 'Documentation': 'https://pytest-dependency.readthedocs.io/', - 'Source Code': 'https://github.com/RKrahl/pytest-dependency', - }, - package_dir = {'': 'src'}, - py_modules=['pytest_dependency'], - install_requires=['pytest >= 3.7.0'], - classifiers=[ - 'Development Status :: 4 - Beta', - 'Framework :: Pytest', - 'Intended Audience :: Developers', - 'Topic :: Software Development :: Testing', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Operating System :: OS Independent', - 'License :: OSI Approved :: Apache Software License', + name = "pytest-dependency", + version = version, + description = "Manage dependencies of tests", + long_description = readme, + long_description_content_type = "text/x-rst", + url = "https://github.com/RKrahl/pytest-dependency", + author = "Rolf Krahl", + author_email = "rolf@rotkraut.de", + license = "Apache-2.0", + classifiers = [ + "Development Status :: 4 - Beta", + "Framework :: Pytest", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Topic :: Software Development :: Testing", ], - entry_points={ - 'pytest11': [ - 'dependency = pytest_dependency', + project_urls = dict( + Documentation="https://pytest-dependency.readthedocs.io/", + Source="https://github.com/RKrahl/pytest-dependency", + Download="https://github.com/RKrahl/pytest-dependency/releases/latest", + ), + package_dir = {"": "src"}, + python_requires = ">=3.4", + py_modules = ["pytest_dependency"], + install_requires = ["setuptools", "pytest >= 3.7.0"], + entry_points = { + "pytest11": [ + "dependency = pytest_dependency", ], }, cmdclass = {'build_py': build_py, 'sdist': sdist}, From 8cc61f7c4f2ebf06880e4e3b185be496f9f8614f Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 30 Dec 2023 17:29:33 +0100 Subject: [PATCH 50/71] Create a _meta.py file rather than .version --- .gitignore | 2 +- MANIFEST.in | 2 +- Makefile | 8 ++++++-- setup.py | 37 +++++++++++++++++++++++++++++-------- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 9fb4879..211b44c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,8 @@ *~ .cache/ __pycache__/ -/.version /MANIFEST +/_meta.py /build/ /dist/ /doc/doctest/ diff --git a/MANIFEST.in b/MANIFEST.in index e5caef0..f42290a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,7 @@ -include .version include LICENSE.txt include MANIFEST.in include README.rst +include _meta.py include doc/examples/*.py include tests/conftest.py include tests/pytest.ini diff --git a/Makefile b/Makefile index e341c12..08db401 100644 --- a/Makefile +++ b/Makefile @@ -19,12 +19,16 @@ clean: rm -rf build distclean: clean + rm -f MANIFEST _meta.py rm -rf .cache tests/.cache .pytest_cache tests/.pytest_cache rm -f *.pyc tests/*.pyc rm -rf __pycache__ tests/__pycache__ - rm -f MANIFEST .version rm -rf dist rm -rf pytest_dependency.egg-info $(MAKE) -C doc distclean -.PHONY: build test sdist doc-html clean distclean +meta: + $(PYTHON) setup.py meta + + +.PHONY: build test sdist doc-html clean distclean meta diff --git a/setup.py b/setup.py index fdcb4f8..f6026d0 100755 --- a/setup.py +++ b/setup.py @@ -18,13 +18,10 @@ try: import setuptools_scm version = setuptools_scm.get_version() - with open(".version", "wt") as f: - f.write(version) except (ImportError, LookupError): try: - with open(".version", "rt") as f: - version = f.read() - except (OSError, IOError): + from _meta import version + except ImportError: log.warn("warning: cannot determine version number") version = "UNKNOWN" @@ -69,14 +66,38 @@ def copy_file(self, infile, outfile, not self.force, link, dry_run=self.dry_run) +class meta(setuptools.Command): + description = "generate meta files" + user_options = [] + meta_template = ''' +version = "%(version)s" +''' + def initialize_options(self): + pass + def finalize_options(self): + pass + def run(self): + version = self.distribution.get_version() + log.info("version: %s", version) + values = { + 'version': version, + } + with Path("_meta.py").open("wt") as f: + print(self.meta_template % values, file=f) + # Note: Do not use setuptools for making the source distribution, # rather use the good old distutils instead. # Rationale: https://rhodesmill.org/brandon/2009/eby-magic/ class sdist(copy_file_mixin, distutils.command.sdist.sdist): - pass + def run(self): + self.run_command('meta') + super().run() class build_py(copy_file_mixin, setuptools.command.build_py.build_py): - pass + def run(self): + self.run_command('meta') + super().run() + with Path("README.rst").open("rt", encoding="utf8") as f: readme = f.read() @@ -121,5 +142,5 @@ class build_py(copy_file_mixin, setuptools.command.build_py.build_py): "dependency = pytest_dependency", ], }, - cmdclass = {'build_py': build_py, 'sdist': sdist}, + cmdclass = dict(build_py=build_py, sdist=sdist, meta=meta), ) From a43bc63779eb9ecc190c62dddb4c6e177228efbe Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 30 Dec 2023 17:51:06 +0100 Subject: [PATCH 51/71] Use distutils-pytest to run the test suite --- .github/requirements.txt | 1 + Makefile | 4 ++-- README.rst | 7 ++++++- setup.py | 7 ++++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/requirements.txt b/.github/requirements.txt index 3b3dd3d..28a5564 100644 --- a/.github/requirements.txt +++ b/.github/requirements.txt @@ -1,3 +1,4 @@ +distutils-pytest pathlib ; python_version == '2.7' pytest >=3.7.0 setuptools_scm diff --git a/Makefile b/Makefile index 08db401..1c92a9d 100644 --- a/Makefile +++ b/Makefile @@ -5,8 +5,8 @@ BUILDLIB = $(CURDIR)/build/lib build: $(PYTHON) setup.py build -test: build - PYTHONPATH=$(BUILDLIB) $(PYTHON) -m pytest tests +test: + $(PYTHON) setup.py test sdist: $(PYTHON) setup.py sdist diff --git a/README.rst b/README.rst index 67192e4..6c28f67 100644 --- a/README.rst +++ b/README.rst @@ -45,6 +45,10 @@ Optional library packages: package is only needed to build out of the plain development source tree as cloned from GitHub. ++ `distutils-pytest`_ >= 0.2 + + Only needed to run the test suite. + Installation ------------ @@ -57,7 +61,7 @@ Installation 3. Test (optional):: - $ PYTHONPATH=build/lib python -m pytest tests + $ python setup.py test 4. Install:: @@ -102,4 +106,5 @@ permissions and limitations under the License. .. _setuptools: http://pypi.python.org/pypi/setuptools/ .. _pytest: http://pytest.org/ .. _setuptools_scm: https://github.com/pypa/setuptools_scm/ +.. _distutils-pytest: https://github.com/RKrahl/distutils-pytest .. _Read the Docs site: https://pytest-dependency.readthedocs.io/ diff --git a/setup.py b/setup.py index f6026d0..9ac98cb 100755 --- a/setup.py +++ b/setup.py @@ -15,6 +15,11 @@ from pathlib import Path from stat import ST_ATIME, ST_MTIME, ST_MODE, S_IMODE import string +try: + import distutils_pytest + cmdclass = distutils_pytest.cmdclass +except (ImportError, AttributeError): + cmdclass = dict() try: import setuptools_scm version = setuptools_scm.get_version() @@ -142,5 +147,5 @@ def run(self): "dependency = pytest_dependency", ], }, - cmdclass = dict(build_py=build_py, sdist=sdist, meta=meta), + cmdclass = dict(cmdclass, build_py=build_py, sdist=sdist, meta=meta), ) From a736b9e0930c32458ed552ad6254abffb51b8e10 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 30 Dec 2023 19:13:33 +0100 Subject: [PATCH 52/71] Drop setuptools_scm in favour of git-props --- .github/requirements.txt | 3 ++- README.rst | 14 +++++++------- setup.py | 14 +++++++++----- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/.github/requirements.txt b/.github/requirements.txt index 28a5564..926a307 100644 --- a/.github/requirements.txt +++ b/.github/requirements.txt @@ -1,4 +1,5 @@ distutils-pytest +git-props pathlib ; python_version == '2.7' pytest >=3.7.0 -setuptools_scm +setuptools diff --git a/README.rst b/README.rst index 6c28f67..40a5472 100644 --- a/README.rst +++ b/README.rst @@ -37,13 +37,13 @@ System requirements Optional library packages: -+ `setuptools_scm`_ ++ `git-props`_ - The version number is managed using this package. All source - distributions add a static text file with the version number and - fall back using that if `setuptools_scm` is not available. So this - package is only needed to build out of the plain development source - tree as cloned from GitHub. + This package is used to extract some metadata such as the version + number out of git, the version control system. All releases embed + that metadata in the distribution. So this package is only needed + to build out of the plain development source tree as cloned from + GitHub, but not to build a release distribution. + `distutils-pytest`_ >= 0.2 @@ -105,6 +105,6 @@ permissions and limitations under the License. .. _PyPI site: https://pypi.org/project/pytest-dependency/ .. _setuptools: http://pypi.python.org/pypi/setuptools/ .. _pytest: http://pytest.org/ -.. _setuptools_scm: https://github.com/pypa/setuptools_scm/ +.. _git-props: https://github.com/RKrahl/git-props .. _distutils-pytest: https://github.com/RKrahl/distutils-pytest .. _Read the Docs site: https://pytest-dependency.readthedocs.io/ diff --git a/setup.py b/setup.py index 9ac98cb..3bccd01 100755 --- a/setup.py +++ b/setup.py @@ -21,14 +21,15 @@ except (ImportError, AttributeError): cmdclass = dict() try: - import setuptools_scm - version = setuptools_scm.get_version() + import gitprops + release = str(gitprops.get_last_release()) + version = str(gitprops.get_version()) except (ImportError, LookupError): try: - from _meta import version + from _meta import release, version except ImportError: log.warn("warning: cannot determine version number") - version = "UNKNOWN" + release = version = "UNKNOWN" docstring = __doc__ @@ -75,6 +76,7 @@ class meta(setuptools.Command): description = "generate meta files" user_options = [] meta_template = ''' +release = "%(release)s" version = "%(version)s" ''' def initialize_options(self): @@ -85,6 +87,7 @@ def run(self): version = self.distribution.get_version() log.info("version: %s", version) values = { + 'release': release, 'version': version, } with Path("_meta.py").open("wt") as f: @@ -136,7 +139,8 @@ def run(self): project_urls = dict( Documentation="https://pytest-dependency.readthedocs.io/", Source="https://github.com/RKrahl/pytest-dependency", - Download="https://github.com/RKrahl/pytest-dependency/releases/latest", + Download=("https://github.com/RKrahl/pytest-dependency/releases/%s/" + % release), ), package_dir = {"": "src"}, python_requires = ">=3.4", From 7d99833ea50749ae793b04d9ecb6db5d471e8634 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 30 Dec 2023 19:20:52 +0100 Subject: [PATCH 53/71] General review of Makefile and .gitignore --- .gitignore | 11 +---------- Makefile | 7 ++----- doc/.gitignore | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+), 15 deletions(-) create mode 100644 doc/.gitignore diff --git a/.gitignore b/.gitignore index 211b44c..3ccd468 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,6 @@ -*.pyc -*~ -.cache/ __pycache__/ +/.env /MANIFEST /_meta.py /build/ /dist/ -/doc/doctest/ -/doc/doctrees/ -/doc/html/ -/doc/latex/ -/doc/linkcheck/ -/pytest_dependency.egg-info/ -/python2_6.patch diff --git a/Makefile b/Makefile index 1c92a9d..74a5ba7 100644 --- a/Makefile +++ b/Makefile @@ -15,16 +15,13 @@ doc-html: build $(MAKE) -C doc html PYTHONPATH=$(BUILDLIB) clean: - rm -f *~ tests/*~ rm -rf build + rm -rf __pycache__ distclean: clean rm -f MANIFEST _meta.py - rm -rf .cache tests/.cache .pytest_cache tests/.pytest_cache - rm -f *.pyc tests/*.pyc - rm -rf __pycache__ tests/__pycache__ rm -rf dist - rm -rf pytest_dependency.egg-info + rm -rf tests/.pytest_cache $(MAKE) -C doc distclean meta: diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..431ef05 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,18 @@ +/devhelp/ +/dirhtml/ +/doctrees/ +/epub/ +/gettext/ +/html/ +/htmlhelp/ +/json/ +/latex/ +/linkcheck/ +/man/ +/pickle/ +/pseudoxml/ +/qthelp/ +/singlehtml/ +/texinfo/ +/text/ +/xml/ From 30a3db12d47266fbe4269b1881581ff5b600c020 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 30 Dec 2023 19:39:41 +0100 Subject: [PATCH 54/71] Add spec file --- python-pytest-dependency.spec | 60 +++++++++++++++++++++++++++++++++++ setup.py | 11 +++++++ 2 files changed, 71 insertions(+) create mode 100644 python-pytest-dependency.spec diff --git a/python-pytest-dependency.spec b/python-pytest-dependency.spec new file mode 100644 index 0000000..d458166 --- /dev/null +++ b/python-pytest-dependency.spec @@ -0,0 +1,60 @@ +%bcond_without tests +%global distname pytest-dependency + +%if 0%{?sle_version} >= 150500 +%global pythons python3 python311 +%else +%{?!python_module:%define python_module() python3-%{**}} +%define skip_python2 1 +%endif + +Name: python-%{distname} +Version: $version +Release: 0 +Summary: $description +License: Apache-2.0 +URL: $url +Group: Development/Languages/Python +Source: https://github.com/RKrahl/pytest-dependency/releases/download/%{version}/%{distname}-%{version}.tar.gz +BuildRequires: %{python_module base >= 3.4} +BuildRequires: %{python_module setuptools} +BuildRequires: fdupes +BuildRequires: python-rpm-macros +%if %{with tests} +BuildRequires: %{python_module distutils-pytest} +BuildRequires: %{python_module pytest >= 3.7} +%endif +Requires: python-pytest >= 3.7 +BuildArch: noarch +%python_subpackages + +%description +$long_description + + +%prep +%setup -q -n %{distname}-%{version} + + +%build +%python_build + + +%install +%python_install +%fdupes %{buildroot}%{python_sitelib} + + +%if %{with tests} +%check +%python_expand $$python setup.py test +%endif + + +%files %{python_files} +%license LICENSE.txt +%doc README.rst +%{python_sitelib}/* + + +%changelog diff --git a/setup.py b/setup.py index 3bccd01..f5c61a3 100755 --- a/setup.py +++ b/setup.py @@ -11,6 +11,7 @@ import distutils.command.sdist import distutils.file_util from distutils import log +from glob import glob import os from pathlib import Path from stat import ST_ATIME, ST_MTIME, ST_MODE, S_IMODE @@ -100,6 +101,16 @@ class sdist(copy_file_mixin, distutils.command.sdist.sdist): def run(self): self.run_command('meta') super().run() + subst = { + "version": self.distribution.get_version(), + "url": self.distribution.get_url(), + "description": docstring.split("\n")[0], + "long_description": docstring.split("\n", maxsplit=2)[2].strip(), + } + for spec in glob("*.spec"): + with Path(spec).open('rt') as inf: + with Path(self.dist_dir, spec).open('wt') as outf: + outf.write(string.Template(inf.read()).substitute(subst)) class build_py(copy_file_mixin, setuptools.command.build_py.build_py): def run(self): From 790dfcc62bd17e637d4cf7eb3acc7885c2f78772 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 30 Dec 2023 20:10:38 +0100 Subject: [PATCH 55/71] Tested with Python 3.4 through 3.12 --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index f5c61a3..f5954e8 100755 --- a/setup.py +++ b/setup.py @@ -145,6 +145,8 @@ def run(self): "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Software Development :: Testing", ], project_urls = dict( From 5399278c50ddda293d25da2113c15ae31786f7bf Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 30 Dec 2023 20:11:18 +0100 Subject: [PATCH 56/71] GitHub Actions workflows: - Review run-tests, - Add publish-to-pypi --- .github/workflows/publish-to-pypi.yaml | 29 ++++++++++++++++++++++++++ .github/workflows/run-tests.yaml | 18 +++++++--------- 2 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/publish-to-pypi.yaml diff --git a/.github/workflows/publish-to-pypi.yaml b/.github/workflows/publish-to-pypi.yaml new file mode 100644 index 0000000..66b197c --- /dev/null +++ b/.github/workflows/publish-to-pypi.yaml @@ -0,0 +1,29 @@ +name: Publish +on: + release: + types: + - published +jobs: + PyPI: + name: publish release to PyPI + runs-on: ubuntu-latest + environment: release + permissions: + id-token: write + env: + SDIST: pytest-dependency-${{ github.event.release.tag_name }}.tar.gz + steps: + - name: Fetch assets + uses: cb80/dlassets@latest + with: + tag: ${{ github.event.release.tag_name }} + to: assets + - name: Check assets + run: | + ls -la assets + - name: Copy distfile to dist directory + run: | + mkdir -p dist + cp -p assets/$SDIST dist + - name: Upload distfile to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 117d3c2..a16bea2 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -6,30 +6,28 @@ jobs: strategy: matrix: python-version: - - '2.7' - - '3.5' - - '3.6' - '3.7' - '3.8' - '3.9' - '3.10' + - '3.11' + - '3.12' os: [ubuntu-latest] + include: + - python-version: '3.6' + os: ubuntu-20.04 steps: - name: Check out repository code - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | pip install -r .github/requirements.txt - - name: Build - run: | - python setup.py build - name: Test with pytest run: | - export PYTHONPATH=$(pwd)/build/lib - python -m pytest tests + python setup.py test From cc3d38ba6499cd938fdd0dd7a20f9ff6e5ce93d6 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 30 Dec 2023 20:25:08 +0100 Subject: [PATCH 57/71] Update changelog --- doc/src/changelog.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/src/changelog.rst b/doc/src/changelog.rst index e46138a..4d3f38e 100644 --- a/doc/src/changelog.rst +++ b/doc/src/changelog.rst @@ -2,16 +2,23 @@ History of changes to pytest-dependency ======================================= dev (not yet released) + Incompatible changes + + Drop support for Python 2. + Bug fixes and minor changes + `#40`_: add logging. + `#50`_, `#51`_: test suite incompatibility with pytest 6.2.0. + `#58`_: declare the type of automark_dependency ini-option correctly as bool. + Internal + + `#75`_: review build tool chain. + .. _#40: https://github.com/RKrahl/pytest-dependency/issues/40 .. _#50: https://github.com/RKrahl/pytest-dependency/issues/50 .. _#51: https://github.com/RKrahl/pytest-dependency/pull/51 .. _#58: https://github.com/RKrahl/pytest-dependency/pull/58 +.. _#75: https://github.com/RKrahl/pytest-dependency/pull/75 0.5.1 (2020-02-14) Bug fixes and minor changes From ce28d66ddc02d9af2b9762afcd53a4304b0be08c Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 30 Dec 2023 20:33:56 +0100 Subject: [PATCH 58/71] Add Read the Dics config --- .readthedocs.yaml | 21 +++++++++++++++++++++ .rtd-require | 4 ++++ doc/src/conf.py | 8 ++++++++ 3 files changed, 33 insertions(+) create mode 100644 .readthedocs.yaml create mode 100644 .rtd-require diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..726b61a --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,21 @@ +# Read the Docs configuration file for Sphinx projects +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.12" + jobs: + post_checkout: + - git fetch --unshallow + post_install: + - python setup.py build + +sphinx: + configuration: doc/src/conf.py + +python: + install: + - requirements: .rtd-require diff --git a/.rtd-require b/.rtd-require new file mode 100644 index 0000000..d316973 --- /dev/null +++ b/.rtd-require @@ -0,0 +1,4 @@ +git-props +pytest >=3.7.0 +setuptools +sphinx_rtd_theme diff --git a/doc/src/conf.py b/doc/src/conf.py index a86fa40..6227eae 100644 --- a/doc/src/conf.py +++ b/doc/src/conf.py @@ -6,6 +6,14 @@ # full list see the documentation: # http://www.sphinx-doc.org/en/master/config +from pathlib import Path +import sys + +maindir = Path(__file__).resolve().parent.parent.parent +buildlib = maindir / "build" / "lib" +sys.path[0] = str(buildlib) +sys.dont_write_bytecode = True + import pytest_dependency # -- Project information ----------------------------------------------------- From 5ddcf5e23496fb0eb8b337c7316aa1cd2628ad88 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 30 Dec 2023 20:49:23 +0100 Subject: [PATCH 59/71] Drop obsolete requirement --- .github/requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/requirements.txt b/.github/requirements.txt index 926a307..de6a2ac 100644 --- a/.github/requirements.txt +++ b/.github/requirements.txt @@ -1,5 +1,4 @@ distutils-pytest git-props -pathlib ; python_version == '2.7' pytest >=3.7.0 setuptools From 3408212556b14753a3853c214e19b6594bf80c14 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 30 Dec 2023 22:20:47 +0100 Subject: [PATCH 60/71] Add GitHub action to check ReST input files --- .github/workflows/rst-lint.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/workflows/rst-lint.yaml diff --git a/.github/workflows/rst-lint.yaml b/.github/workflows/rst-lint.yaml new file mode 100644 index 0000000..b5e7c2f --- /dev/null +++ b/.github/workflows/rst-lint.yaml @@ -0,0 +1,12 @@ +name: Check ReST input files +on: [push, pull_request] +jobs: + doc8: + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v4 + - name: doc8-check + uses: deep-entertainment/doc8-action@v4 + with: + scanPaths: "doc/src" From 44f1efda8b5c2bea2d8f1c25a6ea607ee7064b83 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sat, 30 Dec 2023 22:36:24 +0100 Subject: [PATCH 61/71] Add sphinx_copybutton extension --- .rtd-require | 1 + doc/src/conf.py | 1 + 2 files changed, 2 insertions(+) diff --git a/.rtd-require b/.rtd-require index d316973..1742889 100644 --- a/.rtd-require +++ b/.rtd-require @@ -1,4 +1,5 @@ git-props pytest >=3.7.0 setuptools +sphinx-copybutton sphinx_rtd_theme diff --git a/doc/src/conf.py b/doc/src/conf.py index 6227eae..3701bb5 100644 --- a/doc/src/conf.py +++ b/doc/src/conf.py @@ -40,6 +40,7 @@ extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx', + 'sphinx_copybutton', ] # Add any paths that contain templates here, relative to this directory. From 7d3046aa0c20dc864f06999a46eb34f2ecb87ffb Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 31 Dec 2023 12:20:07 +0100 Subject: [PATCH 62/71] Restrict running tests on push to branches develop and master --- .github/workflows/run-tests.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index a16bea2..5a9a95f 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -1,5 +1,10 @@ name: Run Test -on: [push, pull_request] +on: + push: + branches: + - develop + - master + pull_request: jobs: Test: runs-on: ${{ matrix.os }} From 36480424f0e8d78deeedc139f8fd089daeddd8e1 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 31 Dec 2023 12:27:44 +0100 Subject: [PATCH 63/71] Restrict running ReST lint on push to branches develop and master --- .github/workflows/rst-lint.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rst-lint.yaml b/.github/workflows/rst-lint.yaml index b5e7c2f..b9b239f 100644 --- a/.github/workflows/rst-lint.yaml +++ b/.github/workflows/rst-lint.yaml @@ -1,5 +1,10 @@ name: Check ReST input files -on: [push, pull_request] +on: + push: + branches: + - develop + - master + pull_request: jobs: doc8: runs-on: ubuntu-latest From 695ea2742af78fe65a5b17426170b481666ec0a2 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 31 Dec 2023 19:37:49 +0100 Subject: [PATCH 64/71] Update install instructions --- doc/src/08A1264175343E6E.pub | 98 ++++++++++++++++++++++++++++++++++++ doc/src/install.rst | 97 ++++++++++++++++++++++++++++------- 2 files changed, 177 insertions(+), 18 deletions(-) create mode 100644 doc/src/08A1264175343E6E.pub diff --git a/doc/src/08A1264175343E6E.pub b/doc/src/08A1264175343E6E.pub new file mode 100644 index 0000000..6ec4cf1 --- /dev/null +++ b/doc/src/08A1264175343E6E.pub @@ -0,0 +1,98 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBFgqIDYBEADs08vJtPmKgfaSkKTtHWaYOmCchuXtaTd766b3tDaL55XfTucS +OGVUk1hbaMl8aAZoEmwCDIIMFUGL21QNdZTPLOWv29qXNnUjQEB7vUoJvafZPzTh ++38PDkOeLCQ67J/OSHkRQvEFGc6EXNo/GbtZ1oAGQXFeMbcFg7EuEQvEbHxyJAMo +6a+q9fHB/YkTJVkMFkPnBw2Lbywa5LVJ6ZZWk+IyxbeIZhcjTkpaZMSQhNJAF14q +4uKOGhVupfKZmvwnEvrNwp5ImTiiu6mRuywVDwxXUVersCuIhL/ZQeKI1ImboxW3 +v3p0msxzPaGi0tyb4H7mi/W5rat0u+Zm2EaxYjJDADaNSluxZweUgCi2V/tCzZtP +FgnElFYPHphay8rZ8bbcw5YfcFrC9tdF0sDD1p7qmpOnVlKPw67RwS148+ew7sxy +gW56qJP6AgbVVInJU2XNziphpPBbOYkPhYEa0HsAO62ubESPHJHTHuaMe0m+BbNh +bS2jtPrCaSC5ci6fsVsz0nl5zIFmpDOWKzHNjl5rCcQeV6WXCXeW+f8OfFTe0BXb +nn2qTq2nY+QMNXMiJ0RKwD/XCCphXLlkN5Oflt3JBAEMFMDbptUf8Zd74+xrdjQj +byFu3FLB+3h1oMX+7heoul4LQVbE/qH/fkUIPsSky51I4XWLlgnVy1PQKwARAQAB +tB1Sb2xmIEtyYWhsIDxyb2xmQHJvdGtyYXV0LmRlPokCPAQTAQIAJgIbAwcLCQgH +AwIBBhUIAgkKCwQWAgMBAh4BAheABQJYKisKAhkBAAoJEAihJkF1ND5uLzQQALnu +VyxylxLRlSQ16KAA8mfX2BVcC+3IMj9IyYYIj5Vt7BXbFtBS+sAKQ9sqXVpHzob0 +s5Rfat6sFimO0TDeNlhnS1hRZ1USQJUJ+V8c3L6OmpyNemG3/6Qi0iNYazfE71TA +Km4mW3wgPq8H0/hnKe7tEggPkrhENbo7JDideQ1wAVT9KFu49M2Vm80hUVHiEQh+ +1VbThRmzJjINCiYALcHMo7ZO5uNBenn9zetlKAYpLnRApmPuyAi0jisheJs1gap5 +EtDbcxsD1bqtOKVnJIWqAB7yJDThdDENyo93y2w9BMycobNl3eL7MoB6Ep+Rc8Ae +XIF/HwFtK0j84B+2dUvUHOQZuX3Qtlgu1FenwlOe8u0nwwur1q/Nz7YWg7anagn9 +yA+uDAsO5eclGAqTT5PHjSaEiPtANmRRKijCeHjB7OVTgtT1nY6ThFurDeFnk55J +mTmcaQg9ZPSKeCfWwC+BX+p/9V9Pz5LVa9tyFdxHJERxze4CrwcQkQLFSH+CavLa +iWDLyiAydEa0XU6MU5EmrkwUIHLKzC7ZzwuLkQhC8PXZCifTSkHP7gH4uUUMo2nK +6JQnRC+ylOlyBWSVlzkhYXlKcAbmrw095z70OKx4GVFyBfi3PLjceHjNvA/QPCQR +FIEh65MUYDtSz7LpUwvFYUWVFSuV7zzHlHiT3kYIiEYEExECAAYFAlgqLe8ACgkQ +UcvGPyCdlGbVYwCfYse0zET860S+E71M3Tlfp4brzOIAoOlm+m7wGU6DzTjGyGCa +zPLpoBq4iQEcBBMBAgAGBQJYKi5TAAoJEIPzNkMsf8yRK+sIAKC9HqZY/f5po06Z +gy1rWF5qDBA5GxehwYiD3kZ1EhbINjPbujNLIvpzTce2T4mhu1Ibk8fahu/Viwjy +7n0b0zf9xSiQuUVftopHOf0jfx7oGCVTOMbcENV/UN7SoXCBiKMDDlcfd9Kdt8Ft +nGyqxod3snJMn6G1VKTBCyLECh7BvyBE4oOQhyPgFYrIKwymOq+mBSPd9j3QjvRu +xpqteVOr32IYDYNbcxPIu2q6uydnjZxXdlvuo0xl8wwJgka4zGKj0DboajZyMEvR +OKbs5dQ6pwzRnxvJMxWSB/q4MOWOvtJcVyJP2eYLgE/dcMgN8UgUUjkcJ8G2eSv2 +DgunBHu0H1JvbGYgS3JhaGwgPHJvbGZAdW5pLWJyZW1lbi5kZT6JAjkEEwECACMF +AlgqIb8CGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRAIoSZBdTQ+biHz +D/4pB8FRxJdNYegk5B1HlwzKBrmR/9HW6iJa4MinxOyiPNew3mQRzw/FBM9w1F8h +TL5s+28u/swjwntNLbI5QMYQ+JcSRgmkmzP0lPSS0i+fPm/QjpAsZ/8HTAIUIVPX +6HHOUbCtcqKVePeSIxuubF0QX2dB4uu2BhEdOcaqBkopL0QMTZx4qAaGfh0tKWc5 +Q6genqXmD24cCSezfGwnQrd/2KvgyWkf7OltZHnyOUmoaAamujkttbtVETeybbY7 +GG73nc/Nv40ypzLQmqK6GK2pUmMoM2k3KdsInxTuBWsKjcGLU/FfvPSMsXwaaCHx +N+QByU1d3rc/RDkrw6oHnrGqXQDwvKGpJ3bcAaUpshI/ywRPUUiMOlUPvmMHg4wV +nKSrwJs+9hsf6v930E3Wku3Ohuqf8I7AaMFSSop8McemZQuoMgGSzCuF8rdOlvgj +wY6mOuQ8jSUtvNi6+8NC+tL1DM4p90fx/kn4vI6TJ+34lZ/hMiRj6JH4bbTLEfdS +PL3M3vmh7xl6im2WsBnJaCFpmml7sgIGWIoy8A8dAOEkfmb7kZtGYZwqBSIex4Hu +WdfeEQifzoxBX2YAJjYdMJUUf217+x06s1ML4uChg9csBrphXnMmTzHFXsdI78hh +Cf/f7I/o+mAO49ww4DaZV1SQXjoFQ6iCamsiJaH1nKhnXYhGBBMRAgAGBQJYKi30 +AAoJEFHLxj8gnZRmG5AAoOM1SRMiNBJeR5OeYwsBGuan0ElmAJ4sb+N0emeAImsJ +k1JH3Fuht4/ixIkBGwQTAQIABgUCWCouWAAKCRCD8zZDLH/MkZFMB/QMFHwGT1km +DFDmZKkChCWnL0P5aopsMaCxqx3Ru5aqO87QDRjLOHSK8Emt5sp0Pz1FGJxAUOby +bCll0yG9qFSOU51QQQYEKUSELpMyT4/PdmzGPA8yYclrnq/BJ1cwPnZjw4soRZrL +PiFRYvSb16PF29xGTQF0ejFjSnBnCMNGeoIExtlW5hyGwDoZ1cJgvOqd/o5hyy5D +TxvEFtri0Bx3nCyGrERbH6HNP6Of0+D+MiH/IQKDkfMHaMiR1hHyb4facBALD66e +1dZLp3eKDQdvVZBP2NGW+BOpVLG6Zs1tbGdVCXq6CJEG+zM3xFaUNtAXck09zub3 +IF+F44NY+yu0H1JvbGYgS3JhaGwgPFJvbGYuS3JhaGxAZ214Lm5ldD6JAjkEEwEC +ACMFAlgqIZ4CGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRAIoSZBdTQ+ +bjG8EADiP2oUqpgTz80cy193k7Lo+NEvcEkNgh7bc6W7dLwz7vL7cMBQ9K0qAQjq +TeGHucOM5ju7iDDPOVhchRJFCRl+rg35WaFCmiDd2x4j8c28sSrI+znj9dw5vLfk +8dShS6Ux6ocgLHwd5jh2ErAb3AKEGyVysA+0wydT/44jiLWjRSEF6qIDTmuxsc3L ++/f2ZBHtwRMI2fHWuosXY7Wkb8XTq/4kGgEL/DJrs0AQv/Ww17hfQhf1SYAQSgEK +DC90KsQzJzvAgsplQcJovwKFEgQUZ6ox5x/jhqnj1It0WYALJ4s0qUKOLqi+RKcZ +swpBb0Aq45UMu0KJ+EKWtGG6snfu/d00K+KncS8qBav7ciZ5EP13TdKJNwOcKd8i +NiSnP86yvNHZ5gST/++M8wB9NjhHbf50+JxQ0lJTg6o8rW2IdTjiHUXf5Z3YmwgS +WmH7byhn1leTces2NfsCGKN6j6/0YwKUyOG8XpgAiY34TLXMZbI4zsV07aJY9vRY +Vn45Co0nwOBbl3WMattWg94myQrIyMkEnETStzsO7s/jOIVW8bS4OXdOZg8DY9PE +71k8XQA9Puc5NucYioFosyNWikGoU058qoTQzVXpSgoI9cdTniZGfHoguBqr7X2L +NaX75L5dnwPepM1Z5iFl3P5aBB6rnkW5ZEkftXTOmt8doqj2SohGBBMRAgAGBQJY +Ki30AAoJEFHLxj8gnZRmd1gAoIgAm3VJlohlxaxL4Rk4JaRSvjTcAKDEq8E7j6S6 +4f8JiP2sciLBjUR814kBHAQTAQIABgUCWCouWAAKCRCD8zZDLH/MkU9HB/4p5G0P +O/u5P+hkiCPIZiiMo1DmvuQkQZEDqDobnHaxB5t2SyfdPyM9VJ5rOVSgXwYfxXSJ +3A6eHW5sHtjWqa/eD0dosY+lVJPA/dbJ9RNCPU1YgpfOZSiYtJiAIC3kRd2e4mPW +WwxJqXvTTy+T3aDwt1mfJR8SG1UP2+aiGCVbUWbo1y2EfHUBRc981pKCMERsgemh +WggvRYNkbfyuSF5Mt32beXx91W7TE7hoivKsngzbO82taD9asCSFzmZn3C5BfYth +E3iqb2EmSUbQkRzhfXk7RxoxY7RWeDodFXkRzVbwBXFY3Q7XfRNhtVA7d0O+zIWq +p2DtvLsITicrQxS8uQINBFgqIDYBEADU/dsD2NXhQVQZL12c8Yt6Nj/Ma73B/SaP +wSmyF7f0pPO3sLO0r5wOebolwbGytIh52G/7i1ZdFNJ+D06tbGNc5CUgkgcNTY+x +ND4zazWoaooEsx2TPYqDqSmJbEjeDvr//QvCQ8x7ky1p/iAEvCuFSFiAH0HGXuBU +MiM/MoBC7W3tyS9pbDy43+uphwO0A24Mrxem84zvHBFBFI/pinrp4laU1PMVaSSc +q82ENCGjXhvF8Ummq1F1XclQ+pza+uGBChz6QMG8EB2WRlFQqoR9xa+K3UmC+UO6 +fAkMx8p/LAuAABGphAAGZc011yuYS9uCh9zNFyBOakqLJRP4+faRWxWkzD8d2Cq+ +9I9CpiM0a3bC56VKPFeic8Xwvd81wDIp39eha8OQpMvSZp54j84hDP83IBl8D/Yl +vzKO3Xag1Eg0c92N1mNbLhV75oAbmUgOrJktg2bJjRaUOGN+KuwKUvTUawsIBIAW +xIZP2rLhT21ffSEYC/TZYD39O748lUgcBDH/czTfH+pf1mapjOFaLD+c4lA/hN19 +Su6RqJ8oYTMNsFNWzMmUAsWrCSFnGFhXeOW6kH7AqJ6FMHnsAiCHuhJGKi0Qe76n +wBDr0ut1XqELHK0hC+LJlHufbfsniuG8QqLzmmWr8aX64pyPU8FtB1hYG8tBjkqj +fKIbRKnsBwARAQABiQIfBBgBAgAJBQJYKiA2AhsMAAoJEAihJkF1ND5uOoYQAIgg +DsLqsjW0awdhf/nNK3haDbvYQhtmOmskcKQW7fQXHm0kqGoIliQN57fJNH88OT+9 +Rp6wYjKPblVSNIbcQ8M2nXEVkNtAtO7uC2WVcZeFNVQIsrXX22302riADy7IK51f +RILnCdyrePehxfyscw0VhJIYDx76iZVM0lNKfuZj00CLXOG76V5/T1o4uu8UAVe5 +cW/astcA+u8pU2u7dyUMcaU9kK0rDz2HI+b1CMs+EGPnEVOqML+RxGTIufYUoqSX +tWHXsMSWq6IK22A42m4E6HNtcNAKUK7jGLoOdHA0QaFVxHmajG+pUM9MWTcvZrsn +ZFDlDhyqrF4LBPLG5vk+C4HxdOIEWC+X5GrdESjYWxv14M0ZxustEGkf5VQHdbgE +W+RcqkwkEbiDjLoaFvOZu+NSy0EXxDtBTlkllBJMn01IAxAVgP8M7T/fZ7lg4uLz +RBRhm0T9/IvWjAx0wsiNr45iJ++5sJCQWxU4lWFjSrACPzCY0fP2nDMMBfkn58w/ +r0/tDFumEvBXHCVzdhLzUbetrzmNwGaZdg14ahlEnbbhQktYc+rWbE+ObX74WwHk +0ziR94MVr/9v144v0GuvBZaycUfe1ljHiPjMnjroODyZ48NjRWY83NolEaQhg+Zf +BzxtQzjcEYPj7MEcrHXhzM7gQQ8wnzhc39eK6bKv +=IIFi +-----END PGP PUBLIC KEY BLOCK----- diff --git a/doc/src/install.rst b/doc/src/install.rst index e1a417e..e37c789 100644 --- a/doc/src/install.rst +++ b/doc/src/install.rst @@ -1,13 +1,35 @@ Installation instructions ========================= +See :ref:`install-using-pip` for the short version of the install +instructions. + + System requirements ------------------- -+ Python 2.7 or 3.4 and newer. ++ Python 3.4 or newer. + `setuptools`_. + `pytest`_ 3.7.0 or newer. +Optional library packages +......................... + +These packages are not needed to install or use pytest-dependency. +They are mostly only needed by the maintainer. + ++ `git-props`_ + + This package is used to extract some metadata such as the version + number out of git, the version control system. All releases embed + that metadata in the distribution. So this package is only needed + to build out of the plain development source tree as cloned from + GitHub, but not to build a release distribution. + ++ `distutils-pytest`_ >= 0.2 + + Only needed to run the test suite. + .. _install-other-packages: @@ -30,40 +52,79 @@ Interaction with other packages you do not enable parallelization in pytest-xdist. -Download --------- +Installation +------------ -The latest release version of pytest-dependency is available on the -`Python Package Index (PyPI)`__. +.. _install-using-pip: -.. __: https://pypi.python.org/pypi/pytest_dependency/ +Installation using pip +...................... +You can install pytest-dependency from the `Python Package Index +(PyPI)`__ using pip:: -Installation ------------- + $ pip install pytest-dependency -1. Download the sources, unpack, and change into the source directory. +Note that while installing from PyPI is convenient, there is no way to +verify the integrity of the source distribution, which may be +considered a security risk. -2. Build (optional):: +.. __: `PyPI site`_ + +Manual installation from the source distribution +................................................ + +Release distributions are published on the GitHub. Steps to manually +build from the source distribution: + +1. Download the sources. + + The `Release Page`__ offers download of the source distribution + ``pytest-dependency-X.X.tar.gz`` and a detached signature file + ``pytest-dependency-X.X.tar.gz.asc``, where the "X.X" is to be + replaced by the version number. + +2. Check the signature (optional). + + You may verify the integrity of the source distribution by checking + the signature:: + + $ gpg --verify pytest-dependency-0.5.1.tar.gz.asc + gpg: assuming signed data in 'pytest-dependency-0.5.1.tar.gz' + gpg: Signature made Fri Feb 14 21:58:30 2020 CET + gpg: using RSA key B4EB920861DF33F31B55A07C08A1264175343E6E + gpg: Good signature from "Rolf Krahl " [ultimate] + gpg: aka "Rolf Krahl " [ultimate] + gpg: aka "Rolf Krahl " [ultimate] + + The signature should be made by the key + :download:`0xB4EB920861DF33F31B55A07C08A1264175343E6E + <08A1264175343E6E.pub>`. The fingerprint of that key is:: + + B4EB 9208 61DF 33F3 1B55 A07C 08A1 2641 7534 3E6E + +3. Unpack and change into the source directory. + +4. Build (optional):: $ python setup.py build -3. Test (optional):: +5. Test (optional):: - $ python -m pytest tests + $ python setup.py test -4. Install:: +6. Install:: $ python setup.py install -The last step might require admin privileges in order to write into -the site-packages directory of your Python installation. - -For production use, it is always recommended to use the latest release -version from PyPI, see above. +.. __: `GitHub latest release`_ .. _setuptools: http://pypi.python.org/pypi/setuptools/ .. _pytest: http://pytest.org/ +.. _git-props: https://github.com/RKrahl/git-props +.. _distutils-pytest: https://github.com/RKrahl/distutils-pytest .. _pytest-order: https://github.com/pytest-dev/pytest-order .. _pytest-xdist: https://github.com/pytest-dev/pytest-xdist +.. _PyPI site: https://pypi.python.org/pypi/pytest_dependency/ +.. _GitHub latest release: https://github.com/RKrahl/pytest-dependency/releases/latest From eb48f326af4428f7e292bc980c80a02686650832 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 31 Dec 2023 19:42:01 +0100 Subject: [PATCH 65/71] Fixup 695ea27: trailing whitespace --- doc/src/install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/install.rst b/doc/src/install.rst index e37c789..32e4d40 100644 --- a/doc/src/install.rst +++ b/doc/src/install.rst @@ -89,7 +89,7 @@ build from the source distribution: You may verify the integrity of the source distribution by checking the signature:: - $ gpg --verify pytest-dependency-0.5.1.tar.gz.asc + $ gpg --verify pytest-dependency-0.5.1.tar.gz.asc gpg: assuming signed data in 'pytest-dependency-0.5.1.tar.gz' gpg: Signature made Fri Feb 14 21:58:30 2020 CET gpg: using RSA key B4EB920861DF33F31B55A07C08A1264175343E6E From 463227e4519e444701f22acadf3442c1b45e5214 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 31 Dec 2023 19:54:06 +0100 Subject: [PATCH 66/71] Review README and bump copyright year --- README.rst | 65 ++++------------------------------------------- doc/src/about.rst | 2 +- doc/src/conf.py | 2 +- 3 files changed, 7 insertions(+), 62 deletions(-) diff --git a/README.rst b/README.rst index 9589eac..94b5add 100644 --- a/README.rst +++ b/README.rst @@ -15,61 +15,10 @@ pytest-dependency – Manage dependencies of tests ================================================ -This pytest plugin manages dependencies of tests. It allows to mark -some tests as dependent from other tests. These tests will then be -skipped if any of the dependencies did fail or has been skipped. - - -Download --------- - -The latest release version can be found `at PyPI`__. - -.. __: `PyPI site`_ - - -System requirements -------------------- - -+ Python 3.4 and newer. -+ `setuptools`_. -+ `pytest`_ 3.7.0 or newer. - -Optional library packages: - -+ `git-props`_ - - This package is used to extract some metadata such as the version - number out of git, the version control system. All releases embed - that metadata in the distribution. So this package is only needed - to build out of the plain development source tree as cloned from - GitHub, but not to build a release distribution. - -+ `distutils-pytest`_ >= 0.2 - - Only needed to run the test suite. - - -Installation ------------- - -1. Download the sources, unpack, and change into the source directory. - -2. Build (optional):: - - $ python setup.py build - -3. Test (optional):: - - $ python setup.py test - -4. Install:: - - $ python setup.py install - -The last step might require admin privileges in order to write into -the site-packages directory of your Python installation. - +This module is a plugin for the popular Python testing framework +`pytest`_. It manages dependencies of tests: you may mark some tests +as dependent from other tests. These tests will then be skipped if +any of the dependencies did fail or has been skipped. Documentation ------------- @@ -87,7 +36,7 @@ Copyright and License - Copyright 2013–2015 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH -- Copyright 2016–2020 Rolf Krahl +- Copyright 2016–2023 Rolf Krahl Licensed under the `Apache License`_, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -99,10 +48,6 @@ implied. See the License for the specific language governing permissions and limitations under the License. -.. _PyPI site: https://pypi.org/project/pytest-dependency/ -.. _setuptools: http://pypi.python.org/pypi/setuptools/ .. _pytest: http://pytest.org/ -.. _git-props: https://github.com/RKrahl/git-props -.. _distutils-pytest: https://github.com/RKrahl/distutils-pytest .. _Read the Docs site: https://pytest-dependency.readthedocs.io/ .. _Apache License: https://www.apache.org/licenses/LICENSE-2.0 diff --git a/doc/src/about.rst b/doc/src/about.rst index 24c680a..c2f006d 100644 --- a/doc/src/about.rst +++ b/doc/src/about.rst @@ -71,7 +71,7 @@ Copyright and License - Copyright 2013–2015 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH -- Copyright 2016–2020 Rolf Krahl +- Copyright 2016–2023 Rolf Krahl Licensed under the `Apache License`_, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/doc/src/conf.py b/doc/src/conf.py index 3701bb5..acc5ccf 100644 --- a/doc/src/conf.py +++ b/doc/src/conf.py @@ -19,7 +19,7 @@ # -- Project information ----------------------------------------------------- project = 'pytest-dependency' -copyright = '2016–2020, Rolf Krahl' +copyright = '2016–2023, Rolf Krahl' author = 'Rolf Krahl' # The full version, including alpha/beta/rc tags From 346a3441efbf26dfad83e277ab6ccac26cfe6d75 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 31 Dec 2023 20:08:21 +0100 Subject: [PATCH 67/71] Move the changelog to the end, after the API reference --- doc/src/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/index.rst b/doc/src/index.rst index 790b277..d368390 100644 --- a/doc/src/index.rst +++ b/doc/src/index.rst @@ -19,5 +19,5 @@ Content of the documentation names debugging configuration - changelog reference + changelog From f11cf56ca553992891d80ce79bbbac82aa40d285 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 31 Dec 2023 20:35:36 +0100 Subject: [PATCH 68/71] Rewrite introduction to the debugging guide --- doc/src/debugging.rst | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/doc/src/debugging.rst b/doc/src/debugging.rst index 6f70676..edf7d7b 100644 --- a/doc/src/debugging.rst +++ b/doc/src/debugging.rst @@ -1,8 +1,15 @@ Debugging guide =============== -This section is supposed to provide hints on what to check if -pytest-dependency does not seem to behave as expected. +It's just too easy to make errors. Sometimes, it's not obvious to +understand the behavior of pytest-dependency: test get skipped +although their dependencies succeed or the other way round, the +dependency marker does not seem have any effect and tests are executed +although their dependency fail. + +This section intends to give an overview of the tools that pytest +provides to investigate the situation in detail, which hopefully helps +to understand what happens. Example ------- From e2edf54383b3b8f2c137d78677debfd63b23ba95 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 31 Dec 2023 20:43:44 +0100 Subject: [PATCH 69/71] Explicitely set language to 'en' --- doc/src/conf.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/doc/src/conf.py b/doc/src/conf.py index acc5ccf..5d517fc 100644 --- a/doc/src/conf.py +++ b/doc/src/conf.py @@ -46,10 +46,7 @@ # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] +# The suffix of source filenames. source_suffix = '.rst' # The master toctree document. @@ -60,7 +57,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -75,7 +72,6 @@ autodoc_member_order = 'bysource' - # -- Options for intersphinx extension --------------------------------------- intersphinx_mapping = { @@ -83,7 +79,6 @@ 'pytest': ('https://docs.pytest.org/en/stable/', None), } - # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for From 38baf8cb5f561dcf16539c8304b0f71898a625f6 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 31 Dec 2023 20:57:02 +0100 Subject: [PATCH 70/71] Update changelog --- CHANGES.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 1e48c6e..64487bf 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,11 @@ Changelog dev (not yet released) ~~~~~~~~~~~~~~~~~~~~~~ +Documentation +------------- + ++ `#39`_, `#41`_, `#59`_: Review documentation + Incompatible changes -------------------- @@ -22,10 +27,13 @@ Internal + `#75`_: review build tool chain. +.. _#39: https://github.com/RKrahl/pytest-dependency/issues/39 .. _#40: https://github.com/RKrahl/pytest-dependency/issues/40 +.. _#41: https://github.com/RKrahl/pytest-dependency/issues/41 .. _#50: https://github.com/RKrahl/pytest-dependency/issues/50 .. _#51: https://github.com/RKrahl/pytest-dependency/pull/51 .. _#58: https://github.com/RKrahl/pytest-dependency/pull/58 +.. _#59: https://github.com/RKrahl/pytest-dependency/pull/59 .. _#75: https://github.com/RKrahl/pytest-dependency/pull/75 0.5.1 (2020-02-14) From def647eda5778fc5b0ffebb7251c81e804f50089 Mon Sep 17 00:00:00 2001 From: Rolf Krahl Date: Sun, 31 Dec 2023 21:16:19 +0100 Subject: [PATCH 71/71] Prepare release 0.6.0 --- CHANGES.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 64487bf..4bd0bc1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,8 +1,8 @@ Changelog ========= -dev (not yet released) -~~~~~~~~~~~~~~~~~~~~~~ +0.6.0 (2023-12-31) +~~~~~~~~~~~~~~~~~~ Documentation -------------