pax_global_header00006660000000000000000000000064144065454600014522gustar00rootroot0000000000000052 comment=28492af5bba1da3a2bed19389f96584e51c1e08f pytest-cookies-0.7.0/000077500000000000000000000000001440654546000145105ustar00rootroot00000000000000pytest-cookies-0.7.0/.github/000077500000000000000000000000001440654546000160505ustar00rootroot00000000000000pytest-cookies-0.7.0/.github/workflows/000077500000000000000000000000001440654546000201055ustar00rootroot00000000000000pytest-cookies-0.7.0/.github/workflows/run-checks.yml000066400000000000000000000021221440654546000226670ustar00rootroot00000000000000name: Run checks on: push: branches: [ "main" ] pull_request: branches: [ "main" ] permissions: contents: read jobs: tox: strategy: fail-fast: false matrix: os: ["ubuntu-latest", "macos-latest", "windows-latest"] environment: ["py37", "py38", "py39", "py310", "py311", "flake8"] include: - environment: "py37" python: "3.7" - environment: "py38" python: "3.8" - environment: "py39" python: "3.9" - environment: "py310" python: "3.10" - environment: "py311" python: "3.11" - environment: "flake8" python: "3.7" runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} - name: Install tox run: | python -m pip install --upgrade pip python -m pip install tox - name: Run tox run: | tox -e ${{ matrix.environment }} pytest-cookies-0.7.0/.github/workflows/upload-to-pypi.yml000066400000000000000000000012501440654546000235110ustar00rootroot00000000000000name: Upload to PyPI on: release: types: [published] permissions: contents: read jobs: upload: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install dependencies run: | python -m pip install --upgrade pip python -m pip install setuptools wheel twine - name: Package project run: | python setup.py sdist bdist_wheel - name: Upload distributions env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} run: | twine upload dist/* pytest-cookies-0.7.0/.gitignore000066400000000000000000000023061440654546000165010ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # pyenv .python-version # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ # VS Code .vscode pytest-cookies-0.7.0/CODE_OF_CONDUCT.md000066400000000000000000000064301440654546000173120ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at raphael@hackebrot.de. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq pytest-cookies-0.7.0/COMMUNITY.md000066400000000000000000000014631440654546000164220ustar00rootroot00000000000000# Maintainers - [@hackebrot] - [@michaeljoseph] [@hackebrot]: https://github.com/hackebrot [@michaeljoseph]: https://github.com/michaeljoseph # Contributors - [@insspb] - [@jakirkham] - [@jamesmyatt] - [@jayvdb] - [@jsmedmar] - [@jyrno42] - [@nedbat] - [@obestwalter] - [@pydanny] - [@sobolevn] - [@JonZeolla] - [@hoefling] [@insspb]: https://github.com/insspb [@jakirkham]: https://github.com/jakirkham [@jamesmyatt]: https://github.com/jamesmyatt [@jsmedmar]: https://github.com/jsmedmar [@jyrno42]: https://github.com/Jyrno42 [@nedbat]: https://github.com/nedbat [@obestwalter]: https://github.com/obestwalter [@pydanny]: https://github.com/pydanny [@jayvdb]: https://github.com/jayvdb [@sobolevn]: https://github.com/sobolevn [@JonZeolla]: https://github.com/JonZeolla [@hoefling]: https://github.com/hoefling pytest-cookies-0.7.0/CONTRIBUTING.md000066400000000000000000000136021440654546000167430ustar00rootroot00000000000000# Contributing Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given. You can contribute in many ways: ## Types of Contributions ### Report Bugs Report bugs at [pytest-cookies/issues][issues]. If you are reporting a bug, please include: * Your operating system name and version. * Any details about your local setup that might be helpful in troubleshooting. * Detailed steps to reproduce the bug. [issues]: https://github.com/hackebrot/pytest-cookies/issues ### Fix Bugs Look through the GitHub issues for bugs. Anything tagged with [bug][bug] and [help wanted][help wanted] is open to whoever wants to implement a fix for it. [help wanted]: https://github.com/hackebrot/pytest-cookies/labels/help%20wanted [bug]: https://github.com/hackebrot/pytest-cookies/labels/bug ### Implement Features Look through the GitHub issues for features. Anything tagged with [enhancement][enhancement] and [help wanted][help wanted] is open to whoever wants to implement it. [enhancement]: https://github.com/hackebrot/pytest-cookies/labels/enhancement [help wanted]: https://github.com/hackebrot/pytest-cookies/labels/help%20wanted ### Write Documentation **pytest-cookies** could always use more documentation, whether as part of the official docs, in docstrings, or even on the web in blog posts, articles, and such. ### Submit Feedback The best way to send feedback is to [file an issue][issues]. If you are proposing a new feature: * Explain in detail how it would work. * Keep the scope as narrow as possible, to make it easier to implement. * Remember that this is a volunteer-driven project, and that contributions are welcome :) [issues]: https://github.com/hackebrot/pytest-cookies/issues ## Get Started! Ready to contribute? Here's how to set up **pytest-cookies** for local development. Please note this documentation assumes you already have [virtualenv][virtualenv] and [git][git] installed and ready to go. 1. [Fork][fork] the **pytest-cookies** repo on GitHub. 2. Clone your fork locally: ```bash $ git clone https://github.com/YOUR-USERNAME/pytest-cookies ``` 3. Assuming you have virtualenv installed (If you have Python 3.6 this should already be there), you can create a new environment for your local development by typing: ``` bash $ python -m venv pytest-cookies-env $ source pytest-cookies-env/bin/activate ``` This should change the shell to look something like ``(pytest-cookies-env) $`` 4. Create a branch for local development: ``` bash $ git checkout -b name-of-your-bugfix-or-feature ``` 5. Now you can make your changes locally.When you're done making changes, use [tox][tox] to run checks against your changes. Install it as follows: ``` bash $ pip install tox ``` 6. First you want to make sure that your branch passes [flake8][flake8]. ``` bash $ tox -e flake8 ``` 7. The next step would be to run the tests against your environment (the special tox environment ``py`` refers to the currently active python environment): ``` bash $ tox -e py ``` 8. Before raising any pull request you should run tox. This will run the tests across different versions of Python: ``` bash $ tox ``` 9. If your contribution is a bug fix or new feature, you may want to add a test to the existing test suite. See section *Add a New Test* below for details. 10. Commit your changes and push your branch to GitHub: ``` bash $ git add . $ git commit -m "Your detailed description of your changes." $ git push origin name-of-your-bugfix-or-feature ``` 11. Submit a pull request through the GitHub website. [clone]: https://help.github.com/articles/fork-a-repo/#step-2-create-a-local-clone-of-your-fork [flake8]: https://pypi.python.org/pypi/flake8 [fork]: https://help.github.com/articles/fork-a-repo/ [git]: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git [tox]: https://pypi.python.org/pypi/tox [virtualenv]: https://virtualenv.pypa.io/en/stable/installation Pull Request Guidelines ----------------------- Before you submit a pull request, check that it meets these guidelines: 1. The pull request should include tests. 2. If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.md. 3. The pull request should work for Python 3.6, 3.7, 3.8 and 3.9. Add a New Test --------------- When fixing a bug or adding features, it's good practice to add a test to demonstrate your fix or new feature behaves as expected. These tests should focus on one tiny bit of functionality and prove changes are correct. To write and run your new test, follow these steps: 1. Add the new test to ``tests/test_.py``. Focus your test on the specific bug or a small part of the new feature. 2. If you have already made changes to the code, stash your changes and confirm all your changes were stashed: ``` bash $ git stash $ git stash list ``` 3. Run your test and confirm that your test fails. If your test does not fail, rewrite the test until it fails on the original code: ``` bash $ tox -e py ``` 4. (Optional) Run the tests with tox to ensure that the code changes work with different Python versions: ``` bash $ tox ``` 5. Proceed work on your bug fix or new feature or restore your changes. To restore your stashed changes and confirm their restoration: ``` bash $ git stash pop $ git stash list ``` 6. Rerun your test and confirm that your test passes. If it passes, congratulations! [bug]: https://github.com/hackebrot/pytest-cookies/labels/bug [enhancement]: https://github.com/hackebrot/pytest-cookies/labels/enhancement [help wanted]: https://github.com/hackebrot/pytest-cookies/labels/help%20wanted [issues]: https://github.com/hackebrot/pytest-cookies/issues pytest-cookies-0.7.0/LICENSE000066400000000000000000000020721440654546000155160ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 Raphael Pierzina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.pytest-cookies-0.7.0/MANIFEST.in000066400000000000000000000002151440654546000162440ustar00rootroot00000000000000include COMMUNITY.md include CONTRIBUTING.md include LICENSE include README.md recursive-exclude * __pycache__ recursive-exclude * *.py[co] pytest-cookies-0.7.0/Makefile000066400000000000000000000015301440654546000161470ustar00rootroot00000000000000.DEFAULT_GOAL := help .PHONY: clean clean: clean-tox clean-build clean-pyc ## Remove all file artifacts .PHONY: clean-tox clean-tox: ## Remove tox testing artifacts @echo "+ $@" @rm -rf .tox/ .PHONY: clean-build clean-build: ## Remove build artifacts @echo "+ $@" @rm -fr build/ @rm -fr dist/ @rm -fr *.egg-info .PHONY: clean-pyc clean-pyc: ## Remove Python file artifacts @echo "+ $@" @find . -type f -name "*.py[co]" -delete @find . -type d -name "__pycache__" -delete @find . -name '*~' -delete .PHONY: test test: ## Run tests quickly with the default Python @echo "+ $@" @tox -e py .PHONY: test-all test-all: ## Run tests on every Python version with tox @echo "+ $@" @tox .PHONY: help help: @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-16s\033[0m %s\n", $$1, $$2}' pytest-cookies-0.7.0/README.md000066400000000000000000000115011440654546000157650ustar00rootroot00000000000000# pytest-cookies [pytest][pytest] is a mature testing framework for Python that is developed by a thriving and ever-growing community of volunteers. It uses plain assert statements and regular Python comparisons. At the core of the pytest test framework is a powerful hook-based plugin system. **pytest-cookies** is a pytest plugin that comes with a ``cookies`` fixture which is a wrapper for the [cookiecutter][cookiecutter] API for generating projects. It helps you verify that your template is working as expected and takes care of cleaning up after running the tests. 🍪 # Installation **pytest-cookies** is available for download from [PyPI][pypi] via [pip][pip]: ```text pip install pytest-cookies ``` This will automatically install [pytest][pytest] and [cookiecutter][cookiecutter]. # Usage ## Generate a new project The ``cookies.bake()`` method generates a new project from your template based on the default values specified in ``cookiecutter.json``: ```python def test_bake_project(cookies): result = cookies.bake(extra_context={"repo_name": "helloworld"}) assert result.exit_code == 0 assert result.exception is None assert result.project_path.name == "helloworld" assert result.project_path.is_dir() # The `project` attribute is deprecated assert result.project.basename == "helloworld" assert result.project.isdir() ``` **Please note that the `project` attribute of the returned `Result` class is deprecated and will be removed in a future release, please use `project_path` instead.** The ``cookies.bake()`` method also accepts the ``extra_context`` keyword argument that will be passed to cookiecutter. The given dictionary will override the default values of the template context, effectively allowing you to test arbitrary user input data. For more information on injecting extra context, please check out the [cookiecutter documentation][extra-context]. ## Specify the template directory By default ``cookies.bake()`` looks for a cookiecutter template in the current directory. This can be overridden on the command line by passing a ``--template`` parameter to pytest: ```text pytest --template TEMPLATE ``` You can customize the cookiecutter template directory from a test by passing in the optional ``template`` paramter: ```python @pytest.fixture def custom_template(tmpdir): template = tmpdir.ensure("cookiecutter-template", dir=True) template.join("cookiecutter.json").write('{"repo_name": "example-project"}') repo_dir = template.ensure("{{cookiecutter.repo_name}}", dir=True) repo_dir.join("README.rst").write("{{cookiecutter.repo_name}}") return template def test_bake_custom_project(cookies, custom_template): """Test for 'cookiecutter-template'.""" result = cookies.bake(template=str(custom_template)) assert result.exit_code == 0 assert result.exception is None assert result.project_path.name == "example-project" assert result.project_path.is_dir() ``` ## Keep output directories for debugging By default ``cookies`` removes baked projects. However, you can pass the ``keep-baked-projects`` flag if you'd like to keep them ([it won't clutter][temporary-directories] as pytest only keeps the three newest temporary directories): ```text pytest --keep-baked-projects ``` # Community Contributions are very welcome! If you encounter any problems, please [file an issue][new-issue] along with a detailed description. Tests can be run with [tox][tox]. Please make sure all of the tests are green before you submit a pull request. You can also support the development of this project by volunteering to become a maintainer, which means you will be able to triage issues, merge pull-requests, and publish new releases. If you're interested, please submit a pull-request to add yourself to the list of [maintainers][community] and we'll get you started! 🍪 Please note that **pytest-cookies** is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms. # License Distributed under the terms of the [MIT license][license], **pytest-cookies** is free and open source software. [cookiecutter]: https://github.com/audreyr/cookiecutter [pytest]: https://github.com/pytest-dev/pytest [pip]: https://pypi.org/project/pip/ [pypi]: https://pypi.org/project/pytest-cookies/ [extra-context]: https://cookiecutter.readthedocs.io/en/latest/advanced/injecting_context.html [temporary-directories]: https://docs.pytest.org/en/latest/tmpdir.html#the-default-base-temporary-directory [tox]: https://pypi.org/project/tox/ [new-issue]: https://github.com/hackebrot/pytest-cookies/issues [code-of-conduct]: https://github.com/hackebrot/pytest-cookies/blob/main/CODE_OF_CONDUCT.md [community]: https://github.com/hackebrot/pytest-cookies/blob/main/COMMUNITY.md [license]: https://github.com/hackebrot/pytest-cookies/blob/main/LICENSE pytest-cookies-0.7.0/docs/000077500000000000000000000000001440654546000154405ustar00rootroot00000000000000pytest-cookies-0.7.0/docs/about.md000066400000000000000000000013711440654546000170760ustar00rootroot00000000000000# Issues If you encounter any problems, please [file an issue] along with a detailed description. # Community Contributions are very welcome! Tests can be run with [tox], please make sure all of the tests are green before you submit a pull request. Please note that **pytest-cookies** is released with a [Contributor Code of Conduct][coc]. By participating in this project you agree to abide by its terms. # License Distributed under the terms of the [MIT] license, **pytest-cookies** is free and open source software [file an issue]: https://github.com/hackebrot/pytest-cookies/issues [tox]: https://tox.readthedocs.org/en/latest/ [coc]: https://github.com/hackebrot/pytest-cookies/blob/main/CODE_OF_CONDUCT.md [MIT]: http://opensource.org/licenses/MIT pytest-cookies-0.7.0/docs/features.md000066400000000000000000000015501440654546000176010ustar00rootroot00000000000000# Bake Result ``cookies.bake()`` returns a result instance with a bunch of fields that hold useful information: * ``exit_code``: is the exit code of cookiecutter, ``0`` means successful termination * ``exception``: is the exception that happened if one did * ``project_path``: a [Path] object pointing to the rendered project * ``context``: is the rendered context The [Path] instance in `project_path` provides you with a powerful interface to filesystem related information, that comes in handy for validating the generated project layout and even file contents: ```python def test_readme(cookies): result = cookies.bake() readme_file = result.project_path / "README.rst" readme_lines = readme_file.read_text().splitlines() assert readme_lines == ["helloworld", "=========="] ``` [path]: https://docs.python.org/3/library/pathlib.html#pathlib.Pathpytest-cookies-0.7.0/docs/getting_started.md000066400000000000000000000023471440654546000211570ustar00rootroot00000000000000# Installation **pytest-cookies** is available for download from [PyPI] via [pip]: ```no-highlight $ pip install pytest-cookies ``` It will automatically install [pytest] along with [cookiecutter]. [PyPI]: https://pypi.python.org/pypi [cookiecutter]: https://github.com/cookiecutter/cookiecutter [pip]: https://pypi.python.org/pypi/pip/ [pytest]: https://github.com/pytest-dev/pytest # Usage The ``cookies.bake()`` method generates a new project from your template based on the default values specified in ``cookiecutter.json``: ```python def test_bake_project(cookies): result = cookies.bake(extra_context={'repo_name': 'helloworld'}) assert result.exit_code == 0 assert result.exception is None assert result.project.basename == 'helloworld' assert result.project.isdir() ``` It accepts the ``extra_context`` keyword argument that will be passed to cookiecutter. The given dictionary will override the default values of the template context, allowing you to test arbitrary user input data. Please see the [Injecting Extra Context] section of the official cookiecutter documentation. [Injecting Extra Context]: https://cookiecutter.readthedocs.io/en/latest/advanced/injecting_context.html#injecting-extra-context pytest-cookies-0.7.0/docs/index.md000066400000000000000000000012561440654546000170750ustar00rootroot00000000000000# Welcome to pytest-cookies [pytest] is a mature full-featured Python testing tool that provides easy no boilerplate testing. Its hook-based customization system supports integration of external plugins such as **pytest-cookies**. This plugin comes with a ``cookies`` fixture which is a wrapper for the [cookiecutter] API for generating projects. It helps you verify that your template is working as expected and takes care of cleaning up after running the tests. ## GitHub Project [https://github.com/hackebrot/pytest-cookies](https://github.com/hackebrot/pytest-cookies) [pytest]: https://github.com/pytest-dev/pytest [cookiecutter]: https://github.com/cookiecutter/cookiecutter pytest-cookies-0.7.0/labels.toml000066400000000000000000000026061440654546000166530ustar00rootroot00000000000000[bug] color = "ea707a" description = "Bugs and problems with pytest-cookies" name = "bug" ["code quality"] color = "fcc4db" description = "Tasks related to linting, coding style, type checks" name = "code quality" [dependencies] color = "43a2b7" description = "Tasks related to managing dependencies" name = "dependencies" [discussion] color = "8f7ad6" description = "Issues for discussing ideas for features" name = "discussion" ["do not merge"] color = "e069aa" description = "Pull requests which must not be merged" name = "do not merge" [docs] color = "81c4e2" description = "Tasks to write and update documentation" name = "docs" [enhancement] color = "81c4e2" description = "New feature or enhancement for pytest-cookies" name = "enhancement" ["good first issue"] color = "2abf88" description = "Tasks to pick up by newcomers to pytest-cookies" name = "good first issue" ["help wanted"] color = "2abf88" description = "Tasks to pick up by newcomers to pytest-cookies" name = "help wanted" [misc] color = "f9d03b" description = "Tasks that don't fit any of the other categories" name = "misc" [project] color = "bbd1f7" description = "Tasks related to managing pytest-cookies" name = "project" [question] color = "8f7ad6" description = "Questions about pytest-cookies" name = "question" [release] color = "81c4e2" description = "Issues and pull-requests related to a new release" name = "release" pytest-cookies-0.7.0/mkdocs.yml000066400000000000000000000004651440654546000165200ustar00rootroot00000000000000site_name: pytest-cookies site_description: The pytest plugin for your Cookiecutter templates 🍪 site_author: Raphael Pierzina theme: readthedocs repo_url: https://github.com/hackebrot/pytest-cookies pages: - Home: index.md - Getting Started: getting_started.md - Features: features.md - About: about.md pytest-cookies-0.7.0/setup.cfg000066400000000000000000000001011440654546000163210ustar00rootroot00000000000000[metadata] license_file = LICENSE [flake8] max-line-length = 88 pytest-cookies-0.7.0/setup.py000066400000000000000000000036571440654546000162350ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import codecs import os import setuptools def read(fname): file_path = os.path.join(os.path.dirname(__file__), fname) return codecs.open(file_path, encoding="utf-8").read() setuptools.setup( name="pytest-cookies", version="0.7.0", author="Raphael Pierzina", author_email="raphael@hackebrot.de", maintainer="Raphael Pierzina", maintainer_email="raphael@hackebrot.de", license="MIT", url="https://github.com/hackebrot/pytest-cookies", project_urls={ "Repository": "https://github.com/hackebrot/pytest-cookies", "Issues": "https://github.com/hackebrot/pytest-cookies/issues", }, description="The pytest plugin for your Cookiecutter templates. 🍪", long_description=read("README.md"), long_description_content_type="text/markdown", packages=setuptools.find_packages("src"), package_dir={"": "src"}, include_package_data=True, zip_safe=False, python_requires=">=3.7", install_requires=[ "cookiecutter>=2.1.0", # uses pyyaml "pytest>=3.9.0", # adds tmp_path fixtures ], classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python", "Topic :: Software Development :: Testing", "Framework :: Pytest", ], entry_points={"pytest11": ["cookies = pytest_cookies.plugin"]}, keywords=["cookiecutter", "pytest"], ) pytest-cookies-0.7.0/src/000077500000000000000000000000001440654546000152775ustar00rootroot00000000000000pytest-cookies-0.7.0/src/pytest_cookies/000077500000000000000000000000001440654546000203435ustar00rootroot00000000000000pytest-cookies-0.7.0/src/pytest_cookies/__init__.py000066400000000000000000000000001440654546000224420ustar00rootroot00000000000000pytest-cookies-0.7.0/src/pytest_cookies/plugin.py000066400000000000000000000133141440654546000222150ustar00rootroot00000000000000# -*- coding: utf-8 -*- import os import pathlib import warnings import py import pytest import yaml from cookiecutter.generate import generate_context from cookiecutter.main import cookiecutter from cookiecutter.prompt import prompt_for_config class Result(object): """Holds the captured result of the cookiecutter project generation.""" def __init__(self, exception=None, exit_code=0, project_dir=None, context=None): self.exception = exception self.exit_code = exit_code self.context = context self._project_dir = project_dir @property def project(self): """Return a py.path.local object if no exception occurred.""" warning_message = ( "project is deprecated and will be removed in a future release, " "please use project_path instead." ) warnings.warn( warning_message, DeprecationWarning, stacklevel=1, ) if self.exception is None: return py.path.local(self._project_dir) return None @property def project_path(self): """Return a pathlib.Path object if no exception occurred.""" if self.exception is None: return pathlib.Path(self._project_dir) return None def __repr__(self): if self.exception: return "".format(self.exception) return "".format(self.project) class Cookies(object): """Class to provide convenient access to the cookiecutter API.""" def __init__(self, template, output_factory, config_file): self._default_template = template self._output_factory = output_factory self._config_file = config_file self._counter = 0 def _new_output_dir(self): dirname = "bake{:02d}".format(self._counter) output_dir = self._output_factory(dirname) self._counter += 1 return output_dir def bake(self, extra_context=None, template=None): exception = None exit_code = 0 project_dir = None context = None if template is None: template = self._default_template context_file = pathlib.Path(template) / "cookiecutter.json" try: # Render the context, so that we can store it on the Result context = prompt_for_config( generate_context( context_file=str(context_file), extra_context=extra_context ), no_input=True, ) # Run cookiecutter to generate a new project project_dir = cookiecutter( template, no_input=True, extra_context=extra_context, output_dir=str(self._new_output_dir()), config_file=str(self._config_file), ) except SystemExit as e: if e.code != 0: exception = e exit_code = e.code except Exception as e: exception = e exit_code = -1 return Result( exception=exception, exit_code=exit_code, project_dir=project_dir, context=context, ) @pytest.fixture(scope="session") def _cookiecutter_config_file(tmpdir_factory): user_dir = tmpdir_factory.mktemp("user_dir") config_file = user_dir.join("config") config = { "cookiecutters_dir": str(user_dir.mkdir("cookiecutters")), "replay_dir": str(user_dir.mkdir("cookiecutter_replay")), } with config_file.open("w", encoding="utf-8") as f: yaml.dump(config, f, Dumper=yaml.Dumper) return config_file @pytest.fixture def cookies(request, tmpdir, _cookiecutter_config_file): """Yield an instance of the Cookies helper class that can be used to generate a project from a template. Run cookiecutter: result = cookies.bake(extra_context={ 'variable1': 'value1', 'variable2': 'value2', }) """ template_dir = request.config.option.template output_dir = tmpdir.mkdir("cookies") output_factory = output_dir.mkdir yield Cookies(template_dir, output_factory, _cookiecutter_config_file) # Add option to keep generated output directories. if not request.config.option.keep_baked_projects: output_dir.remove() @pytest.fixture(scope="session") def cookies_session(request, tmpdir_factory, _cookiecutter_config_file): """Yield an instance of the Cookies helper class that can be used to generate a project from a template. Run cookiecutter: result = cookies.bake(extra_context={ 'variable1': 'value1', 'variable2': 'value2', }) """ template_dir = request.config.option.template output_dir = tmpdir_factory.mktemp("cookies") output_factory = output_dir.mkdir yield Cookies(template_dir, output_factory, _cookiecutter_config_file) # Add option to keep generated output directories. if not request.config.option.keep_baked_projects: output_dir.remove() def pytest_addoption(parser): group = parser.getgroup("cookies") group.addoption( "--template", action="store", default=".", dest="template", help="specify the template to be rendered", type=str, ) group.addoption( "--keep-baked-projects", action="store_true", default=False, dest="keep_baked_projects", help="Keep projects directories generated with 'cookies.bake()'.", ) def pytest_configure(config): # To protect ourselves from tests or fixtures changing directories, keep # an absolute path to the template. config.option.template = os.path.abspath(config.option.template) pytest-cookies-0.7.0/tests/000077500000000000000000000000001440654546000156525ustar00rootroot00000000000000pytest-cookies-0.7.0/tests/conftest.py000066400000000000000000000014561440654546000200570ustar00rootroot00000000000000# -*- coding: utf-8 -*- import collections import json import pytest pytest_plugins = "pytester" @pytest.fixture(name="cookiecutter_template") def fixture_cookiecutter_template(tmpdir): template = tmpdir.ensure("cookiecutter-template", dir=True) template_config = collections.OrderedDict( [("repo_name", "foobar"), ("short_description", "Test Project")] ) template.join("cookiecutter.json").write(json.dumps(template_config)) template_readme = "\n".join( [ "{{cookiecutter.repo_name}}", "{% for _ in cookiecutter.repo_name %}={% endfor %}", "{{cookiecutter.short_description}}", ] ) repo = template.ensure("{{cookiecutter.repo_name}}", dir=True) repo.join("README.rst").write(template_readme) return template pytest-cookies-0.7.0/tests/test_cookies.py000066400000000000000000000300001440654546000207100ustar00rootroot00000000000000# -*- coding: utf-8 -*- import json import pytest def test_cookies_fixture(testdir): """Make sure that pytest accepts the `cookies` fixture.""" # create a temporary pytest test module testdir.makepyfile( """ # -*- coding: utf-8 -*- def test_valid_fixture(cookies): assert hasattr(cookies, 'bake') assert callable(cookies.bake) """ ) # run pytest with the following cmd args result = testdir.runpytest("-v") # fnmatch_lines does an assertion internally result.stdout.fnmatch_lines(["*::test_valid_fixture PASSED*"]) # make sure that that we get a '0' exit code for the testsuite assert result.ret == 0 def test_cookies_bake_with_template_kwarg(testdir, cookiecutter_template): """bake accepts a template kwarg.""" testdir.makepyfile( """ # -*- coding: utf-8 -*- def test_bake_project(cookies): result = cookies.bake( extra_context={'repo_name': 'helloworld'}, template=r'%s', ) assert result.exit_code == 0 assert result.exception is None assert result.project.basename == 'helloworld' assert result.project.isdir() assert str(result) == ''.format(result.project) """ % cookiecutter_template ) # run pytest without the template cli arg result = testdir.runpytest("-v") result.stdout.fnmatch_lines(["*::test_bake_project PASSED*"]) def test_cookies_bake_template_kwarg_overrides_cli_option( testdir, cookiecutter_template ): """bake template kwarg overrides cli option.""" testdir.makepyfile( """ # -*- coding: utf-8 -*- def test_bake_project(cookies): result = cookies.bake( extra_context={'repo_name': 'helloworld'}, template=r'%s', ) assert result.exit_code == 0 assert result.exception is None assert result.project.basename == 'helloworld' assert result.project.isdir() assert str(result) == ''.format(result.project) """ % cookiecutter_template ) # run pytest with a bogus template name # it should use template directory passed to `cookies.bake` result = testdir.runpytest("-v", "--template=foobar") result.stdout.fnmatch_lines(["*::test_bake_project PASSED*"]) def test_cookies_bake(testdir, cookiecutter_template): """Programmatically create a **Cookiecutter** template and use `bake` to create a project from it. """ testdir.makepyfile( """ # -*- coding: utf-8 -*- def test_bake_project(cookies): result = cookies.bake(extra_context={'repo_name': 'helloworld'}) assert result.exit_code == 0 assert result.exception is None assert result.project_path.name == 'helloworld' assert result.project_path.is_dir() assert str(result) == ''.format(result.project_path) assert result.project.basename == 'helloworld' assert result.project.isdir() assert str(result) == ''.format(result.project) """ ) result = testdir.runpytest("-v", "--template={}".format(cookiecutter_template)) result.stdout.fnmatch_lines(["*::test_bake_project PASSED*"]) def test_cookies_bake_project_warning(testdir, cookiecutter_template): """Programmatically create a **Cookiecutter** template and use `bake` to create a project from it and check for warnings when accesssing the project attribute. """ testdir.makepyfile( """ # -*- coding: utf-8 -*- import warnings def test_bake_project(cookies): warning_message = ( "project is deprecated and will be removed in a future release, " "please use project_path instead." ) result = cookies.bake(extra_context={'repo_name': 'helloworld'}) assert result.exit_code == 0 assert result.exception is None with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") project_basename = result.project.basename assert project_basename == 'helloworld' [warning] = w assert issubclass(warning.category, DeprecationWarning) assert str(warning.message) == warning_message assert str(result) == ''.format(result.project) """ ) result = testdir.runpytest("-v", "--template={}".format(cookiecutter_template)) result.stdout.fnmatch_lines(["*::test_bake_project PASSED*"]) def test_cookies_bake_result_context(testdir, cookiecutter_template): """Programmatically create a **Cookiecutter** template and use `bake` to create a project from it. Check that the result holds the rendered context. """ testdir.makepyfile( """ # -*- coding: utf-8 -*- import collections def test_bake_project(cookies): result = cookies.bake(extra_context=collections.OrderedDict([ ('repo_name', 'cookies'), ('short_description', '{{cookiecutter.repo_name}} is awesome'), ])) assert result.exit_code == 0 assert result.exception is None assert result.project.basename == 'cookies' assert result.project.isdir() assert result.context == { 'repo_name': 'cookies', 'short_description': 'cookies is awesome', } assert str(result) == ''.format(result.project) """ ) result = testdir.runpytest("-v", "--template={}".format(cookiecutter_template)) result.stdout.fnmatch_lines(["*::test_bake_project PASSED*"]) def test_cookies_bake_result_context_exception(testdir, cookiecutter_template): """Programmatically create a **Cookiecutter** template and use `bake` to create a project from it. Check that exceptions resulting from rendering the context are stored on result and that the rendered context is not set. """ testdir.makepyfile( """ # -*- coding: utf-8 -*- import collections def test_bake_project(cookies): result = cookies.bake(extra_context=collections.OrderedDict([ ('repo_name', 'cookies'), ('short_description', '{{cookiecutter.nope}}'), ])) assert result.exit_code == -1 assert result.exception is not None assert result.project is None assert result.context is None assert str(result) == ''.format(result.exception) """ ) result = testdir.runpytest("-v", "--template={}".format(cookiecutter_template)) result.stdout.fnmatch_lines(["*::test_bake_project PASSED*"]) def test_cookies_bake_should_create_new_output_directories( testdir, cookiecutter_template ): """Programmatically create a **Cookiecutter** template and use `bake` to create a project from it. """ testdir.makepyfile( """ # -*- coding: utf-8 -*- def test_bake_should_create_new_output(cookies): first_result = cookies.bake() assert first_result.exception is None assert first_result.project.dirname.endswith('bake00') second_result = cookies.bake() assert second_result.exception is None assert second_result.project.dirname.endswith('bake01') """ ) result = testdir.runpytest("-v", "--template={}".format(cookiecutter_template)) result.stdout.fnmatch_lines(["*::test_bake_should_create_new_output PASSED*"]) def test_cookies_fixture_removes_output_directories(testdir, cookiecutter_template): """Programmatically create a **Cookiecutter** template and use `bake` to create a project from it. """ testdir.makepyfile( """ # -*- coding: utf-8 -*- import os def test_to_create_result(cookies): global result_dirname result = cookies.bake() result_dirname = result.project.dirname assert result.exception is None def test_previously_generated_directory_is_removed(cookies): exists = os.path.isdir(result_dirname) assert exists is False """ ) result = testdir.runpytest("-v", "--template={}".format(cookiecutter_template)) result.stdout.fnmatch_lines( [ "*::test_to_create_result PASSED*", "*::test_previously_generated_directory_is_removed PASSED*", ] ) def test_cookies_fixture_doesnt_remove_output_directories( testdir, cookiecutter_template ): """Programmatically create a **Cookiecutter** template and use `bake` to create a project from it. """ testdir.makepyfile( """ # -*- coding: utf-8 -*- import os def test_to_create_result(cookies): global result_dirname result = cookies.bake() result_dirname = result.project.dirname assert result.exception is None def test_previously_generated_directory_is_not_removed(cookies): exists = os.path.isdir(result_dirname) assert exists is True """ ) result = testdir.runpytest( "-v", "--template={}".format(cookiecutter_template), "--keep-baked-projects" ) result.stdout.fnmatch_lines( [ "*::test_to_create_result PASSED*", "*::test_previously_generated_directory_is_not_removed PASSED*", ] ) def test_cookies_bake_should_handle_exception(testdir): """Programmatically create a **Cookiecutter** template and make sure that cookies.bake() handles exceptions that happen during project generation. We expect **Cookiecutter** to raise a `NonTemplatedInputDirException`. """ template = testdir.tmpdir.ensure("cookiecutter-fail", dir=True) template_config = {"repo_name": "foobar", "short_description": "Test Project"} template.join("cookiecutter.json").write(json.dumps(template_config)) template.ensure("cookiecutter.repo_name", dir=True) testdir.makepyfile( """ # -*- coding: utf-8 -*- def test_bake_should_fail(cookies): result = cookies.bake() assert result.exit_code == -1 assert result.exception is not None assert result.project is None """ ) result = testdir.runpytest("-v", "--template={}".format(template)) result.stdout.fnmatch_lines(["*::test_bake_should_fail PASSED*"]) @pytest.mark.parametrize("choice", ["mkdocs", "sphinx", "none"]) def test_cookies_bake_choices(testdir, choice): """Programmatically create a **Cookiecutter** template and make sure that cookies.bake() works with choice variables. """ template = testdir.tmpdir.ensure("cookiecutter-choices", dir=True) template_config = {"repo_name": "docs", "docs_tool": ["mkdocs", "sphinx", "none"]} template.join("cookiecutter.json").write(json.dumps(template_config)) repo = template.ensure("{{cookiecutter.repo_name}}", dir=True) repo.join("README.rst").write("docs_tool: {{cookiecutter.docs_tool}}") testdir.makepyfile( """ # -*- coding: utf-8 -*- def test_bake_project(cookies): result = cookies.bake( extra_context={'docs_tool': '%s'}, template=r'%s', ) assert result.exit_code == 0 assert result.exception is None assert result.project.basename == 'docs' assert result.project.isdir() assert result.project.join('README.rst').read() == 'docs_tool: %s' assert str(result) == ''.format(result.project) """ % (choice, template, choice) ) # run pytest without the template cli arg result = testdir.runpytest("-v") result.stdout.fnmatch_lines(["*::test_bake_project PASSED*"]) result = testdir.runpytest("-v", "--template={}".format(template)) pytest-cookies-0.7.0/tests/test_help_message.py000066400000000000000000000003341440654546000217170ustar00rootroot00000000000000# -*- coding: utf-8 -*- def test_cookies_group(testdir): result = testdir.runpytest("--help") # fnmatch_lines does an assertion internally result.stdout.fnmatch_lines(["cookies:", "*--template=TEMPLATE*"]) pytest-cookies-0.7.0/tests/test_user_config.py000066400000000000000000000026321440654546000215710ustar00rootroot00000000000000# -*- coding: utf-8 -*- def test_config(testdir): """Make sure that pytest accepts the `cookies` fixture.""" # create a temporary pytest test module testdir.makepyfile( """ # -*- coding: utf-8 -*- import yaml def test_user_dir(tmpdir_factory, _cookiecutter_config_file): basetemp = tmpdir_factory.getbasetemp() assert _cookiecutter_config_file.basename == 'config' user_dir = _cookiecutter_config_file.dirpath() assert user_dir.fnmatch('user_dir?') assert user_dir.dirpath() == basetemp def test_valid_cookiecutter_config(_cookiecutter_config_file): with open(_cookiecutter_config_file) as f: config = yaml.load(f, Loader=yaml.Loader) user_dir = _cookiecutter_config_file.dirpath() expected = { 'cookiecutters_dir': str(user_dir.join('cookiecutters')), 'replay_dir': str(user_dir.join('cookiecutter_replay')), } assert config == expected """ ) # run pytest with the following cmd args result = testdir.runpytest("-v") # fnmatch_lines does an assertion internally result.stdout.fnmatch_lines( ["*::test_user_dir PASSED*", "*::test_valid_cookiecutter_config PASSED*"] ) # make sure that that we get a '0' exit code for the testsuite assert result.ret == 0 pytest-cookies-0.7.0/tox.ini000066400000000000000000000004251440654546000160240ustar00rootroot00000000000000[tox] envlist = py{37,38,39,310,311}-pytest{4,5,6,7},flake8 [testenv] deps = pytest4: pytest>=4,<5 pytest5: pytest>=5,<6 pytest6: pytest>=6,<7 pytest7: pytest>=7,<8 commands = pytest {posargs:tests} [testenv:flake8] deps = flake8 commands = flake8 setup.py src tests