{ "info": { "author": "Fred L. Drake, Jr.", "author_email": "fred@fdrake.net", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Software Development :: Testing" ], "description": "=============================================\n``kt.testing`` - Test harness support library\n=============================================\n\nApplications that make use of large frameworks often need to mock or\nstub out portions of those APIs in ways that provide a consistent view\non the resources that API exposes. A test fixture often wants to\nestablish a particular state for the API at a higher level than that of\nindividual API calls; this is especially the case if an API provides\nmore than one way to do things. How the code under test uses the\nunderlying API is less interesting than the information exposed by the\nAPI and the operations performed on it.\n\nThere are a number of ways to approach these situations using tests\nbased on ``unittest.TestCase`` fixtures. Too often, these\nbecome tangled messes where test authors have to pay attention to\nimplementation details of base and mix-in classes to avoid support for\ndifferent APIs interfering with each other's internal state.\n\nThis library approaches the problem by allowing APIs that support test\ncontrol of other frameworks or libraries to be independent components.\nThese *fixture components* can:\n\n- access the test object,\n\n- be involved in setup and teardown,\n\n- provide cleanup handlers,\n\n- provide APIs for tests to configure the behavior of the APIs they\n manage, and\n\n- provide additional assertion methods specific to what they do.\n\nThese components can inject themselves into the APIs they manage in\nwhatever ways are appropriate (using ``mock.patch``, for example).\n\n\nRelease history\n---------------\n\n\n3.1.2 (2018-12-19)\n~~~~~~~~~~~~~~~~~~\n\nMinor tweak:\n\n- ``AssertionError`` raised by ``kt.testing.requests`` fixture when\n there is no prepared response now provides a more substantial message\n for PATCH, POST, and PUT requests, showing more information about the\n payload. This can make it easier to debug problems.\n\n\n3.1.1 (2018-10-19)\n~~~~~~~~~~~~~~~~~~\n\nBug fixed:\n\n- Packaging: Wheels are not universal since we don't want to depend on\n ``mock`` under Python 3.\n\n\n3.1.0 (2018-10-19)\n~~~~~~~~~~~~~~~~~~\n\nNew feature:\n\n- ``kt.testing.cleanup`` supports global registration of cleanup\n functions called before & after every test (when using\n ``kt.testing.TestCase``). Directly inspired by\n ``zope.testing.cleanup``, and cooperative with the same.\n\nDevelopment support:\n\n- Add tox configuration for running tests.\n\n\n3.0.0 (2017-11-30)\n~~~~~~~~~~~~~~~~~~\n\nBackward incompatible change:\n\n- The ``kt`` namespace package is switched to use a ``pkgutil``-style\n construction, removing the ``pkg_resources`` support entirely. This\n should not affect many users.\n\n See `Packaging namespace packages`_ for more information about\n namespace package styles.\n\n\n2.2.0 (2017-09-29)\n~~~~~~~~~~~~~~~~~~\n\nNew feature:\n\n- ``kt.testing.requests`` response objects support the ``iter_content``\n method, so long as ``decode_unicode`` is false.\n\n\n2.1.0 (2017-09-05)\n~~~~~~~~~~~~~~~~~~\n\nNew feature:\n\n- ``kt.testing.requests`` intercepts the ``requests`` API at a slightly\n lower level, hooking into the underlying ``requests.sessions.Session``\n object instead of ``requests.api.requests``. This makes it possible\n to use this with packages that manage their own session objects, or\n even derived session objects, as long as the ``request`` method is not\n overridden.\n\n\n2.0.0 (2017-06-19)\n~~~~~~~~~~~~~~~~~~\n\n.. warning::\n\n This release is **not** backward compatible with prior releases.\n Tests *must* now be derived from the ``kt.testing.TestCase`` class.\n This requirement allows the API to be compatible across Python 2 and\n Python 3.\n\nNew features:\n\n- Support for Python 3.\n\n\n1.2.0 (2016-09-20)\n~~~~~~~~~~~~~~~~~~\n\nNew features:\n\n- ``kt.testing.requests.RequestInfo`` object encapsulates information\n received by ``requests`` from the application. This replaces a\n 5-tuple stored in the ``requests`` attribute of the fixture component\n ``kt.testing.requests.Requests``, and provides named access to parts\n of the provided data, for better readability in tests.\n\n\n1.1.0 (2016-05-10)\n~~~~~~~~~~~~~~~~~~\n\nNew features:\n\n- ``kt.testing.requests.Requests`` methods ``add_error`` and\n ``add_response`` grew a new, optional parameter, ``filter``, which\n accepts a callable with the same signature as ``requests.request``.\n The result is a Boolean value that indicates whether request should be\n considered a match for the response. The filter function will only be\n called if the method and URL match.\n\n This can be used to check whether request body matches some\n expectation. This can be especially valuable for RPC-type interfaces\n (XML-RPC or SOAP, for example) where several behaviors map to the same\n URL and HTTP method.\n\n- New ``kt.testing.requests.Requests`` methods: ``add_connect_timeout``,\n ``add_read_timeout``, ``add_unreachable_host``, to add the\n corresponding exceptions to the set of configured responses.\n\n\n1.0.0 (2016-03-21)\n~~~~~~~~~~~~~~~~~~\n\nInitial public release of library initialy created for internal use at\n`Keeper Technology`_.\n\n\nImplementing fixture components\n-------------------------------\n\nFixture components are defined by a factory object, usually a class, and\nare expected to provide a slim API for the harness. Let's look at a\nsimple but complete, usable example::\n\n import logging\n\n\n class TestLoggingHandler(logging.StreamHandler):\n\n def __init__(self, stream, records):\n self.records = records\n super(TestLoggingHandler, self).__init__(stream)\n\n def handle(self, record):\n self.records.append(record)\n super(TestLoggingHandler, self).handle(record)\n\n\n class LoggingFixture(object):\n\n def __init__(self, test, name=None):\n self.test = test\n self.name = name\n\n def setup(self):\n sio = cStringIO.StringIO()\n self.output = sio.getvalue\n self.records = []\n handler = TestLoggingHandler(sio, self.records)\n logger = logging.getLogger(self.name)\n logger.addHandler(handler)\n self.test.addCleanup(logger.removeHandler, handler)\n\nUsing this from a test fixture is straightforward::\n\n import kt.testing\n\n\n class TestMyThing(kt.testing.TestCase):\n\n logging = kt.testing.compose(LoggingFixture)\n\n def test_some_logging(self):\n logging.getLogger('my.package').error('not happy')\n\n record = self.logging.records[-1]\n\n self.assertEqual(record.getMessage(), 'not happy')\n self.assertEqual(record.levelname, 'ERROR')\n\nFixture components may also provide a ``teardown`` method that takes no\narguments (aside from self). These are called after the ``tearDown``\nmethod of the test case is invoked, and do not require that method to be\nsuccessful. (They are invoked as cleanup functions of the test case.)\n\nConstructor arguments for the fixture component can be provided with\n``kt.testing.compose``, but note that the test case instance will always\nbe passed as the first positional argument::\n\n class TestMyThing(kt.testing.TestCase):\n\n logging = kt.testing.compose(LoggingFixture, name='my.package')\n\n def test_some_logging(self):\n logging.getLogger('your.package').error('not happy')\n\n with self.assertRaises(IndexError):\n self.logging.records[-1]\n\nEach instance of the test case class will get it's own instance of the\nfixture components, accessible via the properties defined using\n``kt.testing.compose``. These instances will already be available when\nthe ``__init__`` method of the test case is invoked.\n\nIf the test class overrides the ``setUp`` method, it will need to ensure\nthe superclass ``setUp`` is invoked so the ``setup`` method of the\nfixture components are invoked::\n\n class TestSomeThing(kt.testing.TestCase):\n\n logging = kt.testing.compose(LoggingFixture, name='my.package')\n\n def setUp(self):\n super(TestSomeThing, self).setUp()\n # more stuff here\n\nNote that the ``setUp`` didn't invoke ``unittest.TestCase.setUp``\ndirectly. Since ``kt.testing.compose`` can cause an additional mix-in\nclass to be added, ``super`` is the way to go unless you're specifically\nusing a base class that's known to have the right mix-in already mixed.\n\n\nMultiple fixtures and test inheritance\n--------------------------------------\n\nMultiple fixture components of the same or different types can be added\nfor a single test class::\n\n class TestMyThing(kt.testing.TestCase):\n\n my = kt.testing.compose(LoggingFixture, name='my.package')\n your = kt.testing.compose(LoggingFixture, name='your.package')\n\n def test_different(self):\n self.assertIsNot(self.my, self.your)\n\nBase classes that use fixture components will be properly initialized,\nand properties can be aliased and overridden in ways that make sense::\n\n class TestAnotherThing(TestMyThing):\n\n orig_my = TestMyThing.my\n my = kt.testing.compose(LoggingFixture, name='my.another')\n\n def test_different(self):\n self.assertIsNot(self.my, self.your)\n self.assertIsNot(self.orig_my, self.your)\n self.assertIsNot(self.orig_my, self.my)\n\n self.assertEqual(self.my.name, 'my.another')\n self.assertEqual(self.orig_my.name, 'my.package')\n self.assertEqual(self.your.name, 'your.package')\n\n\n``kt.testing.requests`` - Intercession for ``requests``\n-------------------------------------------------------\n\nMany applications (and other libraries) use the ``requests`` package to\nretrieve resources identified by URL. It's often reasonable to use\n``mock`` directly to handle requests for resources in tests, but\nsometimes a little more is warranted. The ``requests`` library provides\nmultiple ways to trigger particular requests, and applications usually\nshouldn't care which is used to make a request.\n\nA fixture component for ``requests`` is provided::\n\n class TestMyApplication(kt.testing.TestCase):\n\n requests = kt.testing.compose(kt.testing.requests.Requests)\n\nA default response entity can be provided via constructor arguments\npassed through ``compose``. The body and content-type can both be\nprovided::\n\n class TestMyApplication(kt.testing.TestCase):\n\n requests = kt.testing.compose(\n kt.testing.requests.Requests,\n body='{\"success\": true, \"value\": \"let's have some json data\"}',\n content_type='application/json',\n )\n\nIf the default response entity is not defined, an empty body of type\ntext/plain is used.\n\nThe fixture provides these methods for configuring responses for\nparticular requests by URL:\n\n``add_response(method, url, status=200, body=None, headers={}, filter=None)``\n Provide a particular response for a given URL and request method.\n Other aspects of the request are not considered for identifying what\n response to provide.\n\n If the response status indicates an entity is allowed in the\n response and `body` is provided as ``None``, the default body and\n content-type will be returned. This will be an empty string unless\n some other value is provided to the fixture component constructor.\n If the status indicates no entity should be returned, an empty body\n will be used.\n\n If `filter` is provided and not ``None``, if must be a callable that\n accepts the same signature as ``requests.request`` and returns a\n Boolean value indicating whether than response applies to the\n request being made. If the result is true, the response is\n considered a match and will be consumed. If false, the response\n will not be used, but will be considered for subsequent requests.\n\n The provided information will be used to create a response that is\n returned by the ``requests`` API.\n\n``add_error(method, url, exception, filter=None)``\n Provide an exception that should be raised when a particular\n resource is requested. This can be used to simulate errors such as\n a non-responsive server or DNS resolution failure. Only the URL and\n request method are considered for identifying what response to\n provide.\n\n``add_connect_timeout(method, url, filter=None)``\n Provide an exception structured the same way as it would be were the\n host not to connect within a reasonable time. This uses\n ``add_error``, but saves having to construct the exception yourself.\n\n``add_read_timeout(method, url, filter=None)``\n Provide an exception structured the same way as it would be were the\n host to connect but not respond within a reasonable time. This uses\n ``add_error``, but saves having to construct the exception yourself.\n\n``add_unreachable_host(method, url, filter=None)``\n Provide an exception structured the same way as it would be were the\n host unreachable. This uses ``add_error``, but saves having to\n construct the exception yourself.\n\nIf a request is made that does match any provided response, an\n``AssertionError`` is raised; this will normally cause a test to fail,\nunless the code under test catches exceptions too aggressively.\n\nA test that completes without consuming all configured responses will\ncause an ``AssertionError`` to be raised during teardown. Test runners\nbased on ``unittest`` will usually report this as an error rather than a\nfailure, but it'll require a developer to take a look, and that's the\npoint.\n\nIf multiple configurations are made for the same request method and URL\n(whether responses or errors), they'll be provided to the application in\nthe order configured.\n\n\n``kt.testing.cleanup`` - Global cleanup registration\n----------------------------------------------------\n\nMany libraries and applications end up maintaining small bits of global\nstate. These bits may be caches, or information derived from\nconfiguration, but they need to be cleared between tests to avoid tests\ninterfering with each other in ways that can be painful to debug.\n\nClearing these bits of module state in the ``setUp`` or ``tearDown``\nmethods of tests takes care of the problem, but each application needs\nto be aware of every such bit of module state that exists in the\nlibraries and application; this can be a challenge.\n\nAllowing each library or module to register a cleanup function makes it\npossible to collect everything that's needed to ensure test cleanup can\nbe sufficient.\n\nThis approach was built in the |zope.testing|_ package's ``cleanup``\nmodule, which provided functions to register and invoke cleanup\nfunctions. The ``kt.testing.cleanup`` module provides a similar API.\nIf ``zope.testing.cleanup`` is also used, ``kt.testing.cleanup``\ncooperates by sharing the behind-the-scenes registry of cleanup\nfunctions.\n\nThere are two functions which provide the ``kt.testing.cleanup`` API:\n\n``register(func, *args, **kwargs)``\n Register a callable that should be invoked to clean up module\n state. The callable will be invoked with the provided additional\n positional and keyword arguments.\n\n *func* should be fast and simple, and must not raise an\n exception.\n\n``cleanup()``\n Invoke all registered cleanups. The cleanup functions will be\n invoked in the order registered. If ``zope.testing.cleanup`` was\n also used, cleanups registered via each API may be intermingled,\n according to the order of registration.\n\nThe ``setUp`` and ``tearDown`` methods of ``kt.testing.TestCase`` both\ninvoke the ``cleanup`` function.\n\n\n\n.. |zope.testing| replace:: ``zope.testing``\n\n.. _Keeper Technology:\n http://www.keepertech.com/\n\n.. _Packaging namespace packages:\n https://packaging.python.org/guides/packaging-namespace-packages/\n\n.. _zope.testing:\n https://pypi.org/project/zope.testing/\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/keepertech/kt.testing", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "kt.testing", "package_url": "https://pypi.org/project/kt.testing/", "platform": "", "project_url": "https://pypi.org/project/kt.testing/", "project_urls": { "Homepage": "https://github.com/keepertech/kt.testing" }, "release_url": "https://pypi.org/project/kt.testing/3.1.2/", "requires_dist": [ "requests", "six", "nose ; extra == 'test'" ], "requires_python": "", "summary": "Test support code featuring flexible harness composition", "version": "3.1.2" }, "last_serial": 4618446, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "f4456087e5fe8cab9aa5dcb9ab512b30", "sha256": "a63dc30627b836cd82e2923bfb45f3ea62230179871444f14634be8deea080aa" }, "downloads": -1, "filename": "kt.testing-1.0.0.tar.gz", "has_sig": false, "md5_digest": "f4456087e5fe8cab9aa5dcb9ab512b30", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14954, "upload_time": "2016-03-21T14:18:44", "url": "https://files.pythonhosted.org/packages/2c/5a/3278b5040c920526d9287cade11d766c230b1d41034cbe87055b4d6cc8af/kt.testing-1.0.0.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "b2ab9ae21c67e5a8ea79c5f4db97a5a7", "sha256": "b7f3bbaafdac5948cccab8b3dfd4591c5e73dc58a9066136f8083b7084780828" }, "downloads": -1, "filename": "kt.testing-1.1.0.tar.gz", "has_sig": false, "md5_digest": "b2ab9ae21c67e5a8ea79c5f4db97a5a7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16250, "upload_time": "2016-05-10T17:36:33", "url": "https://files.pythonhosted.org/packages/f2/82/8d8236685d9c06cba075d310d85e7dab7d29b692f7aa097b28ddc619c81d/kt.testing-1.1.0.tar.gz" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "45dc7c2bcce824286b1715e8cc4e48d9", "sha256": "0e4c72d28331b3948b4f509076f0b76a113a770dbd3147b29e7d585157d73b98" }, "downloads": -1, "filename": "kt.testing-1.2.0.tar.gz", "has_sig": false, "md5_digest": "45dc7c2bcce824286b1715e8cc4e48d9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16984, "upload_time": "2016-09-20T17:11:03", "url": "https://files.pythonhosted.org/packages/8d/de/28eb4a58cd24cc96b251acbaf7f1cc1cfdc0679840da1aa058ecebcd3aeb/kt.testing-1.2.0.tar.gz" } ], "2.1.0": [ { "comment_text": "", "digests": { "md5": "6c1968f7150f0b510821882fb20c8bad", "sha256": "eb02c35307bf8ed6bd44cbb00dab1281d21ef8e06cb91609a0bbc74d89022f02" }, "downloads": -1, "filename": "kt.testing-2.1.0.tar.gz", "has_sig": false, "md5_digest": "6c1968f7150f0b510821882fb20c8bad", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14077, "upload_time": "2018-04-12T13:49:21", "url": "https://files.pythonhosted.org/packages/da/79/d45daef25bbfc3ac409721baa6fd7947672c0a534f8c9508a93b44348a27/kt.testing-2.1.0.tar.gz" } ], "2.2.0": [ { "comment_text": "", "digests": { "md5": "a188e6084f2fe58c3d0574cd0ef0200a", "sha256": "f3170d4e1fd953720e60c6b3285cbed5ac17e4776d062f75bb865ac0f107eb5d" }, "downloads": -1, "filename": "kt.testing-2.2.0.tar.gz", "has_sig": false, "md5_digest": "a188e6084f2fe58c3d0574cd0ef0200a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14475, "upload_time": "2018-04-12T13:49:22", "url": "https://files.pythonhosted.org/packages/62/72/c713e376a4859afddd7f1030a07d6a04a3347f61071424ca6c924fd0aa9e/kt.testing-2.2.0.tar.gz" } ], "3.0.0": [ { "comment_text": "", "digests": { "md5": "c5ab1e5be84c09fa4ab410730f5e68e6", "sha256": "25ffb1b4b8f217de5ff09ffd99a885933e02830e2f8da44422f1aaa9fb86c22c" }, "downloads": -1, "filename": "kt.testing-3.0.0.tar.gz", "has_sig": false, "md5_digest": "c5ab1e5be84c09fa4ab410730f5e68e6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14578, "upload_time": "2018-04-12T13:49:23", "url": "https://files.pythonhosted.org/packages/2e/15/98f160df2c271504196f9876c0fbec834414d12f63184cc03c7bde0f34a3/kt.testing-3.0.0.tar.gz" } ], "3.1.0": [ { "comment_text": "", "digests": { "md5": "b004ee2be3cec834789bd57fcad570ee", "sha256": "ee7d6eea1b9031ed4e2f9ebe803b8306aa5d4a31940b04244fb9520bd9494249" }, "downloads": -1, "filename": "kt.testing-3.1.0.tar.gz", "has_sig": false, "md5_digest": "b004ee2be3cec834789bd57fcad570ee", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16642, "upload_time": "2018-10-19T17:09:52", "url": "https://files.pythonhosted.org/packages/ec/f5/96db04c1d1cc635d4396411651b5fa95708f6251502561104575c8db8757/kt.testing-3.1.0.tar.gz" } ], "3.1.1": [ { "comment_text": "", "digests": { "md5": "9c4a895703500ecb7d317ac9a349aa03", "sha256": "bc63298a04db5e02a024892f6f4acebb22b15cdb653188509268a2e95b6a110f" }, "downloads": -1, "filename": "kt.testing-3.1.1-py2-none-any.whl", "has_sig": false, "md5_digest": "9c4a895703500ecb7d317ac9a349aa03", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 17116, "upload_time": "2018-10-19T17:27:59", "url": "https://files.pythonhosted.org/packages/8e/38/1bede6ffefe4aa95ab52899971ee962b77760e2c97d067a3339392e311c1/kt.testing-3.1.1-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4d9fc8ff9b0e916a23aefbdf45beec59", "sha256": "ef58ab4dd3ce2db1c7e277d852c3928c008a67b747e71d189bbb54bc56b0c48d" }, "downloads": -1, "filename": "kt.testing-3.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "4d9fc8ff9b0e916a23aefbdf45beec59", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 17111, "upload_time": "2018-10-19T17:28:00", "url": "https://files.pythonhosted.org/packages/30/b0/88ccfb8b3259e15bdbfabcbc5dad2422416fb7ac3205ff0c24cc2f44a5f5/kt.testing-3.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "935556cba0f251dcde4d8726d08c1029", "sha256": "7dfb9f0f310eaf93210414d7f9e1b9c5668610c664708c089282146a02b9a401" }, "downloads": -1, "filename": "kt.testing-3.1.1.tar.gz", "has_sig": false, "md5_digest": "935556cba0f251dcde4d8726d08c1029", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16688, "upload_time": "2018-10-19T17:28:01", "url": "https://files.pythonhosted.org/packages/c8/4e/5fe37481dec1ddfe4886da8eb6ed99aaf86fbf49c8db2d4f3160eedad887/kt.testing-3.1.1.tar.gz" } ], "3.1.2": [ { "comment_text": "", "digests": { "md5": "adcd0aad343993376774b59fe0f242ce", "sha256": "fdcd41beacf2af59c268966eef7a3b1a433a93e9270b4238b8053f1a4a1d8d2b" }, "downloads": -1, "filename": "kt.testing-3.1.2-py2-none-any.whl", "has_sig": false, "md5_digest": "adcd0aad343993376774b59fe0f242ce", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 18963, "upload_time": "2018-12-19T22:07:58", "url": "https://files.pythonhosted.org/packages/d3/09/8c2166a1d75f1d7899d86dd63751fa2167bf54cd71c3122d80da2fae9f33/kt.testing-3.1.2-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9f9e559813816fbadee84c36b016014e", "sha256": "b1c5c95dd5743940be3f15543e86952d384b7e9054772f3423d25525c0667545" }, "downloads": -1, "filename": "kt.testing-3.1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "9f9e559813816fbadee84c36b016014e", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 18960, "upload_time": "2018-12-19T22:01:30", "url": "https://files.pythonhosted.org/packages/39/f1/975ae73873c9e287854ac9485188229bdb8956b918cb409ce44bea4e4090/kt.testing-3.1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8a4c66954eea527a63d92d8a7b668ef7", "sha256": "94621d5cb9d575b1c647c9fc9a7056c2804b8c95e3d7e6b00f6d6c727e8883ce" }, "downloads": -1, "filename": "kt.testing-3.1.2.tar.gz", "has_sig": false, "md5_digest": "8a4c66954eea527a63d92d8a7b668ef7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23311, "upload_time": "2018-12-19T22:01:32", "url": "https://files.pythonhosted.org/packages/03/4b/65b3093db7516b44bbdc4ce593910dad5343f85b3d6e537de92ac62c54ae/kt.testing-3.1.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "adcd0aad343993376774b59fe0f242ce", "sha256": "fdcd41beacf2af59c268966eef7a3b1a433a93e9270b4238b8053f1a4a1d8d2b" }, "downloads": -1, "filename": "kt.testing-3.1.2-py2-none-any.whl", "has_sig": false, "md5_digest": "adcd0aad343993376774b59fe0f242ce", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 18963, "upload_time": "2018-12-19T22:07:58", "url": "https://files.pythonhosted.org/packages/d3/09/8c2166a1d75f1d7899d86dd63751fa2167bf54cd71c3122d80da2fae9f33/kt.testing-3.1.2-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9f9e559813816fbadee84c36b016014e", "sha256": "b1c5c95dd5743940be3f15543e86952d384b7e9054772f3423d25525c0667545" }, "downloads": -1, "filename": "kt.testing-3.1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "9f9e559813816fbadee84c36b016014e", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 18960, "upload_time": "2018-12-19T22:01:30", "url": "https://files.pythonhosted.org/packages/39/f1/975ae73873c9e287854ac9485188229bdb8956b918cb409ce44bea4e4090/kt.testing-3.1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8a4c66954eea527a63d92d8a7b668ef7", "sha256": "94621d5cb9d575b1c647c9fc9a7056c2804b8c95e3d7e6b00f6d6c727e8883ce" }, "downloads": -1, "filename": "kt.testing-3.1.2.tar.gz", "has_sig": false, "md5_digest": "8a4c66954eea527a63d92d8a7b668ef7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23311, "upload_time": "2018-12-19T22:01:32", "url": "https://files.pythonhosted.org/packages/03/4b/65b3093db7516b44bbdc4ce593910dad5343f85b3d6e537de92ac62c54ae/kt.testing-3.1.2.tar.gz" } ] }