{ "info": { "author": "Lex Scarisbrick", "author_email": "lex@scarisbrick.org", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Internet :: Proxy Servers", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Quality Assurance", "Topic :: Software Development :: Testing", "Topic :: Software Development :: Testing :: Traffic Generation" ], "description": "#####\nSpoof\n#####\n\n.. image:: https://img.shields.io/pypi/v/spoof.svg\n :target: https://pypi.org/project/spoof/\n\n.. image:: https://img.shields.io/pypi/wheel/spoof.svg\n :target: https://pypi.org/project/spoof/\n\n.. image:: https://img.shields.io/pypi/pyversions/spoof.svg\n :target: https://pypi.org/project/spoof/\n\n.. image:: https://img.shields.io/github/license/lexsca/spoof.svg\n :target: https://github.com/lexsca/spoof/blob/master/LICENSE\n\n.. image:: https://codecov.io/gh/lexsca/spoof/branch/master/graph/badge.svg\n :target: https://codecov.io/gh/lexsca/spoof\n\nSpoof is an HTTP server written in Python for use in test environments where\nmocking underlying calls isn't an option, or where it's desirable to have an\nactual HTTP server listening on a socket. Hello, functional tests!\n\nUnlike a typical HTTP server, where specific method and path combinations are\nconfigured in advance, Spoof accepts *all* requests and sends either a queued\nresponse, a default response if the queue is empty, or an error response if no\ndefault response is configured. Requests can be inspected after a response is sent.\n\nCompatibility\n=============\n\nSpoof runs on Python 2.7, 3.4 to 3.7, and has no external dependencies.\n\nMultiple Spoof HTTP servers can be run concurrently, and by default, the port\nnumber is the next available unused port. With OpenSSL installed, Spoof can\nalso provide an SSL/TLS HTTP server. IPv6 is fully supported.\n\nQuickstart\n==========\n\nQueue multiple responses, verify content, and request paths:\n\n.. code-block:: python\n\n import requests\n import spoof\n\n with spoof.HTTPServer() as httpd:\n responses = [\n [200, [('Content-Type', 'application/json')], '{\"id\": 1111}'],\n [200, [('Content-Type', 'application/json')], '{\"id\": 2222}'],\n ]\n httpd.queueResponse(*responses)\n httpd.defaultResponse = [404, [], 'Not found']\n\n assert requests.get(httpd.url + '/path').json() == {'id': 1111}\n assert requests.get(httpd.url + '/alt/path').json() == {'id': 2222}\n assert requests.get(httpd.url + '/oops').status_code == 404\n assert [r.path for r in httpd.requests] == ['/path', '/alt/path', '/oops']\n\nSet a callback as the default response:\n\n.. code-block:: python\n\n import requests\n import spoof\n\n with spoof.HTTPServer() as httpd:\n httpd.defaultResponse = lambda request: [200, [], request.path]\n\n assert requests.get(httpd.url + '/alt').content == b'/alt'\n\nTest queued response with SSL:\n\n.. code-block:: python\n\n import requests\n import spoof\n\n with spoof.SelfSignedSSLContext() as selfSigned:\n with spoof.HTTPServer(sslContext=selfSigned.sslContext) as httpd:\n httpd.queueResponse([200, [], 'No self-signed cert warning!'])\n response = requests.get(httpd.url + '/path',\n verify=selfSigned.certFile)\n\n assert httpd.requests[-1].method == 'GET'\n assert httpd.requests[-1].path == '/path'\n assert response.content == b'No self-signed cert warning!'\n\n\nSSL Warnings\n============\n\nSome libraries like\n`Requests `__ will complain\nloudly or refuse to connect to HTTP servers with a self-signed SSL\ncertificate. The preferred way to handle this is to use the `verify`\nproperty in `requests.Session` to trust the certificate:\n\n.. code:: python\n\n import requests\n import spoof\n\n cert, key = spoof.SSLContext.createSelfSignedCert()\n sslContext = spoof.SSLContext.fromCertChain(cert, key)\n httpd = spoof.HTTPServer(sslContext=sslContext)\n httpd.queueResponse([200, [], 'OK'])\n httpd.start()\n\n # trust self-signed certificate\n session = requests.Session()\n session.verify = cert\n\n response = session.get(httpd.url + '/uri/path')\n print(response.status_code, response.content)\n httpd.stop()\n\nIf verifying the certificate is not an option, another way to work around\nthis is to monkeypatch the requests library in the testing code. For example:\n\n.. code:: python\n\n import requests\n\n certVerify = requests.adapters.HTTPAdapter.cert_verify\n def certNoVerify(self, conn, url, verify, cert):\n return certVerify(self, conn, url, False, cert)\n requests.adapters.HTTPAdapter.cert_verify = certNoVerify\n requests.packages.urllib3.disable_warnings()\n\nAnother common case is libraries that leverage ``ssl`` directly. One way\nto work around this is to globally set the default context to\nunverified. For example:\n\n.. code:: python\n\n import ssl\n\n try:\n createUnverifiedHttpsContext = ssl._create_unverified_context\n except AttributeError:\n # ignore if ssl context not verified by default\n pass\n else:\n ssl._create_default_https_context = createUnverifiedHttpsContext\n\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/lexsca/spoof.git", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "spoof", "package_url": "https://pypi.org/project/spoof/", "platform": "", "project_url": "https://pypi.org/project/spoof/", "project_urls": { "Homepage": "https://github.com/lexsca/spoof.git" }, "release_url": "https://pypi.org/project/spoof/1.5.0/", "requires_dist": null, "requires_python": "", "summary": "HTTP server for testing environments", "version": "1.5.0" }, "last_serial": 4583588, "releases": { "1.0.3": [ { "comment_text": "", "digests": { "md5": "a9127c3113d4ea71c54806dd5f1ea69f", "sha256": "fe4d5e66d2fb628a2bf061552d663d7f42c3d71959f2336254df73d222b5d327" }, "downloads": -1, "filename": "spoof-1.0.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a9127c3113d4ea71c54806dd5f1ea69f", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 7196, "upload_time": "2017-04-10T14:46:51", "url": "https://files.pythonhosted.org/packages/f7/ed/a4be1e0cb75bd726b751941c485cc48cde0e3d28a39b196b5533df76f5ce/spoof-1.0.3-py2.py3-none-any.whl" } ], "1.0.4": [ { "comment_text": "", "digests": { "md5": "30448e44faa6793dada7eca72723070a", "sha256": "845fe1af4852cb2fdc3a9a5d58979f3636edcd4989cff09d8cd6aa13816896c6" }, "downloads": -1, "filename": "spoof-1.0.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "30448e44faa6793dada7eca72723070a", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 7196, "upload_time": "2017-04-10T14:48:58", "url": "https://files.pythonhosted.org/packages/c7/72/55992c1924b9b2fb9d4a085d070b3249e5f766fecb878ad04686af0675b2/spoof-1.0.4-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9f09658825f0de94e8300080605dc921", "sha256": "d27f4068f520512cd20bac682fa520b26ce8536d4e3181af66f78526380c7409" }, "downloads": -1, "filename": "spoof-1.0.4.tar.gz", "has_sig": false, "md5_digest": "9f09658825f0de94e8300080605dc921", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6277, "upload_time": "2017-04-10T14:48:59", "url": "https://files.pythonhosted.org/packages/97/91/86a6468972b26622a64613ae1c60fb463a812dc3dc4fd7b03b72ba2ec3c2/spoof-1.0.4.tar.gz" } ], "1.0.5": [ { "comment_text": "", "digests": { "md5": "c98582edd238a21e84b8a993514a219b", "sha256": "f18810236ba705bf064e280891e6c43f6470a43a49b55ad9f82c757fbe3555c0" }, "downloads": -1, "filename": "spoof-1.0.5-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "c98582edd238a21e84b8a993514a219b", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10606, "upload_time": "2017-04-23T18:58:47", "url": "https://files.pythonhosted.org/packages/35/6b/5a64b44b08bd0e40700f9fc1c2da5b796c97602143cc3c69e8fd57c26355/spoof-1.0.5-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "48d8da4656a519bbd837ec5767cd42a6", "sha256": "91f25352e75a0b819ae5e5a45eeb53637a627d388412ff6db1e5b988a834649f" }, "downloads": -1, "filename": "spoof-1.0.5.tar.gz", "has_sig": false, "md5_digest": "48d8da4656a519bbd837ec5767cd42a6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7704, "upload_time": "2017-04-23T18:58:52", "url": "https://files.pythonhosted.org/packages/b2/83/35eb68fd89b6b04d18ffa049e16e410c5631fad888045bc5ce32824dc635/spoof-1.0.5.tar.gz" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "78f8dcbbd837bc6d164e16e3966ee13f", "sha256": "af9f98c8f447d7e65887e3da0572d94634e18c782841bcdef51f0c5560e43d47" }, "downloads": -1, "filename": "spoof-1.2.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "78f8dcbbd837bc6d164e16e3966ee13f", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 12127, "upload_time": "2018-03-07T03:19:01", "url": "https://files.pythonhosted.org/packages/65/e3/9eda1991d7f30e23e3b44e1283e5e885de55712cc283600535fcae4eef3b/spoof-1.2.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "00512353ba04a95fb8e452b7db9d68d8", "sha256": "30ffa3f5d71d82f2b6e26af365e4b0fb41b6a6b8d55c21dc52bf10ad8858015e" }, "downloads": -1, "filename": "spoof-1.2.0.tar.gz", "has_sig": false, "md5_digest": "00512353ba04a95fb8e452b7db9d68d8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16502, "upload_time": "2018-03-07T03:19:04", "url": "https://files.pythonhosted.org/packages/59/28/dd4ceabda3ea0b8f2e408a908d5affc0177df0c1e2c67b7b4e9ba530e554/spoof-1.2.0.tar.gz" } ], "1.3.0": [ { "comment_text": "", "digests": { "md5": "ccb002e5c8535ccd207b9f7a502d718f", "sha256": "e66e34a52dc99c47fae42879db64b7f679c66badf20b71fa56d9cee9aa656584" }, "downloads": -1, "filename": "spoof-1.3.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "ccb002e5c8535ccd207b9f7a502d718f", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10335, "upload_time": "2018-11-17T00:47:02", "url": "https://files.pythonhosted.org/packages/5b/15/6b64e75b0481e694cbfa7de5980fb905fd8be1a10fe5a771d0308a0daa1d/spoof-1.3.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4694d4fb405c7de9f8e3bb79e10f61c0", "sha256": "a3586eaa9b219fdf63c646487b3019ea22c552e235b3a5ff54bf955187b2ac6c" }, "downloads": -1, "filename": "spoof-1.3.0.tar.gz", "has_sig": false, "md5_digest": "4694d4fb405c7de9f8e3bb79e10f61c0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9482, "upload_time": "2018-11-17T00:47:04", "url": "https://files.pythonhosted.org/packages/7d/be/cae47b7ab670d8f662af3bd9f418f137bc64517d482c88d443a5d91ecf23/spoof-1.3.0.tar.gz" } ], "1.4.0": [ { "comment_text": "", "digests": { "md5": "b95e1020e9f16c06357d4c3af347ad1e", "sha256": "76ce83fc043bec3747d9df6ec68669245a7d38eec2bfcbd5a0a425cf85287726" }, "downloads": -1, "filename": "spoof-1.4.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "b95e1020e9f16c06357d4c3af347ad1e", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10465, "upload_time": "2018-11-18T15:50:51", "url": "https://files.pythonhosted.org/packages/95/2b/97cc12c716e6c17a02c3540562f78cf8c284b010e163362e4dd39d2d5127/spoof-1.4.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "88babfc57c674b7761462f1528319d8d", "sha256": "77a4c60597d120d3530697667f4680db643bfe40421037e2e2d22bf9f422d4a8" }, "downloads": -1, "filename": "spoof-1.4.0.tar.gz", "has_sig": false, "md5_digest": "88babfc57c674b7761462f1528319d8d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9707, "upload_time": "2018-11-18T15:50:55", "url": "https://files.pythonhosted.org/packages/0c/bd/88a33ffad50303125e667f097afdc2a1136456b01ccf42fb20c7eab3cd01/spoof-1.4.0.tar.gz" } ], "1.5.0": [ { "comment_text": "", "digests": { "md5": "ba76cbc4e52ec8ad0c1d1455275ad1f7", "sha256": "c205e77354bfba9342fbb3ff90e2a493ae8840a3e6b54df2620cb872b9914938" }, "downloads": -1, "filename": "spoof-1.5.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "ba76cbc4e52ec8ad0c1d1455275ad1f7", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10517, "upload_time": "2018-12-11T03:06:24", "url": "https://files.pythonhosted.org/packages/94/af/2600805d3fce842fb021d65734f5563c19a950391db5575d489e79e9ae12/spoof-1.5.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "004d2ec2b6abba29c61e4b6747ba3a69", "sha256": "f0b6396a23c9f1d9ca1a46438b484036c1d049a2271156317125e9533aefb573" }, "downloads": -1, "filename": "spoof-1.5.0.tar.gz", "has_sig": false, "md5_digest": "004d2ec2b6abba29c61e4b6747ba3a69", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9835, "upload_time": "2018-12-11T03:06:28", "url": "https://files.pythonhosted.org/packages/a7/81/8b67fe8d6a708b5a86a5989d481d4c2fff485b95f0c61f75c02564194e8a/spoof-1.5.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "ba76cbc4e52ec8ad0c1d1455275ad1f7", "sha256": "c205e77354bfba9342fbb3ff90e2a493ae8840a3e6b54df2620cb872b9914938" }, "downloads": -1, "filename": "spoof-1.5.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "ba76cbc4e52ec8ad0c1d1455275ad1f7", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10517, "upload_time": "2018-12-11T03:06:24", "url": "https://files.pythonhosted.org/packages/94/af/2600805d3fce842fb021d65734f5563c19a950391db5575d489e79e9ae12/spoof-1.5.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "004d2ec2b6abba29c61e4b6747ba3a69", "sha256": "f0b6396a23c9f1d9ca1a46438b484036c1d049a2271156317125e9533aefb573" }, "downloads": -1, "filename": "spoof-1.5.0.tar.gz", "has_sig": false, "md5_digest": "004d2ec2b6abba29c61e4b6747ba3a69", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9835, "upload_time": "2018-12-11T03:06:28", "url": "https://files.pythonhosted.org/packages/a7/81/8b67fe8d6a708b5a86a5989d481d4c2fff485b95f0c61f75c02564194e8a/spoof-1.5.0.tar.gz" } ] }