{ "info": { "author": "Davide Moro", "author_email": "davide.moro@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Framework :: Pytest", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development :: Testing" ], "description": "pytest-play\n===========\n\n.. image:: https://travis-ci.org/pytest-dev/pytest-play.svg?branch=master\n :target: https://travis-ci.org/pytest-dev/pytest-play\n :alt: See Build Status on Travis CI\n\n.. image:: https://readthedocs.org/projects/pytest-play/badge/?version=latest\n :target: http://pytest-play.readthedocs.io/en/latest/?badge=latest\n :alt: Documentation Status\n\n.. image:: https://codecov.io/gh/pytest-dev/pytest-play/branch/master/graph/badge.svg\n :target: https://codecov.io/gh/pytest-dev/pytest-play\n\n``pytest-play`` is a codeless, generic, pluggable and extensible **automation tool**,\nnot necessarily **test automation** only, based on the fantastic pytest_ test framework\nthat let you define and execute YAML_ files containing scripts or test scenarios\nthrough actions and assertions that can be implemented and managed even by **non technical users**:\n\n* automation (not necessarily test automation). You can build a set of actions on a single file (e.g,\n call a JSON based API endpoint, perform an action if a condition matches) or a test automation\n project with many test scenarios.\n\n For example you can create always fresh test data on demand supporting\n manual testing activities, build a live simulator and so on\n\n* codeless, or better almost codeless. If you have to write assertions against action results or some\n conditional expressions you need a very basic knowledge of Python or Javascript expressions\n with a smooth learning curve (something like ``variables['foo'] == 'bar'``)\n\n* generic. It is not yet again another automation tool for browser automation only, API only, etc.\n You can drive a browser, perform some API calls, make database queries and/or make assertions\n using the same tool for different technologies\n\n So there are several free or not free testing frameworks or automation tools and many times\n they address just one single area testing needs and they are not extensible: API testing only,\n UI testing only and so on. It could be fine if you are testing a web\n only application like a CMS but if you are dealing with a reactive IoT application you might something more,\n make cross actions or cross checks against different systems or build something of more complex upon\n ``pytest-play``\n\n* powerful. It is not yet again another test automation tool, it only extends the pytest_ framework\n with another paradigm and inherits a lot of good stuff (test data decoupled by test implementation\n that let you write once and executed many times the same scenario thanks to native parametrization\n support, reporting, integration with test management tools, many useful command line options, browsers and\n remote Selenium grids integration, etc)\n\n* pluggable and extensible. Let's say you need to interact with a system not yet supported by a ``pytest-play``\n plugin, you can write by your own or pay someone for you. In addition there is a scaffolding tool that\n let you implement your own command: https://github.com/davidemoro/cookiecutter-play-plugin\n \n* easy to use. Why YAML? Easy to read, easy to write, simple and standard syntax, easy to be validated and\n no parentheses hell. Despite there are no recording tools (not yet) for browser interaction or API calls, the\n documentation based on very common patterns let you copy, paste and edit command by command with no pain\n\n* free software. It's an open source project based on the large and friendly pytest_ community\n\n* easy to install. The only prerequisite is Docker thanks to the ``davidemoro/pytest-play`` Docker Hub container.\n Or better, with docker, no installation is required: you just need to type the following command\n ``docker run -i --rm -v $(pwd):/src davidemoro/pytest-play`` inside your project folder\n See https://hub.docker.com/r/davidemoro/pytest-play\n\nSee at the bottom of the page the third party plugins that extends ``pytest-play``:\n\n* `Third party pytest-play plugins`_\n\nHow it works\n------------\n\nDepending on your needs and skills you can choose to use pytest-play programmatically\nwriting some Python code or following a Python-less approach.\n\nAs said before with pytest-play_ you will be able to create codeless scripts or test scenarios\nwith no or very little Python knowledge: a file ``test_XXX.yml`` (e.g., ``test_something.yml``,\nwhere ``test_`` and ``.yml`` matter) will be automatically recognized and executed without having\nto touch any ``*.py`` module. \n\nYou can run a single scenario with ``pytest test_XXX.yml`` or running the entire suite filtering\nby name or keyword markers.\n\nDespite ``pytest-play`` was born with native support for JSON format, ``pytest-play``>=2.0 versions will support\nYAML only for improved usability.\n\nPython-less (pure YAML)\n=======================\n\nHere you can see the contents of a ``pytest-play`` project without any Python files inside\ncontaining a login scenario::\n\n $ tree\n .\n \u251c\u2500\u2500 env-ALPHA.yml (OPTIONAL)\n \u2514\u2500\u2500 test_login.yml\n\nand you might have some global variables in a settings file specific for a target environment:: \n \n $ cat env-ALPHA.yml \n pytest-play:\n base_url: https://www.yoursite.com\n\nThe test scenario with action, assertions and optional metadata\n(play_selenium_ external plugin needed)::\n \n $ cat test_login.yml\n ---\n markers:\n - login\n test_data:\n - username: siteadmin\n password: siteadmin\n - username: editor\n password: editor\n - username: reader\n password: reader\n ---\n - comment: visit base url\n type: get\n provider: selenium\n url: \"$base_url\"\n - comment: click on login link\n locator:\n type: id\n value: personaltools-login\n type: clickElement\n provider: selenium\n - comment: provide a username\n locator:\n type: id\n value: __ac_name\n text: \"$username\"\n type: setElementText\n provider: selenium\n - comment: provide a password\n locator:\n type: id\n value: __ac_password\n text: \"$password\"\n type: setElementText\n provider: selenium\n - comment: click on login submit button\n locator:\n type: css\n value: \".pattern-modal-buttons > input[name=submit]\"\n type: clickElement\n provider: selenium\n - comment: wait for page loaded\n locator:\n type: css\n value: \".icon-user\"\n type: waitForElementVisible\n provider: selenium\n\nThe first optional YAML document contains some metadata with keywords aka ``markers``\nso you can filter tests to be executed invoking pytest with marker expressions,\ndecoupled test data, etc.\n\nThe same ``test_login.yml`` scenario will be executed 3 times with different\ndecoupled test data ``test_data`` defined inside its first optional YAML\ndocument (the block between the 2 ``---`` lines).\n\nSo write once and execute many times with different test data!\n\nYou can see a hello world example here:\n\n* https://github.com/davidemoro/pytest-play-plone-example\n\nAs told before the metadata document is optional so you might have 1 or 2\ndocuments in your YAML file. You can find more info about `Metadata format`_.\n\nHere you can see the same example without the metadata section for sake of\ncompleteness::\n\n ---\n - comment: visit base url\n type: get\n provider: selenium\n url: \"http://YOURSITE\"\n - comment: click on login link\n type: clickElement\n provider: selenium\n locator:\n type: id\n value: personaltools-login\n - comment: provide a username\n type: setElementText\n provider: selenium\n locator:\n type: id\n value: __ac_name\n text: \"YOURUSERNAME\"\n - comment: provide a password\n type: setElementText\n provider: selenium\n locator:\n type: id\n value: __ac_password\n text: \"YOURPASSWORD\"\n - comment: click on login submit button\n type: clickElement\n provider: selenium\n locator:\n type: css\n value: \".pattern-modal-buttons > input[name=submit]\"\n - comment: wait for page loaded\n type: waitForElementVisible\n provider: selenium\n locator:\n type: css\n value: \".icon-user\"\n\nProgrammatically\n================\n\nYou can invoke pytest-play programmatically too. \n\nYou can define a test ``test_login.py`` like this::\n\n def test_login(play):\n data = play.get_file_contents(\n 'my', 'path', 'etc', 'login.yml')\n play.execute_raw(data, extra_variables={})\n\nOr this programmatical approach might be used if you are\nimplementing BDD based tests using ``pytest-bdd``.\n\nCore commands\n-------------\n\npytest-play_ provides some core commands that let you:\n\n* write simple Python assertions, expressions and variables\n\n* reuse steps including other test scenario scripts\n\n* provide a default command template for some particular providers\n (eg: add by default HTTP authentication headers for all requests)\n\n* a generic wait until machinery. Useful for waiting for an\n observable asynchronous event will complete its flow before\n proceeding with the following commands that depends on the previous\n step completion\n\nYou can write restricted Python expressions and assertions based on the ``RestrictedPython`` package.\n\nRestrictedPython_ is a tool that helps to define a subset of the Python\nlanguage which allows to provide a program input into a trusted environment.\nRestrictedPython is not a sandbox system or a secured environment, but it helps\nto define a trusted environment and execute untrusted code inside of it.\n\nSee:\n\n* https://github.com/zopefoundation/RestrictedPython\n\nHow to reuse steps\n==================\n\nYou can split your commands and reuse them using the ``include`` command avoiding\nduplication::\n\n - provider: include\n type: include\n path: \"/some-path/included-scenario.yml\"\n\n\nYou can create a variable for the base folder where your test scripts live.\n\nDefault commands\n================\n\nSome commands require many verbose options you don't want to repeat (eg: authentication headers for play_requests_).\n\nInstead of replicating all the headers information you can initialize a ``pytest-play`` with the provider name as\nkey and as a value the default command you want to omit (this example neets the external plugin play_selenium_)::\n\n - provider: python\n type: store_variable\n name: bearer\n expression: \"'BEARER'\"\n - provider: python\n type: store_variable\n name: play_requests\n expression: \"{'parameters': {'headers': {'Authorization': '$bearer'}}}\"\n - provider: play_requests\n type: GET\n comment: this is an authenticated request!\n url: \"$base_url\"\n\n\nStore variables\n===============\n\nYou can store a pytest-play_ variables::\n\n - provider: python\n type: store_variable\n expression: \"1+1\"\n name: foo\n\nMake a Python assertion\n=======================\n\nYou can make an assertion based on a Python expression::\n\n - provider: python\n type: assert\n expression: variables['foo'] == 2\n\nSleep\n=====\n\nSleep for a given amount of seconds::\n\n - provider: python\n type: sleep\n seconds: 2\n\nExec a Python expresssion\n=========================\n\nYou can execute a Python expression::\n\n - provider: python\n type: exec\n expression: \"1+1\"\n\nWhile condition and looping\n===========================\n\nIf you need to loop over a series of commands or wait something you can use\nthe ``while`` command. It will execute the sequence of sub commands, if any,\nwhile the resulting expression condition is true. Assuming you have a ``countdown``\nvariable containing a integer ``10``, the block of commands whill be executed 10 times::\n\n ---\n - provider: python\n type: while\n expression: variables['countdown'] >= 0\n timeout: 2.3\n poll: 0.1\n sub_commands:\n - provider: python\n type: store_variable\n name: countdown\n expression: variables['countdown'] - 1\n\nThe ``while`` command supersedes the other legacy commands ``wait_until``\n(stops when the condition becomes true) or ``wait_until_not``.\ncommands.\n\n\nConditional commands (Python)\n=============================\n\nYou can skip any command evaluating a Python based skip condition\nlike the following::\n\n - provider: include\n type: include\n path: \"/some-path/assertions.yml\"\n skip_condition: variables['cassandra_assertions'] is True\n\nHow to assert commands elapsed time\n===================================\n\nThe engine updates a ``pytest-play`` variable called ``_elapsed``\nfor each executed command. So you can write something that::\n\n ---\n - type: GET\n provider: play_requests\n url: https://api.chucknorris.io/jokes/categories\n expression: \"'dev' in response.json()\"\n - type: assert\n provider: python\n expression: \"variables['_elapsed'] > 0\"\n\nGenerate a JUnit XML report\n===========================\n\nUse the ``--junit-xml`` command line option, e.g.::\n\n --junit-xml results.xml\n\nYou'll get for each test case errors, commands executed in ``system-output`` (do not use ``-s`` or ``--capture=no`` otherwise you won't\nsee commands in ``system-output``) and execution timing metrics (global, per test case and per single command thanks to ``_elapsed`` property tracked on every executed command shown in ``system-output``).\n\nHere you can see a standard ``results.xml`` file::\n\n {'expression': '1 == 1', 'provider': 'python', 'type': 'assert', '_elapsed': 0.0003077983856201172}\n {'expression': '0 == 0', 'provider': 'python', 'type': 'assert', '_elapsed': 0.0002529621124267578}\n \n\nGenerate a custom JUnit XML report with custom properties and execution times metrics\n=====================================================================================\n\nYou can track execution time metrics for monitoring and measure\nwhat is important to you. For example you can track using a machine interpretable format:\n\n* response times (e.g., how much time is needed for returning a ``POST`` json payload)\n\n* time that occurs between the invocation of an API and a reactive web application update or some asynchronous data appearing on an event store\n\n* time that occurs between a user input on browser and results updated (e.g., a live search)\n\n* time that occurs between a login button and the page loaded an usable (e.g., how much time is needed after a browser action to click on a target button)\n\nTrack response time metric in JUnit XML report\n----------------------------------------------\n\nFor example, a ``test_categories.yml`` file executed with\nthe command line option ``--junit-xml report.xml`` (requires play_requests_ plugin)::\n\n test_data:\n - category: dev\n - category: movie\n - category: food\n ---\n - type: GET\n provider: play_requests\n url: https://api.chucknorris.io/jokes/categories\n expression: \"'$category' in response.json()\"\n - provider: metrics\n type: record_elapsed\n name: categories_time\n - type: assert\n provider: python\n expression: \"variables['categories_time'] < 2.5\"\n comment: you can make an assertion against the categories_time\n\nwill generate an extended ``report.xml`` file with custom properties like that::\n\n {'expression': "'dev' in response.json()", 'provider': 'play_requests', 'type': 'GET', 'url': 'https://api.chucknorris.io/jokes/categories', '_elapsed': 0.5829994678497314}\n {'name': 'categories_time', 'provider': 'metrics', 'type': 'record_elapsed', '_elapsed': 3.3855438232421875e-05}\n {'comment': 'you can make an assertion against the categories_time', 'expression': "variables['categories_time'] < 2.5", 'provider': 'python', 'type': 'assert', '_elapsed': 0.0006382465362548828}\n {'expression': "'movie' in response.json()", 'provider': 'play_requests', 'type': 'GET', 'url': 'https://api.chucknorris.io/jokes/categories', '_elapsed': 0.4184422492980957}\n {'name': 'categories_time', 'provider': 'metrics', 'type': 'record_elapsed', '_elapsed': 2.09808349609375e-05}\n {'comment': 'you can make an assertion against the categories_time', 'expression': "variables['categories_time'] < 2.5", 'provider': 'python', 'type': 'assert', '_elapsed': 0.000553131103515625}\n {'expression': "'food' in response.json()", 'provider': 'play_requests', 'type': 'GET', 'url': 'https://api.chucknorris.io/jokes/categories', '_elapsed': 0.463592529296875}\n {'name': 'categories_time', 'provider': 'metrics', 'type': 'record_elapsed', '_elapsed': 2.09808349609375e-05}\n {'comment': 'you can make an assertion against the categories_time', 'expression': "variables['categories_time'] < 2.5", 'provider': 'python', 'type': 'assert', '_elapsed': 0.00054931640625}\n \n\nand the custom property ``categories_time`` will be tracked for each\ntest case execution, for example::\n\n \n \n \n\nAdvanced metrics in JUnit XML report\n------------------------------------\n\nIn this example we want to measures how long it takes a page to become interactive\n(page responding to user interactions) and evaluate update time for a live search feature.\nLet's see the ``test_search.yml`` example (requires play_selenium_)::\n\n ---\n - provider: selenium\n type: get\n url: https://www.plone-demo.info/\n - provider: metrics\n type: record_elapsed_start\n name: load_time\n - provider: selenium\n type: setElementText\n text: plone 5\n locator:\n type: id\n value: searchGadget\n - provider: metrics\n type: record_elapsed_stop\n name: load_time\n - provider: metrics\n type: record_elapsed_start\n name: live_search_time\n - provider: selenium\n type: waitForElementVisible\n locator:\n type: css\n value: li[data-url$=\"https://www.plone-demo.info/front-page\"]\n - provider: metrics\n type: record_elapsed_stop\n name: live_search_time\n\nIf you execute this scenario with the ``--junit-xml results.xml``\noption you'll get a ``results.xml`` file similar to this one::\n\n {'provider': 'selenium', 'type': 'get', 'url': 'https://www.plone-demo.info/', '_elapsed': 9.593282461166382}\n {'name': 'load_time', 'provider': 'metrics', 'type': 'record_elapsed_start', '_elapsed': 1.1682510375976562e-05}\n {'locator': {'type': 'id', 'value': 'searchGadget'}, 'provider': 'selenium', 'text': 'plone 5', 'type': 'setElementText', '_elapsed': 1.1019845008850098}\n {'name': 'load_time', 'provider': 'metrics', 'type': 'record_elapsed_stop', '_elapsed': 1.9788742065429688e-05}\n {'name': 'live_search_time', 'provider': 'metrics', 'type': 'record_elapsed_start', '_elapsed': 1.0013580322265625e-05}\n {'locator': {'type': 'css', 'value': 'li[data-url$="https://www.plone-demo.info/front-page"]'}, 'provider': 'selenium', 'type': 'waitForElementVisible', '_elapsed': 1.060795545578003}\n {'name': 'live_search_time', 'provider': 'metrics', 'type': 'record_elapsed_stop', '_elapsed': 2.3603439331054688e-05}\n \n\nand in this case you'll find out that the key metric ``load_time``\nwas ``1.11`` seconds and the ``live_search_time`` was ``1.09`` seconds as\nyou can see here::\n\n \n \n \n \n\nSo thanks to JUnit XML reporting you can track response times (not only browser based timings)\nusing a machine readable format to be ingested by third party systems with an acceptable approximation\nif you cannot track timings directly on the systems under test.\n\nTrack any property in JUnit XML reports using expressions\n---------------------------------------------------------\n\nLet's see a ``test_categories.yml`` (play_selenium_ required)::\n\n test_data:\n - category: dev\n - category: movie\n - category: food\n ---\n - type: GET\n provider: play_requests\n url: https://api.chucknorris.io/jokes/categories\n expression: \"'$category' in response.json()\"\n - provider: metrics\n type: record_property\n name: categories_time\n expression: \"variables['_elapsed']*1000\"\n - type: assert\n provider: python\n expression: \"variables['categories_time'] < 2500\"\n comment: you can make an assertion against the categories_time\n\ngenerates some custom properties (``categories_time`` in milliseconds using a python expression)\nusing the ``--junit-xml results.xml`` cli option::\n\n {'expression': "'dev' in response.json()", 'provider': 'play_requests', 'type': 'GET', 'url': 'https://api.chucknorris.io/jokes/categories', '_elapsed': 0.6103124618530273}\n {'expression': "variables['_elapsed']*1000", 'provider': 'python', 'type': 'exec', '_elapsed': 0.0006859302520751953}\n {'expression': "variables['_elapsed']*1000", 'name': 'categories_time', 'provider': 'metrics', 'type': 'record_property', '_elapsed': 0.006484270095825195}\n {'comment': 'you can make an assertion against the categories_time', 'expression': "variables['categories_time'] < 2500", 'provider': 'python', 'type': 'assert', '_elapsed': 0.0005526542663574219}\n {'expression': "'movie' in response.json()", 'provider': 'play_requests', 'type': 'GET', 'url': 'https://api.chucknorris.io/jokes/categories', '_elapsed': 0.44372105598449707}\n {'expression': "variables['_elapsed']*1000", 'provider': 'python', 'type': 'exec', '_elapsed': 0.0009415149688720703}\n {'expression': "variables['_elapsed']*1000", 'name': 'categories_time', 'provider': 'metrics', 'type': 'record_property', '_elapsed': 0.01613616943359375}\n {'comment': 'you can make an assertion against the categories_time', 'expression': "variables['categories_time'] < 2500", 'provider': 'python', 'type': 'assert', '_elapsed': 0.0011241436004638672}\n {'expression': "'food' in response.json()", 'provider': 'play_requests', 'type': 'GET', 'url': 'https://api.chucknorris.io/jokes/categories', '_elapsed': 0.5765485763549805}\n {'expression': "variables['_elapsed']*1000", 'provider': 'python', 'type': 'exec', '_elapsed': 0.0006375312805175781}\n {'expression': "variables['_elapsed']*1000", 'name': 'categories_time', 'provider': 'metrics', 'type': 'record_property', '_elapsed': 0.006584644317626953}\n {'comment': 'you can make an assertion against the categories_time', 'expression': "variables['categories_time'] < 2500", 'provider': 'python', 'type': 'assert', '_elapsed': 0.0005452632904052734}\n \n\nobtaining the metrics you want to track for each execution, for example::\n\n \n\nso you might track the category as well for each test execution\nor whatever you want.\n\nMonitoring test metrics with statsd/graphite\n============================================\n\nIf you like the measure everything approach you can track and monitor interesting\ncustom test metrics from an end user perspective during normal test executions or\nheavy load/stress tests thanks to the statsd_/graphite_ integration.\n\nMeasuring important key metrics is important for many reasons:\n\n* compare performance between different versions under same conditions using past\n tracked stats for the same metric (no more say the system *seems slower* today)\n\n* predict the system behaviour with many items on frontend (e.g., evaluate\n the browser dealing with thousands and thousands of items managed by an infinite\n scroll plugin)\n\n* predict the system behaviour under load\n\nYou can install ``statsd``/``graphite`` in minutes using Docker:\n\n* https://graphite.readthedocs.io/en/latest/install.html\n\nBasically you can track on ``statsd``/``graphite`` every **numeric** metric using\nthe same commands used for tracking metrics on JUnit XML reports as we will see.\n\nIn addition, but not required, installing the third party plugin called pytest-statsd_.\nyou can track on ``statsd``/``graphite``:\n\n* execution times\n* number of executed tests per status (pass, fail, error, etc)\n\nPrerequisites (you need to install the optional statsd client not installed by\ndefault):::\n\n pip install pytest-play[statsd]\n\nUsage (cli options compatible with ``pytest-statsd``)::\n\n --stats-d [--stats-prefix play --stats-host http://myserver.com --stats-port 3000]\n\nwhere:\n\n* ``--stats-d``, enable ``statsd``\n\n* ``--stats-prefix`` (optional), if you plan on having multiple projects sending\n results to the same server.\n For example if you provide ``play`` as prefix you'll get a time metric under\n the ``stats.timers.play.YOURMETRIC.mean`` key (or instead of ``.mean`` you can use ``.upper``,\n ``upper_90``, etc)\n\n* ``--stats-host``, by default ``localhost``\n\n* ``--stats-port``, by default ``8125``\n\nNow you can track timing metrics using the ``record_elapsed`` or\n``record_elapsed_start``/``record_elapsed_stop`` commands seen before (pytest-play will\nsend for you time values to ``statsd`` converted to ``milliseconds`` as requested by ``statsd``).\n\nIf you want to track custom metrics using the ``record_property`` command you have to provide\nan additional parameter called ``metric_type``. For example::\n\n - provider: metrics\n type: record_property\n name: categories_time\n expression: \"variables['_elapsed']*1000\"\n metric_type: timing\n - provider: metrics\n type: record_property\n name: fridge_temperature\n expression: \"4\"\n metric_type: gauge\n\nSome additional information regarding the ``record_property`` command:\n\n* if you don't provide the ``metric_type`` option in ``record_property`` commands values\n will not be transmitted to ``statsd`` (eventually they will be tracked on JUnit XML report\n if ``--junit-xml`` option was provided)\n\n* if you provide an allowed ``metric_type`` value (``timing`` or ``gauge``) non numeric values\n will be considered as an error (``ValueError`` exception raised)\n\n* non allowed ``metric_type`` values will be considered as an error\n\n* if you provide ``timing`` as ``metric_type``, it's up to you providing a numeric value\n expressed in ``milliseconds``\n\nMonitor HTTP response times\n---------------------------\n\nMonitor API response time (see https://github.com/pytest-dev/pytest-play/tree/features/examples/statsd_graphite_monitoring):\n\n.. image:: https://raw.githubusercontent.com/pytest-dev/pytest-play/features/docs/_static/statsd_graphite_monitoring.gif\n :alt: Chuck Norris API response time\n\nBrowser metrics\n---------------\n\nMonitor browser metrics using Selenium from an end user perspective (see https://github.com/pytest-dev/pytest-play/tree/features/examples/statsd_graphite_monitoring_selenium):\n\n* from page load to page usable\n\n* live search responsiveness\n\n.. image:: https://raw.githubusercontent.com/pytest-dev/pytest-play/features/docs/_static/statsd_graphite_monitoring_selenium.gif\n :alt: Time for first interaction after load and live search rendering timings\n\nRecord metrics programmatically\n-------------------------------\n\nIf you don't want to use ``pytest-play`` but you need to record test metrics\nyou can use ``pytest-play`` as a library:::\n\n def test_programmatically(play):\n play.execute_command({\n 'provider': 'metrics',\n 'type': 'record_property',\n 'name': 'oil_temperature',\n 'expression': '60',\n 'metric_type': 'gauge'})\n\nPerformance tests with pytest-play and bzt/Taurus (BlazeMeter)\n==============================================================\n\nYou can reuse all your pytest-play scenario and turn them to\nperformance tests using bzt/Taurus (so it is compatible with BlazeMeter_\ntoo and all its goodies).\n\nAdd a bzt/Taurus YAML file with no ``test_`` prefix like that (full example here in\nbzt_performance_)::\n\n settings:\n artifacts-dir: /tmp/%Y-%m-%d_%H-%M-%S.%f\n \n execution:\n - executor: pytest\n scenario: pytest-run\n iterations: 1\n \n scenarios:\n pytest-run:\n # additional-args: --stats-d --stats-prefix play\n script: scripts/\n \n services:\n - module: shellexec\n prepare:\n - pip3 install -r https://raw.githubusercontent.com/davidemoro/pytest-play-docker/master/requirements.txt\n\nand run the following command::\n\n docker run --rm -it -v $(pwd):/src --user root --entrypoint \"bzt\" davidemoro/pytest-play bzt.yml\n\nYou will see bzt up and running playing our scenarios:\n\n\n.. image:: https://raw.githubusercontent.com/pytest-dev/pytest-play/features/docs/_static/pytest_play_performance.png\n :alt: Taurus/bzt running pytest-play scenarios\n\nYou can uncomment ``additional-args`` to pass other ``pytest`` command line options (e.g., enable ``statsd``\nfor key user metrics monitoring or any other cli option).\n\nMore info about bzt/Taurus here:\n\n* http://gettaurus.org/\n\nDynamic expressions in payloads without declaring variables\n===========================================================\n\nIf you have to send a certain payload to a REST endpoint or a MQTT message\ncontaining a dynamic value you can store a variable with ``store_variable``\nand use ``$variable_name`` in your payload when needed.\nStoring variables is cool if you will reuse later that value but if just have to\ngenerate a dynamic value, let's say a timestamp in milliseconds,\nyou can use the ``{! EXPRESSION !}`` format.\n\nFor example (play_mqtt_ plugin required):\n\n::\n\n ---\n - comment: python expressions in mqtt payload (without declaring variables)\n provider: mqtt\n type: publish\n host: \"$mqtt_host\"\n port: \"$mqtt_port\"\n endpoint: \"$mqtt_endpoint/$device_serial_number\"\n payload: '{\n \"measure_id\": [124],\n \"obj_id_L\": [0],\n \"measureType\": [\"float\"],\n \"start_time\": {! int(datetime.datetime.utcnow().timestamp()*1000) !},\n \"bin_value\": [1]\n }'\n\nwhere instead of the expression::\n\n {! int(datetime.datetime.utcnow().timestamp()*1000) !},\n\nwill be printed::\n\n 1553007973702\n\nBrowser based commands\n----------------------\n\nThe ``pytest-play`` core no more includes browser based commands. Moved to play_selenium_\nexternal plugin.\n\npytest-play is pluggable and extensible\n---------------------------------------\n\n``pytest-play`` has a pluggable architecture and you can extend it.\n\nFor example you might want to support your own commands, support non UI\ncommands like making raw POST/GET/etc calls, simulate IoT devices\nactivities, provide easy interaction with complex UI widgets like\ncalendar widgets, send commands to a device using the serial port implementing\na binary protocol and so on.\n\nHow to register a new command provider\n======================================\n\nLet's suppose you want to extend pytest-play with the following command::\n\n command = {'type': 'print', 'provider': 'newprovider', 'message': 'Hello, World!'}\n\nYou just have to implement a command provider::\n\n from pytest_play.providers import BaseProvider\n\n class NewProvider(BaseProvider):\n\n def this_is_not_a_command(self):\n \"\"\" Commands should be command_ prefixed \"\"\"\n\n def command_print(self, command):\n print(command['message'])\n\n def command_yetAnotherCommand(self, command):\n print(command)\n\nand register your new provider in your ``setup.py`` adding an entrypoint::\n\n entry_points={\n 'playcommands': [\n 'print = your_package.providers:NewProvider',\n ],\n },\n\nYou can define new providers also for non UI commands. For example publish MQTT\nmessages simulating IoT device activities for integration tests.\n\nIf you want you can generate a new command provider thanks to:\n\n* https://github.com/davidemoro/cookiecutter-play-plugin\n\nMetadata format\n---------------\n\nYou can also add some scenario metadata placing another YAML document on top of the scenario\ndefined on the ``test_XXX.yml`` with the following format::\n\n ---\n markers:\n - marker1\n - marker2\n test_data:\n - username: foo\n - username: bar\n ---\n # omitted scenario steps in this example...\n\nOption details:\n\n* ``markers``, you can decorate your scenario with one or more markers. You can use them\n in pytest command line for filtering scenarios to be executed thanks to marker\n expressions like ``-m \"marker1 and not slow\"``\n\n* ``test_data``, enables parametrization of your decoupletd test data and let you execute\n the same scenario many times. For example\n the example above will be executed twice (one time with \"foo\" username and another time\n with \"bar\")\n\nNew options will be added in the next feature (e.g., skip scenarios, xfail, xpass, etc).\n\nExamples\n--------\n\n* https://github.com/pytest-dev/pytest-play/tree/master/examples\n\n* https://github.com/davidemoro/pytest-play-docker/tree/master/tests\n\n* https://github.com/davidemoro/pytest-play-plone-example\n\n\nArticles and talks\n------------------\n\nArticles:\n\n* `Hello pytest-play!`_\n\n* `API/REST testing like Chuck Norris with pytest play using YAML`_\n\n* `pytest-play automated docker hub publishing workflow`_\n\n* `Test automation framework thoughts and examples with Python, pytest and Jenkins`_\n\n* `Testing metrics thoughts and examples: how to turn lights on and off through MQTT with pytest-play`_\n\nTalks:\n\n* `Serena Martinetti @ Pycon9 - Florence: Integration tests ready to use with pytest-play`_ \n\n* `Davide Moro @ STF2019 - Milan: Automazione e monitoraggio metriche di test in ambito IoT con pytest-play`_\n\nThird party pytest-play plugins\n-------------------------------\n\n* play_selenium_, ``pytest-play`` plugin driving browsers using Selenium/Splinter\n under the hood. Selenium grid compatible and implicit auto wait actions\n for more robust scenarios with less controls.\n\n* play_requests_, ``pytest-play`` plugin driving the famous Python ``requests``\n library for making ``HTTP`` calls.\n\n* play_sql_, ``pytest-play`` support for SQL expressions and assertions\n\n* play_cassandra_, ``pytest-play`` support for Cassandra expressions and assertions\n\n* play_dynamodb_, ``pytest-play`` support for AWS DynamoDB queries and assertions\n\n* play_websocket_, ``pytest-play`` support for websockets\n\n* play_mqtt_, ``pytest-play`` plugin for MQTT support. Thanks to ``play_mqtt``\n you can test the integration between a mocked IoT device that sends\n commands on MQTT and a reactive web application with UI checks.\n\n You can also build a simulator that generates messages for you.\n\n\nFeel free to add your own public plugins with a pull request!\n\n\nTwitter\n-------\n\n``pytest-play`` tweets happens here:\n\n* `@davidemoro`_\n \n\n.. _`pytest`: https://github.com/pytest-dev/pytest\n.. _`pypom_form`: http://pypom-form.readthedocs.io/en/latest/\n.. _`splinter`: https://splinter.readthedocs.io/en/latest/\n.. _`pypom`: http://pypom.readthedocs.io/en/latest/\n.. _`@davidemoro`: https://twitter.com/davidemoro\n.. _`cookiecutter-qa`: https://github.com/davidemoro/cookiecutter-qa\n.. _`play.yml`: https://github.com/davidemoro/cookiecutter-qa/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/%7B%7Bcookiecutter.project_slug%7D%7D/tests/functional/data/play.yml\n.. _`test_play.py`: https://github.com/davidemoro/cookiecutter-qa/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/%7B%7Bcookiecutter.project_slug%7D%7D/tests/functional/test_play.py\n.. _`play_mqtt`: https://github.com/davidemoro/play_mqtt\n.. _`play_selenium`: https://github.com/davidemoro/play_selenium\n.. _`play_requests`: https://github.com/davidemoro/play_requests\n.. _`play_sql`: https://github.com/davidemoro/play_sql\n.. _`play_cassandra`: https://github.com/davidemoro/play_cassandra\n.. _`play_dynamodb`: https://github.com/davidemoro/play_dynamodb\n.. _`play_websocket`: https://github.com/davidemoro/play_websocket\n.. _`RestrictedPython`: https://github.com/zopefoundation/RestrictedPython\n.. _`Serena Martinetti @ Pycon9 - Florence: Integration tests ready to use with pytest-play`: https://www.pycon.it/conference/talks/integration-tests-ready-to-use-with-pytest-play\n.. _`Davide Moro @ STF2019 - Milan: Automazione e monitoraggio metriche di test in ambito IoT con pytest-play`: https://speakerdeck.com/davidemoro/automazione-e-monitoraggio-metriche-di-test-in-ambito-iot-con-pytest-play\n.. _`Hello pytest-play!`: http://davidemoro.blogspot.it/2018/04/hello-pytest-play.html\n.. _`API/REST testing like Chuck Norris with pytest play using YAML`: https://davidemoro.blogspot.com/2019/02/api-rest-testing-pytest-play-yaml-chuck-norris.html\n.. _`YAML`: https://en.wikipedia.org/wiki/YAML\n.. _`pytest-play automated docker hub publishing workflow`: https://davidemoro.blogspot.com/2019/02/automated-docker-hub-push-travisci-pyup-python.html\n.. _`statsd`: https://github.com/statsd/statsd\n.. _`graphite`: https://github.com/graphite-project/graphite-web\n.. _`pytest-statsd`: https://github.com/jlane9/pytest-statsd\n.. _`Test automation framework thoughts and examples with Python, pytest and Jenkins`: https://davidemoro.blogspot.com/2018/03/test-automation-python-pytest-jenkins.html\n.. _`Testing metrics thoughts and examples: how to turn lights on and off through MQTT with pytest-play`: https://davidemoro.blogspot.com/2019/04/testing-metrics-thoughts-and-examples.html\n.. _`BlazeMeter`: https://www.blazemeter.com/\n.. _`bzt_performance`: https://github.com/pytest-dev/pytest-play/tree/features/examples/bzt_performance\n\nChangelog\n=========\n\n2.3.1 (2019-06-12)\n------------------\n\nBugfix:\n\n- fix compatibility with pytest 4.6. Rif #86\n\nDocumentation:\n\n- update media section (articles and talks)\n\n2.3.0 (2019-04-05)\n------------------\n\nFeatures and improvements:\n\n- ``wait_until`` and ``wait_until_not`` now accept commands with no ``sub_commands`` property\n\n- implement new ``while`` command in python provider (while expression is true)\n\n2.2.2 (2019-03-29)\n------------------\n\nMinor changes:\n\n- remove internal property parameter on engine\n\nBugfix:\n\n- add compatibility with ``pytest-repeat``'s ``--count`` command line option\n\nDocumentation:\n\n- mention how to generate dynamic values using ``{! expr !}`` expressions\n (e.g., dynamic payloads in REST or MQTT without having to store variables\n when not needed)\n\n\n2.2.1 (2019-03-19)\n------------------\n\nMinor changes:\n\n- add ``int`` and ``float`` builtins available in Python expressions\n\n- make python expressions more flexible for future improvements (internal change that doesn't\n affect compatibility)\n\nBugfix:\n\n- fix ``--setup-plan`` invokation\n\nDocumentation:\n\n- add more examples (bzt/Taurus and performance tests using pytest-play)\n\n\n2.2.0 (2019-03-01)\n------------------\n\n- ``statsd`` integration (optional requirement) for advanced test metrics using statsd/graphite.\n If you install pytest play with the optional statsd support with ``pytest-play[statsd]``\n you will get the additional dependency ``statsd`` client and you can use the same cli\n options defined by the ``pytest-statsd`` plugin (e.g.,\n ``--stats-d [--stats-prefix myproject --stats-host http://myserver.com --stats-port 3000]``).\n\n Note well: despite the above cli options are the same defined by the ``pytest-statsd`` plugin,\n at this time of writing ``pytest-statsd`` is not a ``pytest-play`` dependency\n so you won't get stats about number of failures, passing, etc but only stats tracked by\n ``pytest-play``. If you need them you can install ``pytest-statsd`` (it plays well with ``pytest-play``)\n\n2.1.0 (2019-02-22)\n------------------\n\nFeatures:\n\n- support junit xml generation file with ``system-out`` element for\n each test case execution (pytest ``--junit-xml`` option).\n ``system-out`` will tracked by default in junit report unless you use\n the ``--capture=no`` or its alias ``-s``\n\n- track ``_elapsed`` time for each executed command ``--junit-xml`` report\n if ``system-out`` is enabled\n\n- track ``pytest`` custom properties in ``--junit-xml`` report for monitoring\n and measure what is important to you. For example you can track as key metric\n the time of the time occurred between the end of the previous action and\n the completion of the following. Basically you can track under the ``property_name``\n `load_login` key the time occurred between the click on the submit button\n and the end of the current command (e.g., click on the menu or text input\n being able to receive text) using a machine interpretable format.\n\n The ``property_name`` value elapsed time will be available as standard ``pytest-play``\n variable so that you can make additional assertions\n\n- after every command execution a ``pytest-play`` variable will be added/updated\n reporting the elapsed time (accessible using ``variables['_elapsed']``).\n\n So be aware that the ``_elapsed`` variable name should be considered as a special\n variable and so you should not use this name for storing variables\n\n- improve debug in case of failed assertions or errored commands. Logged variables\n dump in standard logs and ``system-out`` reporting if available\n\n- improve debuggability in case of assertion errors (log failing expression)\n\n- added a new ``metrics`` provider that let you track custom metrics in conjunction\n with ``--junit-xml`` option. You can track in a machine readable format response\n times, dynamic custom expressions, time that occurs between different commands\n (e.g., measure the time needed after a login to interact with the page, time before\n an asynchronous update happens and so on). Under the ``metrics`` provider you'll\n find the ``record_property``, ``record_elapsed``, ``record_elapsed_start`` and\n ``record_elapsed_stop`` commands\n\nDocumentation:\n\n- minor documentation changes\n\n- add more examples\n\n\n2.0.2 (2019-02-06)\n------------------\n\nDocumentation:\n\n- more examples\n\n- fix documentation bug on README (example based on selenium with missing ``provider: selenium``)\n\n\n2.0.1 (2019-01-30)\n------------------\n\nDocumentation:\n\n- Mention davidemoro/pytest-play docker container in README.\n You can use pytest-play with a docker command like that now\n ``docker run -i --rm -v $(pwd):/src davidemoro/pytest-play``\n\nBugfix:\n\n- Fix error locking pipenv due to pytest-play requirement\n constraint not existing (RestrictedPython>=4.0.b2 -> RestrictedPython>=4.0b2)\n\n\n2.0.0 (2019-01-25)\n------------------\n\nBreaking changes:\n\n- Renamed fixture from `play_json` to `play` (#5)\n\n- Drop json support, adopt yaml only format for scenarios (#5)\n\n- Drop ``.ini`` file for metadata, if you need them you can add\n a YAML document on top of the scenario ``.yml`` file. You no more\n need multiple files for decorating your scenarios now (#65)\n\n- `play.execute` no more accepts raw data string), consumes a list of commands.\n Introduced `play.execute_raw` accepting raw data string.\n\n- `play.execute_command` accepts a Python dictionary only now (not a string)\n\n- Selenium provider removed from ``pytest-play`` core, implemented on a\n separate package ``play_selenium``. Starting from now you have to add\n to your selenium commands ``provider: selenium``\n\n- engine's ``parametrizer_class`` attribute no more available (\n use ``parametrizer.Parametrizer`` by default now)\n\nBug fix:\n\n- Fix invalid markup on PyPI (#55)\n\n- Fix invalid escape sequences (#62).\n\nDocumentation and trivial changes:\n\n- Add examples folder\n\n\n1.4.2 (2018-05-17)\n------------------\n\n- Configuration change on Github. Use the same branching policy adopted by\n pytest (master becomes main branch, see #56)\n\n- Fixed skipped test and added new tests (deselect scenarios with keyword\n and marker expressions)\n\n- Fix #58: you no more get a TypeError if you try to launch pytest-play\n in autodiscovery mode\n\n- Fix #55: restructured text lint on README.rst (bad visualization on pypi)\n\n- Updated README (articles and talks links)\n\n- Added a ``DeprecationWarning`` for `play_json` fixture.\n pytest-play will be based on yaml instead of json in version >=2.0.0.\n See https://github.com/pytest-dev/pytest-play/issues/5\n\n\n1.4.1 (2018-04-06)\n------------------\n\n- Documentation improvements\n\n- Add bzt/Taurus/BlazeMeter compatibility\n\n\n1.4.0 (2018-04-05)\n------------------\n\n- Small documentation improvements\n\n- Now ``test_XXX.json`` files are automatically collected and executed\n\n- You can run a test scenario using the pytest CLI ``pytest test_YYY.json``\n\n- Introduced json test scenario ini file with markers definition. For a given\n ``test_YYY.json`` scenario you can add a ``test_YYY.ini`` ini file::\n\n [pytest]\n markers =\n marker1\n marker2\n\n and filter scenarios using marker expressions ``pytest -m marker1``\n\n- Enabled parametrization of arguments for a plain json scenario in scenario ini file::\n\n [pytest]\n test_data =\n {\"username\": \"foo\"}\n {\"username\": \"bar\"}\n\n and your json scenario will be executed twice\n\n- ``pytest-play`` loads some variables based on the contents of the optional ``pytest-play``\n section in your ``pytest-variables`` file now. So if your variables file contains the following\n values::\n\n pytest-play:\n foo: bar\n date_format: YYYYMMDD\n\n you will be able to use expressions ``$foo``, ``$date_format``, ``variables['foo']`` or\n ``variables['date_format']``\n\n\n1.3.2 (2018-02-05)\n------------------\n\n- Add ``sorted`` in python expressions\n\n\n1.3.1 (2018-01-31)\n------------------\n\n- Add more tests\n\n- Documentation update\n\n- play_json fixture no more assumes that you\n have some pytest-variables settings.\n No more mandatory\n\n- fix include scenario bug that occurs only\n on Windows (slash vs backslash and\n JSON decoding issues)\n\n\n1.3.0 (2018-01-22)\n------------------\n\n- documentation improvements\n\n- supports teardown callbacks\n\n\n1.2.0 (2018-01-22)\n------------------\n\n- implement python based commands in ``pytest-play`` and\n deprecates ``play_python``.\n So this feature is a drop-in replacement for the\n ``play-python`` plugin.\n\n You should no more install ``play_python`` since now.\n\n- update documentation\n\n- deprecate selenium commands (they will be implemented\n on a separate plugin and dropped in\n ``pytest-play`` >= 2.0.0). All your previous scripts\n will work fine, this warning is just for people\n directly importing the provider for some reason.\n\n- implement skip conditions. You can omit the execution of\n any command evaluating a Python based skip condition\n\n\n1.1.0 (2018-01-16)\n------------------\n\n- Documentation updated (add new pytest play plugins)\n\n- Support default payloads for command providers. Useful\n for HTTP authentication headers, common database settings\n\n\n1.0.0 (2018-01-10)\n------------------\n\n- execute command accepts kwargs now\n\n- execute command returns the command value now\n\n- complete refactor of ``include`` provider (no\n backwards compatibility)\n\n- add ``play_json.get_file_contents`` and removed\n ``data_getter`` fixture (no backwards compatibility)\n\n\n0.3.1 (2018-01-04)\n------------------\n\n- play engine now logs commands to be executed and errors\n\n\n0.3.0 (2018-01-04)\n------------------\n\n- you are able to update variables when executing commands\n\n- you can extend ``pytest-play`` with new pluggable commands coming\n from third party packages thanks to setuptools entrypoints\n\n\n0.2.0 (2018-01-02)\n------------------\n\n- no more open browser by default\n pytest-play is a generic test engine and it could be used for non UI tests too.\n\n So there is no need to open the browser for non UI tests (eg: API tests)\n\n\n0.1.0 (2017-12-22)\n------------------\n\n- implement reusable steps (include scenario)\n\n- minor documentation changes\n\n0.0.1 (2017-12-20)\n------------------\n\n- First release", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/davidemoro/pytest-play", "keywords": "", "license": "Apache Software License 2.0", "maintainer": "Davide Moro", "maintainer_email": "davide.moro@gmail.com", "name": "pytest-play", "package_url": "https://pypi.org/project/pytest-play/", "platform": "", "project_url": "https://pypi.org/project/pytest-play/", "project_urls": { "Homepage": "https://github.com/davidemoro/pytest-play" }, "release_url": "https://pypi.org/project/pytest-play/2.3.1/", "requires_dist": null, "requires_python": "", "summary": "pytest plugin that let you automate actions and assertions with test metrics reporting executing plain YAML files", "version": "2.3.1" }, "last_serial": 5390830, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "1c66df8bff3c3f7c0466c3ac5b218a9a", "sha256": "22ac2ec8444f05010b3c6c10c5b0b39ca87d1629837615270385fd82878f86c7" }, "downloads": -1, "filename": "pytest-play-0.0.1.tar.gz", "has_sig": false, "md5_digest": "1c66df8bff3c3f7c0466c3ac5b218a9a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16162, "upload_time": "2017-12-20T14:50:01", "url": "https://files.pythonhosted.org/packages/65/a9/0ca4fa619c3c7fca89d9ea24d30e3e0786c390450d74af0dbf8ca3bc9d79/pytest-play-0.0.1.tar.gz" } ], "0.1.0": [ { "comment_text": "", "digests": { "md5": "8c5e3a3d5de35948565744e5e504e2a0", "sha256": "a415d8c45a76af6a4e5b5f1033f5f285777a9f8c6e7b8dc4912ecd236a2bea77" }, "downloads": -1, "filename": "pytest-play-0.1.0.tar.gz", "has_sig": false, "md5_digest": "8c5e3a3d5de35948565744e5e504e2a0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17254, "upload_time": "2017-12-22T11:58:15", "url": "https://files.pythonhosted.org/packages/e4/f4/8e0ee21a85b179f22802be877bb92fe0eca34cb0fff2e44b4ec1d4e1ef9e/pytest-play-0.1.0.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "2f52aabf8177646a0da0412c02f7309a", "sha256": "bcfc0ad7d63f18ca535e689354a8cd0b2f7b20f6e4cd663f0d824e6fa469d6bc" }, "downloads": -1, "filename": "pytest-play-0.2.0.tar.gz", "has_sig": false, "md5_digest": "2f52aabf8177646a0da0412c02f7309a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17473, "upload_time": "2018-01-02T14:27:49", "url": "https://files.pythonhosted.org/packages/a1/5b/40d36380f68e16ffcd085a0163e87d4dfb58c0272bfb94befa4191fd4eb3/pytest-play-0.2.0.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "1b131f6727487a49008ff019909cb04e", "sha256": "b322948a973a763d7555754bacb7d4d33fa1562db02b24015fbf47e7455a85d4" }, "downloads": -1, "filename": "pytest-play-0.3.0.tar.gz", "has_sig": false, "md5_digest": "1b131f6727487a49008ff019909cb04e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18333, "upload_time": "2018-01-04T09:40:07", "url": "https://files.pythonhosted.org/packages/2f/71/68517f6c352481dd740978057a895f5ead33360c625947e08040350b6fb8/pytest-play-0.3.0.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "e2d6847da3dbd057c9836775bbcd2953", "sha256": "99ff6b1add1d48f1a3c80e60a8b49eeb0db3983df07eed194771462e74f21f53" }, "downloads": -1, "filename": "pytest-play-0.3.1.tar.gz", "has_sig": false, "md5_digest": "e2d6847da3dbd057c9836775bbcd2953", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18440, "upload_time": "2018-01-04T14:03:12", "url": "https://files.pythonhosted.org/packages/6d/e8/b429e0acdea75525e99973aaedc03baec1b262e9b926e77de4061833a886/pytest-play-0.3.1.tar.gz" } ], "1.0.0": [ { "comment_text": "", "digests": { "md5": "8edcdadba6a724af71f6181af427bb44", "sha256": "024f3d6ecc77ff757ad84df1a63ca11c5041dbd50e88a08c5f6ada81a8d3e349" }, "downloads": -1, "filename": "pytest-play-1.0.0.tar.gz", "has_sig": false, "md5_digest": "8edcdadba6a724af71f6181af427bb44", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18809, "upload_time": "2018-01-10T08:36:25", "url": "https://files.pythonhosted.org/packages/a4/de/f7c74d227a9a31018c20c7c727af4354683e9ff141fd32c6cd534988f8db/pytest-play-1.0.0.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "464e39d132fdc4ff55476ca0247d0afd", "sha256": "4c5ac93e38c2e334917b18a4c41127a277ce6e6503b073d50e79777fe109cf07" }, "downloads": -1, "filename": "pytest-play-1.1.0.tar.gz", "has_sig": false, "md5_digest": "464e39d132fdc4ff55476ca0247d0afd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20153, "upload_time": "2018-01-16T14:03:29", "url": "https://files.pythonhosted.org/packages/d3/ef/239ec9e2307cae584fdd9a9c3a1a0e9e7269d9dd092fb03a302eadc43d0f/pytest-play-1.1.0.tar.gz" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "b1c27616d96b061e4f250cdfafeb8efb", "sha256": "165815576ecf48919658a0fdb978d28a19f61600060bcd585c6cea72f103082c" }, "downloads": -1, "filename": "pytest-play-1.2.0.tar.gz", "has_sig": false, "md5_digest": "b1c27616d96b061e4f250cdfafeb8efb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24540, "upload_time": "2018-01-22T11:11:36", "url": "https://files.pythonhosted.org/packages/db/38/57c54720e876c4150dc9303a9d992f12d8bb458db0cfea40ef3a81153799/pytest-play-1.2.0.tar.gz" } ], "1.3.0": [ { "comment_text": "", "digests": { "md5": "475669bb98dff1587a5f537730d49019", "sha256": "561c7307b3c5760e72611e4270ed7543677d750aa37028f15493d167ff68f1bc" }, "downloads": -1, "filename": "pytest-play-1.3.0.tar.gz", "has_sig": false, "md5_digest": "475669bb98dff1587a5f537730d49019", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24680, "upload_time": "2018-01-22T16:57:40", "url": "https://files.pythonhosted.org/packages/ec/44/2e3e0c40e447e9e15204ee272d493207f36f603f08ff863a357b65f17a1c/pytest-play-1.3.0.tar.gz" } ], "1.3.1": [ { "comment_text": "", "digests": { "md5": "ec5615bff5b5e131a0e3341dd39fa780", "sha256": "253a570b14975568748c2d0ab07dcdb66ddc3bb9829efd9dc425e2215b472b4e" }, "downloads": -1, "filename": "pytest-play-1.3.1.tar.gz", "has_sig": false, "md5_digest": "ec5615bff5b5e131a0e3341dd39fa780", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 25192, "upload_time": "2018-01-31T09:11:57", "url": "https://files.pythonhosted.org/packages/33/ee/e6335df8e48940c990cdbf9051099d26d2a509c4c4df77eac3e3fa8143b5/pytest-play-1.3.1.tar.gz" } ], "1.3.2": [ { "comment_text": "", "digests": { "md5": "148fce124b4ebda2f394a007e4fa8392", "sha256": "76f110c930e4b7edfc3b2e7190d900daf192f9fbf2bf63f5c3fa608e961e1143" }, "downloads": -1, "filename": "pytest-play-1.3.2.tar.gz", "has_sig": false, "md5_digest": "148fce124b4ebda2f394a007e4fa8392", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 25255, "upload_time": "2018-02-05T17:22:07", "url": "https://files.pythonhosted.org/packages/ed/18/84aeea6f8a8264c27cf8220c74aeb94af40bbffd42baa525364fc9152e0c/pytest-play-1.3.2.tar.gz" } ], "1.4.0": [ { "comment_text": "", "digests": { "md5": "31168df37f28ce1af485c197c7066a99", "sha256": "0a1c108cced00f6a77d5709143b50260cbf4e37e057a967fb2979af9abcebe5e" }, "downloads": -1, "filename": "pytest-play-1.4.0.tar.gz", "has_sig": false, "md5_digest": "31168df37f28ce1af485c197c7066a99", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28509, "upload_time": "2018-04-04T22:14:27", "url": "https://files.pythonhosted.org/packages/ee/d1/35867d069cab177a467ecab62f785799acc7f121cc87ee4542a1437d8c05/pytest-play-1.4.0.tar.gz" } ], "1.4.1": [ { "comment_text": "", "digests": { "md5": "03a9e37233da200f081d449381cfd09b", "sha256": "1e3e92c4d13017612b58764e8c06f201af97cb4b7f54f208c7657148b98ce959" }, "downloads": -1, "filename": "pytest-play-1.4.1.tar.gz", "has_sig": false, "md5_digest": "03a9e37233da200f081d449381cfd09b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31569, "upload_time": "2018-04-05T22:46:54", "url": "https://files.pythonhosted.org/packages/f9/e8/49a489dfdbc2b9527492036f3abb963b00b8bf2bff883e6fdee313a206b2/pytest-play-1.4.1.tar.gz" } ], "1.4.2": [ { "comment_text": "", "digests": { "md5": "0653b0e36fc9c17f91f55d582656d1c3", "sha256": "326c705ccdf92900c5538a7ee429062f90e9f24ad6be86ecd8f0d5284328743f" }, "downloads": -1, "filename": "pytest-play-1.4.2.tar.gz", "has_sig": false, "md5_digest": "0653b0e36fc9c17f91f55d582656d1c3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 32389, "upload_time": "2018-05-17T22:02:17", "url": "https://files.pythonhosted.org/packages/4f/77/cad3b4f11a4991e1177032f5350523b64832f6a890637429bf19ec36ab75/pytest-play-1.4.2.tar.gz" } ], "2.0.0": [ { "comment_text": "", "digests": { "md5": "264aa38a983e838738542cb585d7bb94", "sha256": "b3a057a72104038372f823ef1b78ebc21287d8cb1a0d6b18d964c248fd947515" }, "downloads": -1, "filename": "pytest-play-2.0.0.tar.gz", "has_sig": false, "md5_digest": "264aa38a983e838738542cb585d7bb94", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28751, "upload_time": "2019-01-25T21:53:21", "url": "https://files.pythonhosted.org/packages/0b/d2/9e9c32040ddf032f92eec61e9cc42321986706c94a008bbc349fadea6140/pytest-play-2.0.0.tar.gz" } ], "2.0.1": [ { "comment_text": "", "digests": { "md5": "d08ec5a2a3cc6965d2b767053ae57cbb", "sha256": "43f1390d79721468c96920f492a5a4ed29cbf436947e9cc1830ad8e7065014c5" }, "downloads": -1, "filename": "pytest-play-2.0.1.tar.gz", "has_sig": false, "md5_digest": "d08ec5a2a3cc6965d2b767053ae57cbb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29417, "upload_time": "2019-01-30T21:44:21", "url": "https://files.pythonhosted.org/packages/39/f4/3854ae908bc95c89496b7c40ce5535a1de098073cc6d2a428946a4a827d6/pytest-play-2.0.1.tar.gz" } ], "2.0.2": [ { "comment_text": "", "digests": { "md5": "1be0ddc929a383f2f5a1103879fd10e0", "sha256": "8f4a16f1bec2e87310c3b4ecb7a51ded48d92eba1387c1243f7478a6c64e59e9" }, "downloads": -1, "filename": "pytest-play-2.0.2.tar.gz", "has_sig": false, "md5_digest": "1be0ddc929a383f2f5a1103879fd10e0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29822, "upload_time": "2019-02-06T23:10:59", "url": "https://files.pythonhosted.org/packages/6b/20/41edbac39aee857e8dc9f0dfac73d667390b812af57fd6e7a10ab852501e/pytest-play-2.0.2.tar.gz" } ], "2.1.0": [ { "comment_text": "", "digests": { "md5": "09fb968054f8bea77b622cc3b507998e", "sha256": "4748537f4fc53a0bd739162a54c0dc6c540221766b85ec84e2f604cd998540e5" }, "downloads": -1, "filename": "pytest-play-2.1.0.tar.gz", "has_sig": false, "md5_digest": "09fb968054f8bea77b622cc3b507998e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 44500, "upload_time": "2019-02-22T23:16:23", "url": "https://files.pythonhosted.org/packages/36/46/1ae847d3e17b972bb2220973f465f61dcc3dea96f3786e73395dc63c483a/pytest-play-2.1.0.tar.gz" } ], "2.2.0": [ { "comment_text": "", "digests": { "md5": "51672de55cd112aad12d8b2d727caa36", "sha256": "1d7830caca95707371b0c6396aa654a4dbb43275db00bb6724058e4ad9edd008" }, "downloads": -1, "filename": "pytest-play-2.2.0.tar.gz", "has_sig": false, "md5_digest": "51672de55cd112aad12d8b2d727caa36", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 50117, "upload_time": "2019-03-01T11:54:12", "url": "https://files.pythonhosted.org/packages/21/81/7662b57ddc7401c69bcb4b3b3f2bcba6c82750c6d26b3c1cfcaf490c37bd/pytest-play-2.2.0.tar.gz" } ], "2.2.1": [ { "comment_text": "", "digests": { "md5": "02b113f41f6b14e11b099dfdae019aa2", "sha256": "d9f46c01cfe4db41677924a900fd5b21399f953e53c439d08ce78a8205bf8ea1" }, "downloads": -1, "filename": "pytest-play-2.2.1.tar.gz", "has_sig": false, "md5_digest": "02b113f41f6b14e11b099dfdae019aa2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 52166, "upload_time": "2019-03-19T13:04:48", "url": "https://files.pythonhosted.org/packages/61/2c/1c79415f68ea9958686282c2cbeae8f5258e1c42fff29fe0a9a6a9f762fc/pytest-play-2.2.1.tar.gz" } ], "2.2.2": [ { "comment_text": "", "digests": { "md5": "fd58cc4e626adf4e41af754aea7a30df", "sha256": "a491f0f657e5869b8b4e3b88c6ab9fd34a2a759173ec123a56fda5b098e822bd" }, "downloads": -1, "filename": "pytest-play-2.2.2.tar.gz", "has_sig": false, "md5_digest": "fd58cc4e626adf4e41af754aea7a30df", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 54167, "upload_time": "2019-03-29T12:20:45", "url": "https://files.pythonhosted.org/packages/32/53/03c5ede32ef99453e75e5c0df0dd4d67b2176baf05cfff14393f96d3d678/pytest-play-2.2.2.tar.gz" } ], "2.3.0": [ { "comment_text": "", "digests": { "md5": "05378ca35c0cb7e780cfa4dd9b247cac", "sha256": "48163c0bd889f09fb718f827b22cc7123cbdb0304f950ded3e33e0e45ab8f353" }, "downloads": -1, "filename": "pytest-play-2.3.0.tar.gz", "has_sig": false, "md5_digest": "05378ca35c0cb7e780cfa4dd9b247cac", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 52976, "upload_time": "2019-04-05T11:43:43", "url": "https://files.pythonhosted.org/packages/ec/19/e526f837d78681ac9c336ebdb927c9ff574f26078c62ee1fd8355f7b424f/pytest-play-2.3.0.tar.gz" } ], "2.3.1": [ { "comment_text": "", "digests": { "md5": "69c1d2e2c00fd06bdeac9136ce6aa1b0", "sha256": "dd19138cdd1c8baa68671c404c8581eee64623e7ff02a4cc5f586fd2198936cd" }, "downloads": -1, "filename": "pytest-play-2.3.1.tar.gz", "has_sig": false, "md5_digest": "69c1d2e2c00fd06bdeac9136ce6aa1b0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 53504, "upload_time": "2019-06-12T11:59:29", "url": "https://files.pythonhosted.org/packages/8c/ec/b9ab32993fbc2fb612cd828d58eba9b250dab591a380c7cef1d42f2e5fd0/pytest-play-2.3.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "69c1d2e2c00fd06bdeac9136ce6aa1b0", "sha256": "dd19138cdd1c8baa68671c404c8581eee64623e7ff02a4cc5f586fd2198936cd" }, "downloads": -1, "filename": "pytest-play-2.3.1.tar.gz", "has_sig": false, "md5_digest": "69c1d2e2c00fd06bdeac9136ce6aa1b0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 53504, "upload_time": "2019-06-12T11:59:29", "url": "https://files.pythonhosted.org/packages/8c/ec/b9ab32993fbc2fb612cd828d58eba9b250dab591a380c7cef1d42f2e5fd0/pytest-play-2.3.1.tar.gz" } ] }