├── .bumpversion.cfg ├── .coveragerc ├── .gitignore ├── .pre-commit-config.yaml ├── .travis.yml ├── LICENSE ├── MANIFEST.in ├── README.rst ├── poetry.lock ├── pytest.ini ├── pytest_docs ├── __init__.py ├── element.py ├── formatter.py ├── formatters │ ├── __init__.py │ ├── markdown.py │ └── restuctured.py ├── plugin.py └── utils.py ├── setup.py ├── tests ├── conftest.py ├── output │ ├── markdown_sanity.md │ └── rst_sanity.rst └── test_pytest_docs.py ├── tox.ini └── venv ├── bin ├── activate ├── activate.csh ├── activate.fish ├── easy_install ├── easy_install-3.7 ├── pip ├── pip3 ├── pip3.7 ├── py.test ├── pytest ├── python ├── python3 └── python3.7 ├── pip-selfcheck.json └── pyvenv.cfg /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.1.0 3 | commit = True 4 | tag = True 5 | 6 | [bumpversion:file:setup.py] -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | source=pytest-docs 3 | 4 | [report] 5 | # Regexes for lines to exclude from consideration 6 | exclude_lines = 7 | # Have to re-enable the standard pragma 8 | pragma: no cover 9 | 10 | # Don't complain about missing debug-only code: 11 | def __repr__ 12 | if self\.debug 13 | 14 | # Don't complain if tests don't hit defensive assertion code: 15 | raise AssertionError 16 | raise NotImplementedError 17 | 18 | # Don't complain if non-runnable code isn't run: 19 | if 0: 20 | if __name__ == .__main__.: 21 | 22 | ignore_errors = True -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask instance folder 57 | instance/ 58 | 59 | # Sphinx documentation 60 | docs/_build/ 61 | 62 | # MkDocs documentation 63 | /site/ 64 | 65 | # PyBuilder 66 | target/ 67 | 68 | # IPython Notebook 69 | .ipynb_checkpoints 70 | 71 | # pyenv 72 | .python-version 73 | 74 | .idea 75 | /venv/ 76 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/ambv/black 3 | rev: 18.6b4 4 | hooks: 5 | - id: black 6 | args: [--safe, --quiet] 7 | language_version: python3.6 -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Config file for automatic testing at travis-ci.org 2 | 3 | sudo: false 4 | language: python 5 | 6 | matrix: 7 | include: 8 | - python: 3.4 9 | - python: 3.5 10 | - python: 3.6 11 | - python: 3.7 12 | sudo: required 13 | dist: xenial 14 | 15 | install: 16 | - pip install --upgrade pip setuptools tox tox-travis codecov coverage 17 | 18 | script: 19 | - tox 20 | 21 | after_success: 22 | - codecov 23 | 24 | before_cache: 25 | - rm -rf $HOME/.cache/pip/log 26 | 27 | cache: 28 | directories: 29 | - $HOME/.cache/pip 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2018 Or Carmi 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.rst 3 | 4 | recursive-exclude * __pycache__ 5 | recursive-exclude * *.py[co] 6 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | pytest-docs 3 | =========== 4 | 5 | A `pytest`_ plugin that generates documentation of the testing application itself. 6 | 7 | .. image:: https://img.shields.io/pypi/v/pytest-docs.svg 8 | :target: https://pypi.org/project/pytest-docs 9 | :alt: PyPI version 10 | 11 | .. image:: https://img.shields.io/pypi/pyversions/pytest-docs.svg 12 | :target: https://pypi.org/project/pytest-docs 13 | :alt: Python versions 14 | 15 | .. image:: https://travis-ci.org/liiight/pytest-docs.svg?branch=master 16 | :target: https://travis-ci.org/liiight/pytest-docs 17 | :alt: Travis CI 18 | 19 | .. image:: https://img.shields.io/badge/code%20style-black-000000.svg 20 | :target: https://github.com/ambv/black 21 | :alt: Black 22 | 23 | .. image:: https://pepy.tech/badge/pytest-docs 24 | :target: https://pepy.tech/project/pytest-docs 25 | :alt: Pepy.tech 26 | 27 | .. image:: https://codecov.io/gh/liiight/pytest_docs/branch/master/graph/badge.svg 28 | :target: https://codecov.io/gh/liiight/pytest_docs 29 | 30 | 31 | Features 32 | -------- 33 | 34 | Create documentation of your tests. Turns this: 35 | 36 | .. code-block:: 37 | 38 | '''This is the module doc''' 39 | import pytest 40 | 41 | pytestmark = [ 42 | pytest.mark.module_mark, 43 | pytest.mark.module_mark_2, 44 | pytest.mark.pytest_doc(name="Test Docs"), 45 | ] 46 | 47 | 48 | @pytest.mark.class_marker 49 | @pytest.mark.pytest_doc(name="Test Class") 50 | class TestClass: 51 | '''This is the class doc''' 52 | 53 | @pytest.mark.func_mark_a("foo") 54 | def test_func_a(self): 55 | '''This is the doc for test_func_a''' 56 | assert 1 57 | 58 | @pytest.mark.kwarg_mark(goo="bla") 59 | def test_func_b(self): 60 | '''This is the doc for test_func_b''' 61 | assert 1 62 | 63 | To this: 64 | 65 | .. code-block:: 66 | 67 | # Test Docs 68 | This is the module doc 69 | 70 | **Markers:** 71 | - module_mark 72 | - module_mark_2 73 | - pytest_doc (name=Test Docs) 74 | ## Test Class 75 | This is the class doc 76 | 77 | **Markers:** 78 | - pytest_doc (name=Test Class) 79 | - class_marker 80 | ### test_func_a 81 | This is the doc for test_func_a 82 | 83 | **Markers:** 84 | - func_mark_a (foo) 85 | ### test_func_b 86 | This is the doc for test_func_b 87 | 88 | **Markers:** 89 | - kwarg_mark (goo=bla) 90 | 91 | Current supported formats: 92 | 93 | - Markdown 94 | - reStrcutured text 95 | 96 | Why not sphinx? 97 | --------------- 98 | 99 | (More accurately, why not sphinx-autodoc?) 100 | Sphinx is an amazing tool that I use and used in other project. To use its autodoc plugin, it need the documented plugin to be importable by the python interperter. Pytest test collection and invocation uses a completely separate mechanism. 101 | If you believe that it somehow possible to use sphinx to create pytest documentation, please do not hesitate to contact me. 102 | 103 | Requirements 104 | ------------ 105 | 106 | - Python 3.4, 3.5, 3.6 or 3.7 107 | - Pytest >= 3.5.0 108 | 109 | Installation 110 | ------------ 111 | 112 | You can install "pytest-docs" via `pip`_ from `PyPI`_:: 113 | 114 | $ pip install pytest-docs 115 | 116 | 117 | Usage 118 | ----- 119 | 120 | Use ``--docs [PATH]`` to create the documentation. 121 | 122 | Use ``--doc-type`` to select the type (currently supports ``md`` and ``rst``) 123 | 124 | Use ``@pytest.mark.pytest_doc(name="Test Class")`` to override name of element. It'll override name based on the place it is being used (module, class or function). 125 | 126 | **Note:** pytest-docs uses the pytest collection mechanism, so your documentation will be generated according the the usual collection commands used to run the tests. 127 | 128 | What's planned ahead 129 | -------------------- 130 | 131 | 1. See if anyone is even interested in this 132 | 2. Document fixtures 133 | 3. Document tests and fixtures parametrization 134 | 4. Custom formatters via hooks 135 | 136 | Contributing 137 | ------------ 138 | Contributions are very welcome. Tests can be run with `tox`_, please ensure 139 | the coverage at least stays the same before you submit a pull request. 140 | 141 | License 142 | ------- 143 | 144 | Distributed under the terms of the `MIT`_ license, "pytest-docs" is free and open source software 145 | 146 | Issues 147 | ------ 148 | 149 | If you encounter any problems, please `file an issue`_ along with a detailed description. 150 | 151 | .. _`Cookiecutter`: https://github.com/audreyr/cookiecutter 152 | .. _`@hackebrot`: https://github.com/hackebrot 153 | .. _`MIT`: http://opensource.org/licenses/MIT 154 | .. _`BSD-3`: http://opensource.org/licenses/BSD-3-Clause 155 | .. _`GNU GPL v3.0`: http://www.gnu.org/licenses/gpl-3.0.txt 156 | .. _`Apache Software License 2.0`: http://www.apache.org/licenses/LICENSE-2.0 157 | .. _`cookiecutter-pytest-plugin`: https://github.com/pytest-dev/cookiecutter-pytest-plugin 158 | .. _`file an issue`: https://github.com/liiight/pytest-docs/issues 159 | .. _`pytest`: https://github.com/pytest-dev/pytest 160 | .. _`tox`: https://tox.readthedocs.io/en/latest/ 161 | .. _`pip`: https://pypi.org/project/pip/ 162 | .. _`PyPI`: https://pypi.org/project 163 | 164 | This `pytest`_ plugin was generated with `Cookiecutter`_ along with `@hackebrot`_'s `cookiecutter-pytest-plugin`_ template. 165 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | category = "dev" 3 | description = "A few extensions to pyyaml." 4 | name = "aspy.yaml" 5 | optional = false 6 | python-versions = "*" 7 | version = "1.1.1" 8 | 9 | [package.dependencies] 10 | pyyaml = "*" 11 | 12 | [[package]] 13 | category = "main" 14 | description = "Atomic file writes." 15 | name = "atomicwrites" 16 | optional = false 17 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 18 | version = "1.2.1" 19 | 20 | [[package]] 21 | category = "main" 22 | description = "Classes Without Boilerplate" 23 | name = "attrs" 24 | optional = false 25 | python-versions = "*" 26 | version = "18.2.0" 27 | 28 | [[package]] 29 | category = "dev" 30 | description = "A decorator for caching properties in classes." 31 | name = "cached-property" 32 | optional = false 33 | python-versions = "*" 34 | version = "1.5.1" 35 | 36 | [[package]] 37 | category = "dev" 38 | description = "Validate configuration and produce human readable error messages." 39 | name = "cfgv" 40 | optional = false 41 | python-versions = "*" 42 | version = "1.1.0" 43 | 44 | [package.dependencies] 45 | six = "*" 46 | 47 | [[package]] 48 | category = "main" 49 | description = "Cross-platform colored terminal text." 50 | marker = "sys_platform == \"win32\"" 51 | name = "colorama" 52 | optional = false 53 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 54 | version = "0.4.0" 55 | 56 | [[package]] 57 | category = "dev" 58 | description = "A platform independent file lock." 59 | name = "filelock" 60 | optional = false 61 | python-versions = "*" 62 | version = "3.0.10" 63 | 64 | [[package]] 65 | category = "dev" 66 | description = "File identification library for Python" 67 | name = "identify" 68 | optional = false 69 | python-versions = "*" 70 | version = "1.1.7" 71 | 72 | [[package]] 73 | category = "dev" 74 | description = "Read metadata from Python packages" 75 | name = "importlib-metadata" 76 | optional = false 77 | python-versions = ">=2.7,!=3.0,!=3.1,!=3.2,!=3.3" 78 | version = "0.6" 79 | 80 | [[package]] 81 | category = "dev" 82 | description = "Read resources from Python packages" 83 | marker = "python_version < \"3.7\"" 84 | name = "importlib-resources" 85 | optional = false 86 | python-versions = ">=2.7,!=3.0,!=3.1,!=3.2,!=3.3" 87 | version = "1.0.2" 88 | 89 | [package.dependencies] 90 | [package.dependencies.typing] 91 | python = "<3.5" 92 | version = "*" 93 | 94 | [[package]] 95 | category = "main" 96 | description = "More routines for operating on iterables, beyond itertools" 97 | name = "more-itertools" 98 | optional = false 99 | python-versions = "*" 100 | version = "4.3.0" 101 | 102 | [package.dependencies] 103 | six = ">=1.0.0,<2.0.0" 104 | 105 | [[package]] 106 | category = "dev" 107 | description = "Node.js virtual environment builder" 108 | name = "nodeenv" 109 | optional = false 110 | python-versions = "*" 111 | version = "1.3.2" 112 | 113 | [[package]] 114 | category = "main" 115 | description = "Object-oriented filesystem paths" 116 | marker = "python_version < \"3.6\"" 117 | name = "pathlib2" 118 | optional = false 119 | python-versions = "*" 120 | version = "2.3.2" 121 | 122 | [package.dependencies] 123 | six = "*" 124 | 125 | [package.dependencies.scandir] 126 | python = "<3.5" 127 | version = "*" 128 | 129 | [[package]] 130 | category = "main" 131 | description = "plugin and hook calling mechanisms for python" 132 | name = "pluggy" 133 | optional = false 134 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 135 | version = "0.8.0" 136 | 137 | [[package]] 138 | category = "dev" 139 | description = "A framework for managing and maintaining multi-language pre-commit hooks." 140 | name = "pre-commit" 141 | optional = false 142 | python-versions = "*" 143 | version = "1.12.0" 144 | 145 | [package.dependencies] 146 | "aspy.yaml" = "*" 147 | cached-property = "*" 148 | cfgv = ">=1.0.0" 149 | identify = ">=1.0.0" 150 | importlib-metadata = "*" 151 | nodeenv = ">=0.11.1" 152 | pyyaml = "*" 153 | six = "*" 154 | toml = "*" 155 | virtualenv = "*" 156 | 157 | [package.dependencies.importlib-resources] 158 | python = "<3.7" 159 | version = "*" 160 | 161 | [[package]] 162 | category = "main" 163 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 164 | name = "py" 165 | optional = false 166 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 167 | version = "1.7.0" 168 | 169 | [[package]] 170 | category = "main" 171 | description = "pytest: simple powerful testing with Python" 172 | name = "pytest" 173 | optional = false 174 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 175 | version = "3.10.0" 176 | 177 | [package.dependencies] 178 | atomicwrites = ">=1.0" 179 | attrs = ">=17.4.0" 180 | colorama = "*" 181 | more-itertools = ">=4.0.0" 182 | pluggy = ">=0.7" 183 | py = ">=1.5.0" 184 | setuptools = "*" 185 | six = ">=1.10.0" 186 | 187 | [package.dependencies.pathlib2] 188 | python = "<3.6" 189 | version = ">=2.2.0" 190 | 191 | [[package]] 192 | category = "dev" 193 | description = "YAML parser and emitter for Python" 194 | name = "pyyaml" 195 | optional = false 196 | python-versions = "*" 197 | version = "3.13" 198 | 199 | [[package]] 200 | category = "main" 201 | description = "scandir, a better directory iterator and faster os.walk()" 202 | marker = "python_version < \"3.5\"" 203 | name = "scandir" 204 | optional = false 205 | python-versions = "*" 206 | version = "1.9.0" 207 | 208 | [[package]] 209 | category = "main" 210 | description = "Python 2 and 3 compatibility utilities" 211 | name = "six" 212 | optional = false 213 | python-versions = "*" 214 | version = "1.11.0" 215 | 216 | [[package]] 217 | category = "dev" 218 | description = "Python Library for Tom's Obvious, Minimal Language" 219 | name = "toml" 220 | optional = false 221 | python-versions = "*" 222 | version = "0.10.0" 223 | 224 | [[package]] 225 | category = "dev" 226 | description = "virtualenv-based automation of test activities" 227 | name = "tox" 228 | optional = false 229 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 230 | version = "3.5.3" 231 | 232 | [package.dependencies] 233 | filelock = ">=3.0.0,<4" 234 | pluggy = ">=0.3.0,<1" 235 | py = ">=1.4.17,<2" 236 | setuptools = ">=30.0.0" 237 | six = ">=1.0.0,<2" 238 | toml = ">=0.9.4" 239 | virtualenv = ">=1.11.2" 240 | 241 | [[package]] 242 | category = "dev" 243 | description = "Type Hints for Python" 244 | marker = "python_version < \"3.5\"" 245 | name = "typing" 246 | optional = false 247 | python-versions = "*" 248 | version = "3.6.6" 249 | 250 | [[package]] 251 | category = "dev" 252 | description = "Virtual Python Environment builder" 253 | name = "virtualenv" 254 | optional = false 255 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" 256 | version = "16.1.0" 257 | 258 | [metadata] 259 | content-hash = "aaa7cdb4e35b783601f608b38adc37f0f393ccf01b422d85da61b1b80fd60faa" 260 | python-versions = "^3.4" 261 | 262 | [metadata.hashes] 263 | "aspy.yaml" = ["04d26279513618f1024e1aba46471db870b3b33aef204c2d09bcf93bea9ba13f", "0a77e23fafe7b242068ffc0252cee130d3e509040908fc678d9d1060e7494baa"] 264 | atomicwrites = ["0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0", "ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee"] 265 | attrs = ["10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69", "ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb"] 266 | cached-property = ["3a026f1a54135677e7da5ce819b0c690f156f37976f3e30c5430740725203d7f", "9217a59f14a5682da7c4b8829deadbfc194ac22e9908ccf7c8820234e80a1504"] 267 | cfgv = ["73f48a752bd7aab103c4b882d6596c6360b7aa63b34073dd2c35c7b4b8f93010", "d1791caa9ff5c0c7bce80e7ecc1921752a2eb7c2463a08ed9b6c96b85a2f75aa"] 268 | colorama = ["a3d89af5db9e9806a779a50296b5fdb466e281147c2c235e8225ecc6dbf7bbf3", "c9b54bebe91a6a803e0772c8561d53f2926bfeb17cd141fbabcb08424086595c"] 269 | filelock = ["b8d5ca5ca1c815e1574aee746650ea7301de63d87935b3463d26368b76e31633", "d610c1bb404daf85976d7a82eb2ada120f04671007266b708606565dd03b5be6"] 270 | identify = ["5e956558a9a1e3b3891d7c6609fc9709657a11878af288ace484d1a46a93922b", "623086059219cc7b86c77a3891f3700cb175d4ce02b8fb8802b047301d71e783"] 271 | importlib-metadata = ["36b02c84f9001adf65209fefdf951be8e9014a95eab9938c0779ad5670359b1c", "60b6481a72908c93ccb707abeb926fb5a15319b9e6f0b76639a718837ee12de0"] 272 | importlib-resources = ["6e2783b2538bd5a14678284a3962b0660c715e5a0f10243fd5e00a4b5974f50b", "d3279fd0f6f847cced9f7acc19bd3e5df54d34f93a2e7bb5f238f81545787078"] 273 | more-itertools = ["c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092", "c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e", "fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d"] 274 | nodeenv = ["aa040ab5189bae17d272175609010be6c5b589ec4b8dbd832cc50c9e9cb7496f"] 275 | pathlib2 = ["8eb170f8d0d61825e09a95b38be068299ddeda82f35e96c3301a8a5e7604cb83", "d1aa2a11ba7b8f7b21ab852b1fb5afb277e1bb99d5dfc663380b5015c0d80c5a"] 276 | pluggy = ["447ba94990e8014ee25ec853339faf7b0fc8050cdc3289d4d71f7f410fb90095", "bde19360a8ec4dfd8a20dcb811780a30998101f078fc7ded6162f0076f50508f"] 277 | pre-commit = ["7542bd8ae1c58745175ea0a9295964ee82a10f7e18c4344f5e4c02bd85d02561", "87f687da6a2651d5067cfec95b854b004e95b70143cbf2369604bb3acbce25ec"] 278 | py = ["bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694", "e76826342cefe3c3d5f7e8ee4316b80d1dd8a300781612ddbc765c17ba25a6c6"] 279 | pytest = ["630ff1dbe04f469ee78faa5660f712e58b953da7df22ea5d828c9012e134da43", "a2b5232735dd0b736cbea9c0f09e5070d78fcaba2823a4f6f09d9a81bd19415c"] 280 | pyyaml = ["3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b", "3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf", "40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a", "558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3", "a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1", "aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1", "bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613", "d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04", "d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f", "e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537", "e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531"] 281 | scandir = ["04b8adb105f2ed313a7c2ef0f1cf7aff4871aa7a1883fa4d8c44b5551ab052d6", "1444134990356c81d12f30e4b311379acfbbcd03e0bab591de2696a3b126d58e", "1b5c314e39f596875e5a95dd81af03730b338c277c54a454226978d5ba95dbb6", "346619f72eb0ddc4cf355ceffd225fa52506c92a2ff05318cfabd02a144e7c4e", "44975e209c4827fc18a3486f257154d34ec6eaec0f90fef0cca1caa482db7064", "61859fd7e40b8c71e609c202db5b0c1dbec0d5c7f1449dec2245575bdc866792", "a5e232a0bf188362fa00123cc0bb842d363a292de7126126df5527b6a369586a", "c14701409f311e7a9b7ec8e337f0815baf7ac95776cc78b419a1e6d49889a383", "c7708f29d843fc2764310732e41f0ce27feadde453261859ec0fca7865dfc41b", "c9009c527929f6e25604aec39b0a43c3f831d2947d89d6caaab22f057b7055c8", "f5c71e29b4e2af7ccdc03a020c626ede51da471173b4a6ad1e904f2b2e04b4bd"] 282 | six = ["70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", "832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"] 283 | toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"] 284 | tox = ["513e32fdf2f9e2d583c2f248f47ba9886428c949f068ac54a0469cac55df5862", "75fa30e8329b41b664585f5fb837e23ce1d7e6fa1f7811f2be571c990f9d911b"] 285 | typing = ["4027c5f6127a6267a435201981ba156de91ad0d1d98e9ddc2aa173453453492d", "57dcf675a99b74d64dacf6fba08fb17cf7e3d5fdff53d4a30ea2a5e7e52543d4", "a4c8473ce11a65999c8f59cb093e70686b6c84c98df58c1dae9b3b196089858a"] 286 | virtualenv = ["686176c23a538ecc56d27ed9d5217abd34644823d6391cbeb232f42bf722baad", "f899fafcd92e1150f40c8215328be38ff24b519cd95357fa6e78e006c7638208"] 287 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | pytester_example_dir = tests/examples -------------------------------------------------------------------------------- /pytest_docs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liiight/pytest-docs/bdbd7b3e83f16582cadb66e54aea8070becf3e99/pytest_docs/__init__.py -------------------------------------------------------------------------------- /pytest_docs/element.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | from enum import Enum 3 | 4 | from _pytest.mark.structures import MarkDecorator 5 | from pytest import Function 6 | 7 | from .utils import methdispatch 8 | 9 | PYTEST_DOC_MARKER = "pytest_doc" 10 | 11 | 12 | class ElementType(Enum): 13 | FUNCTION = "function" 14 | CLASS = "class" 15 | MODULE = "module" 16 | NONE = None 17 | 18 | 19 | class Element: 20 | """Represent the document consistent of the separate elements. 21 | A recursive tree structure where each element can have a parent, siblings or children. 22 | A module is a parent of a class, class of a function.""" 23 | 24 | def __init__(self, element: "Element" = None): 25 | self.raw_element = element 26 | self.raw_markers = self.element_markers(element) 27 | self.type_ = self.element_type(element) if element else ElementType.NONE 28 | self.unique_id = self.unique_identifier(element) 29 | self.raw_name = self.element_name(element) 30 | self.desc = self.element_desc(element) 31 | 32 | self.parent = None 33 | self.children = [] 34 | 35 | def __iter__(self): 36 | return iter(self.children) 37 | 38 | @property 39 | def top(self): 40 | return self.parent is None 41 | 42 | @property 43 | def siblings(self): 44 | """Return a generator of :class:`Element` that share the same parent as current element""" 45 | return (elem for elem in self.parent if elem is not self) if self.parent else () 46 | 47 | @methdispatch 48 | def element_type(self, element) -> ElementType: 49 | return ( 50 | ElementType.CLASS 51 | if hasattr(element, "__qualname__") 52 | else ElementType.MODULE 53 | ) 54 | 55 | @element_type.register(Function) 56 | def _(self, element) -> ElementType: 57 | return ElementType.FUNCTION 58 | 59 | @classmethod 60 | def create_doc_tree(cls, items) -> "Element": 61 | tree = cls() 62 | for item in items: 63 | tree.add(cls(item.module)).add(cls(item.cls)).add(cls(item)) 64 | return tree 65 | 66 | @methdispatch 67 | def element_name(self, element) -> str: 68 | return element.__name__ if element else "" 69 | 70 | @element_name.register(Function) 71 | def _(self, element) -> str: 72 | return element.originalname or element.name 73 | 74 | @methdispatch 75 | def element_desc(self, element) -> str: 76 | return element.__doc__ if element else "" 77 | 78 | @element_desc.register(Function) 79 | def _(self, element) -> str: 80 | return element.function.__doc__ 81 | 82 | @methdispatch 83 | def format_marker(self, marker_data): 84 | data = ["(", ")"] 85 | data.insert(1, "".join(["{}".format(arg) for arg in marker_data])) 86 | return "".join(data) 87 | 88 | @format_marker.register(dict) 89 | def _(self, marker_data): 90 | data = ["(", ")"] 91 | data.insert( 92 | 1, 93 | "".join(["{}={}".format(key, value) for key, value in marker_data.items()]), 94 | ) 95 | return "".join(data) 96 | 97 | def marker_details(self, marker): 98 | args = kwargs = "" 99 | if marker.args: 100 | args = self.format_marker(marker.args) 101 | 102 | if marker.kwargs: 103 | kwargs = self.format_marker(marker.kwargs) 104 | 105 | out = [marker.name, args, kwargs] 106 | return " ".join(out).strip() 107 | 108 | @methdispatch 109 | def get_marker(self, marker): 110 | return self.marker_details(marker) 111 | 112 | @get_marker.register(MarkDecorator) 113 | def _(self, marker): 114 | return self.marker_details(marker.mark) 115 | 116 | def add(self, element: "Element") -> "Element": 117 | if element not in self.children: 118 | element.parent = self 119 | self.children.append(element) 120 | return self.children[self.children.index(element)] 121 | 122 | def format_markers(self, markers): 123 | return [self.get_marker(marker) for marker in markers] 124 | 125 | @methdispatch 126 | def element_markers(self, element): 127 | markers = getattr(element, "pytestmark", []) 128 | if not isinstance(markers, list): 129 | markers = [markers] 130 | return markers 131 | 132 | @element_markers.register(Function) 133 | def _(self, element): 134 | return element.own_markers 135 | 136 | @methdispatch 137 | def unique_identifier(self, element): 138 | if not element: 139 | return None 140 | qualname = getattr(element, "__qualname__", None) 141 | source_file = inspect.getsourcefile(element) 142 | if qualname: 143 | return "{}/{}".format(source_file, qualname) 144 | return source_file 145 | 146 | @unique_identifier.register(Function) 147 | def _(self, element): 148 | return element.nodeid 149 | 150 | @property 151 | def markers(self) -> list: 152 | return self.format_markers(self.raw_markers) 153 | 154 | @property 155 | def name(self) -> str: 156 | for marker in self.raw_markers: 157 | if marker.name == PYTEST_DOC_MARKER: 158 | return marker.kwargs["name"] 159 | return self.raw_name 160 | 161 | def __repr__(self): 162 | return "".format(self.name) 163 | 164 | def __str__(self): 165 | return self.name 166 | 167 | def __hash__(self): 168 | return hash(self.unique_id) 169 | 170 | def __eq__(self, other): 171 | if not isinstance(other, Element): 172 | raise TypeError 173 | return self.unique_id == other.unique_id 174 | -------------------------------------------------------------------------------- /pytest_docs/formatter.py: -------------------------------------------------------------------------------- 1 | from itertools import chain 2 | 3 | from .element import Element 4 | 5 | 6 | class Formatter: 7 | """Build the output document from an :class:`Element`""" 8 | 9 | name = None 10 | 11 | @staticmethod 12 | def _default_format(element) -> str: 13 | return element 14 | 15 | module_name_format = _default_format 16 | module_desc_format = _default_format 17 | class_name_format = _default_format 18 | class_desc_format = _default_format 19 | func_name_format = _default_format 20 | func_desc_format = _default_format 21 | marker_format = _default_format 22 | marker_prefix = "Markers" 23 | 24 | def create_document(self, doc_tree: Element) -> str: 25 | """Iterates over the elements and generates an hierarchical document structure""" 26 | out = [] 27 | for module in doc_tree: 28 | out += self._doc_element( 29 | module, self.module_name_format, self.module_desc_format 30 | ) 31 | for class_ in module: 32 | out += self._doc_element( 33 | class_, self.class_name_format, self.class_desc_format 34 | ) 35 | for func in class_: 36 | out += self._doc_element( 37 | func, self.func_name_format, self.func_desc_format 38 | ) 39 | return "".join(out).lstrip("\n") 40 | 41 | def _element_markers(self, element: Element) -> list: 42 | marker_doc = [] 43 | if element.markers: 44 | marker_doc.append(self.marker_prefix) 45 | for marker in element.markers: 46 | marker_doc.append(self.marker_format(marker)) 47 | return marker_doc 48 | 49 | def _doc_element(self, element, element_name_fmt, element_desc_fmt) -> list: 50 | element_doc = [element_name_fmt(element.name)] 51 | if element.desc: 52 | element_doc.append(element_desc_fmt(element.desc)) 53 | element_doc += self._element_markers(element) 54 | element_doc = self._add_new_lines(element_doc) 55 | return element_doc 56 | 57 | @staticmethod 58 | def _add_new_lines(element_doc: list) -> list: 59 | """Adds a new line between each element""" 60 | return list(chain.from_iterable(zip(element_doc, ["\n" for _ in element_doc]))) 61 | -------------------------------------------------------------------------------- /pytest_docs/formatters/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liiight/pytest-docs/bdbd7b3e83f16582cadb66e54aea8070becf3e99/pytest_docs/formatters/__init__.py -------------------------------------------------------------------------------- /pytest_docs/formatters/markdown.py: -------------------------------------------------------------------------------- 1 | from pytest_docs.formatter import Formatter 2 | 3 | 4 | class MarkdownFormatter(Formatter): 5 | name = "md" 6 | marker_prefix = "\n**Markers:**" 7 | 8 | @staticmethod 9 | def module_name_format(element): 10 | return "# {}".format(element) 11 | 12 | @staticmethod 13 | def class_name_format(element): 14 | return "## {}".format(element) 15 | 16 | @staticmethod 17 | def func_name_format(element): 18 | return "### {}".format(element) 19 | 20 | @staticmethod 21 | def marker_format(marker): 22 | return "- {}".format(marker) 23 | -------------------------------------------------------------------------------- /pytest_docs/formatters/restuctured.py: -------------------------------------------------------------------------------- 1 | from pytest_docs.formatter import Formatter 2 | 3 | 4 | class RSTFormatter(Formatter): 5 | name = "rst" 6 | marker_prefix = "\n**Markers:**" 7 | 8 | @staticmethod 9 | def module_name_format(element): 10 | return "\n{}\n{}".format(element, "*" * len(element)) 11 | 12 | @staticmethod 13 | def class_name_format(element): 14 | return "\n{}\n{}".format(element, "-" * len(element)) 15 | 16 | @staticmethod 17 | def func_name_format(element): 18 | return "\n{}\n{}".format(element, "=" * len(element)) 19 | 20 | @staticmethod 21 | def marker_format(marker): 22 | return "\n- {}".format(marker) 23 | -------------------------------------------------------------------------------- /pytest_docs/plugin.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | from .element import Element 4 | from .formatters.markdown import MarkdownFormatter 5 | from .formatters.restuctured import RSTFormatter 6 | 7 | FORMATTERS = { 8 | MarkdownFormatter.name: MarkdownFormatter(), 9 | RSTFormatter.name: RSTFormatter(), 10 | } 11 | 12 | 13 | class DocPlugin: 14 | def __init__(self, path, format_type): 15 | self.path = path 16 | self.format_type = format_type 17 | 18 | def pytest_runtestloop(self, session): 19 | doc_tree = Element.create_doc_tree(session.items) 20 | 21 | fmt = FORMATTERS[self.format_type] 22 | out = fmt.create_document(doc_tree) 23 | 24 | with Path(self.path).open("w", encoding="utf-8") as file: 25 | file.write(out) 26 | 27 | def pytest_terminal_summary(self, terminalreporter, exitstatus): 28 | terminalreporter.write_sep("-", "generated doc file: {}".format(self.path)) 29 | 30 | 31 | def pytest_addoption(parser): 32 | group = parser.getgroup("docs generator") 33 | group.addoption("--docs", dest="docs_path", help="create documentation given path") 34 | group.addoption( 35 | "--doc-type", 36 | dest="docs_type", 37 | default="md", 38 | help="Choose document type", 39 | choices=list(FORMATTERS), 40 | ) 41 | 42 | 43 | def pytest_configure(config): 44 | path = config.getoption("docs_path") 45 | if path: 46 | format_type = config.getoption("docs_type") 47 | config.pluginmanager.register(DocPlugin(path, format_type), "pytest-docs") 48 | -------------------------------------------------------------------------------- /pytest_docs/utils.py: -------------------------------------------------------------------------------- 1 | from functools import singledispatch, update_wrapper 2 | 3 | 4 | # thanks to https://stackoverflow.com/a/24602374 5 | def methdispatch(func): 6 | dispatcher = singledispatch(func) 7 | 8 | def wrapper(*args, **kw): 9 | return dispatcher.dispatch(args[1].__class__)(*args, **kw) 10 | 11 | wrapper.register = dispatcher.register 12 | update_wrapper(wrapper, func) 13 | return wrapper 14 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import codecs 5 | import os 6 | 7 | from setuptools import setup, find_packages 8 | 9 | 10 | def read(fname): 11 | file_path = os.path.join(os.path.dirname(__file__), fname) 12 | return codecs.open(file_path, encoding="utf-8").read() 13 | 14 | 15 | setup( 16 | name="pytest-docs", 17 | version="0.1.0", 18 | author="Or Carmi", 19 | author_email="or.carmi82@gmail.com", 20 | maintainer="Or Carmi", 21 | maintainer_email="or.carmi82@gmail.com", 22 | license="MIT", 23 | url="https://github.com/liiight/pytest-docs", 24 | description="Documentation tool for pytest", 25 | long_description=read("README.rst"), 26 | python_requires=">=3.4", 27 | install_requires=["pytest>=3.5.0"], 28 | packages=find_packages(exclude=["pytest_docs.tests"]), 29 | classifiers=[ 30 | "Development Status :: 4 - Beta", 31 | "Framework :: Pytest", 32 | "Intended Audience :: Developers", 33 | "Topic :: Software Development :: Testing", 34 | "Programming Language :: Python", 35 | "Programming Language :: Python :: 3", 36 | "Programming Language :: Python :: 3.4", 37 | "Programming Language :: Python :: 3.5", 38 | "Programming Language :: Python :: 3.6", 39 | "Programming Language :: Python :: 3.7", 40 | "Programming Language :: Python :: Implementation :: CPython", 41 | "Operating System :: OS Independent", 42 | "License :: OSI Approved :: MIT License", 43 | ], 44 | entry_points={"pytest11": ["docs = pytest_docs.plugin"]}, 45 | ) 46 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pathlib import Path 3 | 4 | BASE_PATH = Path(__file__).parent 5 | OUTPUT_PATH = BASE_PATH / "output" 6 | 7 | pytest_plugins = "pytester" 8 | 9 | 10 | @pytest.fixture 11 | def expected_output(): 12 | def _(file_name): 13 | path = OUTPUT_PATH / file_name 14 | with path.open() as file: 15 | return file.read() 16 | 17 | return _ 18 | -------------------------------------------------------------------------------- /tests/output/markdown_sanity.md: -------------------------------------------------------------------------------- 1 | # Test Docs 2 | This is the module doc 3 | 4 | **Markers:** 5 | - module_mark 6 | - module_mark_2 7 | - pytest_doc (name=Test Docs) 8 | ## Test Class 9 | This is the class doc 10 | 11 | **Markers:** 12 | - pytest_doc (name=Test Class) 13 | - class_marker 14 | ### test_func_a 15 | This is the doc for test_func_a 16 | 17 | **Markers:** 18 | - func_mark_a (foo) 19 | ### test_func_b 20 | This is the doc for test_func_b 21 | 22 | **Markers:** 23 | - kwarg_mark (goo=bla) 24 | -------------------------------------------------------------------------------- /tests/output/rst_sanity.rst: -------------------------------------------------------------------------------- 1 | Test Docs 2 | ********* 3 | This is the module doc 4 | 5 | **Markers:** 6 | 7 | - module_mark 8 | 9 | - module_mark_2 10 | 11 | - pytest_doc (name=Test Docs) 12 | 13 | Test Class 14 | ---------- 15 | This is the class doc 16 | 17 | **Markers:** 18 | 19 | - pytest_doc (name=Test Class) 20 | 21 | - class_marker 22 | 23 | test_func_a 24 | =========== 25 | This is the doc for test_func_a 26 | 27 | **Markers:** 28 | 29 | - func_mark_a (foo) 30 | 31 | test_func_b 32 | =========== 33 | This is the doc for test_func_b 34 | 35 | **Markers:** 36 | 37 | - kwarg_mark (goo=bla) 38 | -------------------------------------------------------------------------------- /tests/test_pytest_docs.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | TEST_SUITE = """ 4 | '''This is the module doc''' 5 | import pytest 6 | 7 | pytestmark = [ 8 | pytest.mark.module_mark, 9 | pytest.mark.module_mark_2, 10 | pytest.mark.pytest_doc(name="Test Docs"), 11 | ] 12 | 13 | 14 | @pytest.mark.class_marker 15 | @pytest.mark.pytest_doc(name="Test Class") 16 | class TestClass: 17 | '''This is the class doc''' 18 | 19 | @pytest.mark.func_mark_a("foo") 20 | def test_func_a(self): 21 | '''This is the doc for test_func_a''' 22 | assert 1 23 | 24 | @pytest.mark.kwarg_mark(goo="bla") 25 | def test_func_b(self): 26 | '''This is the doc for test_func_b''' 27 | assert 1 28 | """ 29 | 30 | 31 | @pytest.mark.parametrize( 32 | "file_type, expected_file", 33 | [("md", "markdown_sanity.md"), ("rst", "rst_sanity.rst")], 34 | ) 35 | def test_formatter_sanity(testdir, tmpdir, file_type, expected_file, expected_output): 36 | path = tmpdir.join("doc.{}".format(file_type)) 37 | testdir.makepyfile(TEST_SUITE) 38 | testdir.runpytest("--docs", str(path), "--doc-type", file_type) 39 | assert path.read() == expected_output(expected_file) 40 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # For more information about tox, see https://tox.readthedocs.io/en/latest/ 2 | [tox] 3 | envlist = py34,py35,py36,py37 4 | 5 | [testenv] 6 | passenv = CI TRAVIS TRAVIS_* 7 | deps = 8 | pytest>=3.5.0 9 | codecov 10 | commands = 11 | coverage run --source pytest_docs -m py.test 12 | coverage report 13 | -------------------------------------------------------------------------------- /venv/bin/activate: -------------------------------------------------------------------------------- 1 | # This file must be used with "source bin/activate" *from bash* 2 | # you cannot run it directly 3 | 4 | deactivate () { 5 | # reset old environment variables 6 | if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then 7 | PATH="${_OLD_VIRTUAL_PATH:-}" 8 | export PATH 9 | unset _OLD_VIRTUAL_PATH 10 | fi 11 | if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then 12 | PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" 13 | export PYTHONHOME 14 | unset _OLD_VIRTUAL_PYTHONHOME 15 | fi 16 | 17 | # This should detect bash and zsh, which have a hash command that must 18 | # be called to get it to forget past commands. Without forgetting 19 | # past commands the $PATH changes we made may not be respected 20 | if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then 21 | hash -r 22 | fi 23 | 24 | if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then 25 | PS1="${_OLD_VIRTUAL_PS1:-}" 26 | export PS1 27 | unset _OLD_VIRTUAL_PS1 28 | fi 29 | 30 | unset VIRTUAL_ENV 31 | if [ ! "$1" = "nondestructive" ] ; then 32 | # Self destruct! 33 | unset -f deactivate 34 | fi 35 | } 36 | 37 | # unset irrelevant variables 38 | deactivate nondestructive 39 | 40 | VIRTUAL_ENV="/Users/orcarmi/PycharmProjects/pytest-docs/venv" 41 | export VIRTUAL_ENV 42 | 43 | _OLD_VIRTUAL_PATH="$PATH" 44 | PATH="$VIRTUAL_ENV/bin:$PATH" 45 | export PATH 46 | 47 | # unset PYTHONHOME if set 48 | # this will fail if PYTHONHOME is set to the empty string (which is bad anyway) 49 | # could use `if (set -u; : $PYTHONHOME) ;` in bash 50 | if [ -n "${PYTHONHOME:-}" ] ; then 51 | _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" 52 | unset PYTHONHOME 53 | fi 54 | 55 | if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then 56 | _OLD_VIRTUAL_PS1="${PS1:-}" 57 | if [ "x(venv) " != x ] ; then 58 | PS1="(venv) ${PS1:-}" 59 | else 60 | if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then 61 | # special case for Aspen magic directories 62 | # see http://www.zetadev.com/software/aspen/ 63 | PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1" 64 | else 65 | PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1" 66 | fi 67 | fi 68 | export PS1 69 | fi 70 | 71 | # This should detect bash and zsh, which have a hash command that must 72 | # be called to get it to forget past commands. Without forgetting 73 | # past commands the $PATH changes we made may not be respected 74 | if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then 75 | hash -r 76 | fi 77 | -------------------------------------------------------------------------------- /venv/bin/activate.csh: -------------------------------------------------------------------------------- 1 | # This file must be used with "source bin/activate.csh" *from csh*. 2 | # You cannot run it directly. 3 | # Created by Davide Di Blasi . 4 | # Ported to Python 3.3 venv by Andrew Svetlov 5 | 6 | alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate' 7 | 8 | # Unset irrelevant variables. 9 | deactivate nondestructive 10 | 11 | setenv VIRTUAL_ENV "/Users/orcarmi/PycharmProjects/pytest-docs/venv" 12 | 13 | set _OLD_VIRTUAL_PATH="$PATH" 14 | setenv PATH "$VIRTUAL_ENV/bin:$PATH" 15 | 16 | 17 | set _OLD_VIRTUAL_PROMPT="$prompt" 18 | 19 | if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then 20 | if ("venv" != "") then 21 | set env_name = "venv" 22 | else 23 | if (`basename "VIRTUAL_ENV"` == "__") then 24 | # special case for Aspen magic directories 25 | # see http://www.zetadev.com/software/aspen/ 26 | set env_name = `basename \`dirname "$VIRTUAL_ENV"\`` 27 | else 28 | set env_name = `basename "$VIRTUAL_ENV"` 29 | endif 30 | endif 31 | set prompt = "[$env_name] $prompt" 32 | unset env_name 33 | endif 34 | 35 | alias pydoc python -m pydoc 36 | 37 | rehash 38 | -------------------------------------------------------------------------------- /venv/bin/activate.fish: -------------------------------------------------------------------------------- 1 | # This file must be used with ". bin/activate.fish" *from fish* (http://fishshell.org) 2 | # you cannot run it directly 3 | 4 | function deactivate -d "Exit virtualenv and return to normal shell environment" 5 | # reset old environment variables 6 | if test -n "$_OLD_VIRTUAL_PATH" 7 | set -gx PATH $_OLD_VIRTUAL_PATH 8 | set -e _OLD_VIRTUAL_PATH 9 | end 10 | if test -n "$_OLD_VIRTUAL_PYTHONHOME" 11 | set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME 12 | set -e _OLD_VIRTUAL_PYTHONHOME 13 | end 14 | 15 | if test -n "$_OLD_FISH_PROMPT_OVERRIDE" 16 | functions -e fish_prompt 17 | set -e _OLD_FISH_PROMPT_OVERRIDE 18 | functions -c _old_fish_prompt fish_prompt 19 | functions -e _old_fish_prompt 20 | end 21 | 22 | set -e VIRTUAL_ENV 23 | if test "$argv[1]" != "nondestructive" 24 | # Self destruct! 25 | functions -e deactivate 26 | end 27 | end 28 | 29 | # unset irrelevant variables 30 | deactivate nondestructive 31 | 32 | set -gx VIRTUAL_ENV "/Users/orcarmi/PycharmProjects/pytest-docs/venv" 33 | 34 | set -gx _OLD_VIRTUAL_PATH $PATH 35 | set -gx PATH "$VIRTUAL_ENV/bin" $PATH 36 | 37 | # unset PYTHONHOME if set 38 | if set -q PYTHONHOME 39 | set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME 40 | set -e PYTHONHOME 41 | end 42 | 43 | if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" 44 | # fish uses a function instead of an env var to generate the prompt. 45 | 46 | # save the current fish_prompt function as the function _old_fish_prompt 47 | functions -c fish_prompt _old_fish_prompt 48 | 49 | # with the original prompt function renamed, we can override with our own. 50 | function fish_prompt 51 | # Save the return status of the last command 52 | set -l old_status $status 53 | 54 | # Prompt override? 55 | if test -n "(venv) " 56 | printf "%s%s" "(venv) " (set_color normal) 57 | else 58 | # ...Otherwise, prepend env 59 | set -l _checkbase (basename "$VIRTUAL_ENV") 60 | if test $_checkbase = "__" 61 | # special case for Aspen magic directories 62 | # see http://www.zetadev.com/software/aspen/ 63 | printf "%s[%s]%s " (set_color -b blue white) (basename (dirname "$VIRTUAL_ENV")) (set_color normal) 64 | else 65 | printf "%s(%s)%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal) 66 | end 67 | end 68 | 69 | # Restore the return status of the previous command. 70 | echo "exit $old_status" | . 71 | _old_fish_prompt 72 | end 73 | 74 | set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" 75 | end 76 | -------------------------------------------------------------------------------- /venv/bin/easy_install: -------------------------------------------------------------------------------- 1 | #!/Users/orcarmi/PycharmProjects/pytest-docs/venv/bin/python 2 | # EASY-INSTALL-ENTRY-SCRIPT: 'setuptools==39.1.0','console_scripts','easy_install' 3 | __requires__ = "setuptools==39.1.0" 4 | import re 5 | import sys 6 | from pkg_resources import load_entry_point 7 | 8 | if __name__ == "__main__": 9 | sys.argv[0] = re.sub(r"(-script\.pyw?|\.exe)?$", "", sys.argv[0]) 10 | sys.exit( 11 | load_entry_point("setuptools==39.1.0", "console_scripts", "easy_install")() 12 | ) 13 | -------------------------------------------------------------------------------- /venv/bin/easy_install-3.7: -------------------------------------------------------------------------------- 1 | #!/Users/orcarmi/PycharmProjects/pytest-docs/venv/bin/python 2 | # EASY-INSTALL-ENTRY-SCRIPT: 'setuptools==39.1.0','console_scripts','easy_install-3.7' 3 | __requires__ = "setuptools==39.1.0" 4 | import re 5 | import sys 6 | from pkg_resources import load_entry_point 7 | 8 | if __name__ == "__main__": 9 | sys.argv[0] = re.sub(r"(-script\.pyw?|\.exe)?$", "", sys.argv[0]) 10 | sys.exit( 11 | load_entry_point("setuptools==39.1.0", "console_scripts", "easy_install-3.7")() 12 | ) 13 | -------------------------------------------------------------------------------- /venv/bin/pip: -------------------------------------------------------------------------------- 1 | #!/Users/orcarmi/PycharmProjects/pytest-docs/venv/bin/python 2 | 3 | # -*- coding: utf-8 -*- 4 | import re 5 | import sys 6 | 7 | from pip._internal import main 8 | 9 | if __name__ == "__main__": 10 | sys.argv[0] = re.sub(r"(-script\.pyw?|\.exe)?$", "", sys.argv[0]) 11 | sys.exit(main()) 12 | -------------------------------------------------------------------------------- /venv/bin/pip3: -------------------------------------------------------------------------------- 1 | #!/Users/orcarmi/PycharmProjects/pytest-docs/venv/bin/python 2 | 3 | # -*- coding: utf-8 -*- 4 | import re 5 | import sys 6 | 7 | from pip._internal import main 8 | 9 | if __name__ == "__main__": 10 | sys.argv[0] = re.sub(r"(-script\.pyw?|\.exe)?$", "", sys.argv[0]) 11 | sys.exit(main()) 12 | -------------------------------------------------------------------------------- /venv/bin/pip3.7: -------------------------------------------------------------------------------- 1 | #!/Users/orcarmi/PycharmProjects/pytest-docs/venv/bin/python 2 | 3 | # -*- coding: utf-8 -*- 4 | import re 5 | import sys 6 | 7 | from pip._internal import main 8 | 9 | if __name__ == "__main__": 10 | sys.argv[0] = re.sub(r"(-script\.pyw?|\.exe)?$", "", sys.argv[0]) 11 | sys.exit(main()) 12 | -------------------------------------------------------------------------------- /venv/bin/py.test: -------------------------------------------------------------------------------- 1 | #!/Users/orcarmi/PycharmProjects/pytest-docs/venv/bin/python 2 | 3 | # -*- coding: utf-8 -*- 4 | import re 5 | import sys 6 | 7 | from pytest import main 8 | 9 | if __name__ == "__main__": 10 | sys.argv[0] = re.sub(r"(-script\.pyw?|\.exe)?$", "", sys.argv[0]) 11 | sys.exit(main()) 12 | -------------------------------------------------------------------------------- /venv/bin/pytest: -------------------------------------------------------------------------------- 1 | #!/Users/orcarmi/PycharmProjects/pytest-docs/venv/bin/python 2 | 3 | # -*- coding: utf-8 -*- 4 | import re 5 | import sys 6 | 7 | from pytest import main 8 | 9 | if __name__ == "__main__": 10 | sys.argv[0] = re.sub(r"(-script\.pyw?|\.exe)?$", "", sys.argv[0]) 11 | sys.exit(main()) 12 | -------------------------------------------------------------------------------- /venv/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liiight/pytest-docs/bdbd7b3e83f16582cadb66e54aea8070becf3e99/venv/bin/python -------------------------------------------------------------------------------- /venv/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liiight/pytest-docs/bdbd7b3e83f16582cadb66e54aea8070becf3e99/venv/bin/python3 -------------------------------------------------------------------------------- /venv/bin/python3.7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liiight/pytest-docs/bdbd7b3e83f16582cadb66e54aea8070becf3e99/venv/bin/python3.7 -------------------------------------------------------------------------------- /venv/pip-selfcheck.json: -------------------------------------------------------------------------------- 1 | {"last_check":"2018-11-01T13:16:16Z","pypi_version":"18.1"} -------------------------------------------------------------------------------- /venv/pyvenv.cfg: -------------------------------------------------------------------------------- 1 | home = /usr/local/bin 2 | include-system-site-packages = false 3 | version = 3.7.0 4 | --------------------------------------------------------------------------------