{ "info": { "author": "Georges Racinet", "author_email": "gracinet@anybox.fr", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Topic :: Software Development :: Testing" ], "description": "anybox.testing.datetime\n=======================\n\nThis package allows to **cheat with current time** in tests.\nIt has initially been used in Odoo to test workflows spanning over a long period of time.\n\nCurrently it mainly provides a ``datetime.set_now()`` method to fake the\ncurrent time, and a ``datetime.real_now()`` to return back to the original\ntime.\n\nUsage\n~~~~~\n\nBefore anything, the package must be imported in order to replace the\nregular ``datetime`` module with the modified one::\n\n >>> import anybox.testing.datetime\n >>> from datetime import datetime\n >>> import time\n\nLet's keep the real value of ``now`` around::\n\n >>> start = datetime.now()\n >>> start_t = time.time()\n >>> start_s = time.strftime('%Y-%m-%d')\n >>> start_l = time.localtime()\n >>> start_c = time.ctime()\n\nThen you can change the current time::\n\n >>> datetime.set_now(datetime(2001, 01, 01, 3, 57, 0))\n >>> datetime.now()\n datetime(2001, 1, 1, 3, 57)\n >>> datetime.today()\n datetime(2001, 1, 1, 3, 57)\n\nThe time module goes along::\n\n >>> datetime.fromtimestamp(time.time())\n datetime(2001, 1, 1, 3, 57)\n\nNote that you can expect a few microseconds difference (not displayed\nhere because ``datetime.fromtimestamp`` ignores them).\n\nSome other functions from the time module also return the current time:\n\n >>> time.localtime()\n time.struct_time(tm_year=2001, tm_mon=1, tm_mday=1, tm_hour=3, tm_min=57, tm_sec=0, tm_wday=0, tm_yday=1, tm_isdst=-1)\n >>> time.strftime('%Y-%m-%d')\n '2001-01-01'\n >>> time.ctime()\n 'Mon Jan 1 03:57:00 2001'\n >>> time.asctime()\n 'Mon Jan 1 03:57:00 2001'\n >>> time.gmtime()\n time.struct_time(tm_year=2001, tm_mon=1, tm_mday=1, tm_hour=3, tm_min=57, tm_sec=0, tm_wday=0, tm_yday=1, tm_isdst=-1)\n\nThe remaining behaviours are not altered\n\n >>> time.localtime(0).tm_year\n 1970\n >>> time.strftime('%Y-%m-%d', datetime(1999,9,9).timetuple())\n '1999-09-09'\n >>> time.ctime(5)\n 'Thu Jan 1 02:00:05 1970'\n >>> time.asctime(time.localtime(5))\n 'Thu Jan 1 02:00:05 1970'\n >>> time.gmtime(5.0)\n time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=5, tm_wday=3, tm_yday=1, tm_isdst=0)\n\n\n\nDon't forget afterwards to get back to the regular system clock, otherwise\nmany pieces of code might get very suprised if the system clock looks as if\nit's frozen::\n\n >>> datetime.real_now()\n\nNow let's check it worked::\n\n >>> now = datetime.now()\n >>> now > start\n True\n >>> from datetime import timedelta\n >>> now - start < timedelta(0, 0, 10000) # 10 ms\n True\n\nAnd with the ``time`` module::\n\n >>> now_t = time.time()\n >>> now_t > start_t\n True\n >>> now_t - start_t < 0.01 # 10 ms again\n True\n >>> time.strftime('%Y-%m-%d') == start_s\n True\n >>> time.localtime().tm_mday == start_l.tm_mday\n True\n\nOther constructors are still available (this is a non regression\ntest)::\n\n >>> import datetime\n >>> datetime.time(3, 57, 0)\n datetime.time(3, 57)\n >>> datetime.datetime(2013, 1, 1, 3, 57, 0)\n datetime(2013, 1, 1, 3, 57)\n >>> datetime.date(2013, 1, 1)\n datetime.date(2013, 1, 1)\n\nBehind the hood\n~~~~~~~~~~~~~~~\n\nOur replacement class is the one loaded from the ``datetime`` module,\nbut instances of the original ``datetime`` class behave exactly as\ninstances of our ``datetime.datetime``. This is needed because most\ncomputational methods, actually return an object of the original\n``datetime`` class. This works with python >= 2.6 only.\n\nFirst let's check that our class is a subclass of the original\none. If this fails, this test does not mean anything anymore::\n\n >>> datetime.datetime is datetime.original_datetime\n False\n >>> issubclass(datetime.datetime, datetime.original_datetime)\n True\n\nThen let's demonstrate the behaviour::\n\n >>> odt = datetime.original_datetime(2012, 1, 1)\n >>> isinstance(odt, datetime.datetime)\n True\n >>> issubclass(datetime.original_datetime, datetime.datetime)\n True\n\nWe'll need a ``tzinfo`` subclass from now on.\n\n >>> from datetime import tzinfo\n >>> class mytzinfo(tzinfo):\n ... def utcoffset(self, dt):\n ... return timedelta(hours=2)\n ... def dst(self, dt):\n ... return timedelta(0)\n\nCompatibility\n~~~~~~~~~~~~~\n\nOver the lifespan of this development toolkit module, we've had to ensure\ncompatibility with several subsystems\n\nlogging\n-------\n\nIn the logging module, ``time.localtime`` is used as a method. We just check it works\n\n >>> import logging\n >>> datetime.datetime.set_now(datetime.datetime(2000, 1, 1))\n >>> logging.Formatter().converter().tm_year >= 2014\n True\n >>> datetime.datetime.real_now()\n\nSQLite\n------\n\nAlso, ``sqlite3`` does recognize our ``datetime`` and ``date`` classes as\nif they were the original ones::\n\n >>> import sqlite3\n >>> cnx = sqlite3.connect(':memory:')\n >>> cr = cnx.cursor()\n >>> cr = cr.execute(\"CREATE TABLE dates (dt text, d text)\")\n >>> dt = datetime.datetime(2013, 1, 25, 12, 34, 0)\n >>> d = datetime.date(2013, 4, 7)\n >>> cr = cr.execute(\"INSERT INTO dates VALUES (?, ?)\", (dt, d))\n >>> cr = cr.execute(\"SELECT dt, d from dates\")\n >>> cr.fetchall()\n [(u'2013-01-25 12:34:00', u'2013-04-07')]\n\nRestore original time\n~~~~~~~~~~~~~~~~~~~~~\n\nNow let's try this again with the original ones::\n\n >>> dt = datetime.datetime.now()\n >>> isinstance(dt, datetime.original_datetime)\n True\n >>> d = datetime.date.today()\n >>> cr = cr.execute(\"INSERT INTO dates VALUES (?, ?)\", (dt, d))\n >>> cr = cr.execute(\"SELECT dt, d from dates\")\n >>> res = cr.fetchall() # can't check the value, it changes a lot !\n\n\nData streaming aka pickle\n-------------------------\n\nThe mock_dt support pickling::\n\n >>> import pickle\n >>> from StringIO import StringIO\n >>> stream = StringIO()\n >>> v = datetime.datetime(2013, 1, 1, 3, 57, 0)\n >>> pickle.dump(v, stream)\n >>> stream.seek(0)\n >>> v2 = pickle.load(stream)\n >>> v == v2\n True\n >>> type(v2)\n \n >>> stream = StringIO()\n >>> v = datetime.datetime.now()\n >>> pickle.dump(v, stream)\n >>> stream.seek(0)\n >>> v2 = pickle.load(stream)\n >>> v == v2\n True\n >>> type(v2)\n \n >>> stream = StringIO()\n >>> datetime.datetime.set_now(datetime.datetime(2001, 01, 01, 3, 57, 0))\n >>> v = datetime.datetime.now()\n >>> pickle.dump(v, stream)\n >>> stream.seek(0)\n >>> v2 = pickle.load(stream)\n >>> v == v2\n True\n >>> type(v2)\n \n\nTest\n~~~~\n\nThis README is also a doctest. To test it and other doctests for this package,\nsimply install Nose and run::\n\n $ nosetests\n\n\nChanges\n~~~~~~~\n\n0.5 (2015-04-12)\n----------------\n\n- Added support for time.* functions\n- #6: fixed picking error\n\n\n0.4.2 (2013-06-11)\n------------------\n\n- A few improvements in the doc\n\n0.4.1 (2013-04-24)\n------------------\n\n- #3: fixed compatibility problem with ``sqlite3`` (spotted via IPython/IPdb)\n\n0.3.1 (2012-11-28)\n------------------\n\n- #1: tested code using time zone optional arg of now() doesn't break\n any more (no real time zone support, though)\n\n0.3 (2012-11-23)\n----------------\n\n- Fixed the problem that ``datetime`` objects generated from\n computations used to fail ``isinstance`` tests.\n\n0.2.1 (2012-11-22)\n------------------\n\n- Fixed issue with ``datetime.time`` masking\n\n0.1 (2012-07-15)\n----------------\n\n- initial version", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://bitbucket.org/anybox/anybox.testing.datetime", "keywords": null, "license": "GPLv3+", "maintainer": null, "maintainer_email": null, "name": "anybox.testing.datetime", "package_url": "https://pypi.org/project/anybox.testing.datetime/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/anybox.testing.datetime/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://bitbucket.org/anybox/anybox.testing.datetime" }, "release_url": "https://pypi.org/project/anybox.testing.datetime/0.5/", "requires_dist": null, "requires_python": null, "summary": "Various utilities related to date and time for testing purposes.", "version": "0.5" }, "last_serial": 1502323, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "9f09bf14faa2ae6db348c207e17b334a", "sha256": "ca4f8af0fc67cb77c073b5d2c5a2996b40dfeabe212a084658a721fea93cc455" }, "downloads": -1, "filename": "anybox.testing.datetime-0.1.tar.gz", "has_sig": false, "md5_digest": "9f09bf14faa2ae6db348c207e17b334a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2999, "upload_time": "2012-07-15T15:28:53", "url": "https://files.pythonhosted.org/packages/2b/48/b1f7a5d3a3560e3d9376b50f100db11b1fb464dde996d9a42b8eaead5446/anybox.testing.datetime-0.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "5bef7da5a8c0a3e7d0048b17132704a1", "sha256": "17d383300892be46586e77b00018fe89ca865784cafee09884f2922ef8655b80" }, "downloads": -1, "filename": "anybox.testing.datetime-0.2.tar.gz", "has_sig": false, "md5_digest": "5bef7da5a8c0a3e7d0048b17132704a1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3062, "upload_time": "2012-11-22T11:56:42", "url": "https://files.pythonhosted.org/packages/8e/61/9fa60948f7a54dbcd3068c7a0b53d919ecefe45241c9890e2ac1d1cb58e0/anybox.testing.datetime-0.2.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "7a7497eccd1a6c34101e79705238b182", "sha256": "10e5366c14e799b013219bc638e73d03a6f1e33a4b20c98b0d02f27163c8f614" }, "downloads": -1, "filename": "anybox.testing.datetime-0.2.1.tar.gz", "has_sig": false, "md5_digest": "7a7497eccd1a6c34101e79705238b182", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3221, "upload_time": "2012-11-22T13:55:59", "url": "https://files.pythonhosted.org/packages/aa/68/24f4ee7a91cb32eaacc7f97bb58b72eb9a0cf365064df9091363386a15c4/anybox.testing.datetime-0.2.1.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "fdedecfc40ea94c0cf3a12be51d252c3", "sha256": "175c26e0548c563d8e44122ec0e7049ecec39f8b1ad4d962ed04d3a819dee853" }, "downloads": -1, "filename": "anybox.testing.datetime-0.3.tar.gz", "has_sig": false, "md5_digest": "fdedecfc40ea94c0cf3a12be51d252c3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3946, "upload_time": "2012-11-23T11:55:31", "url": "https://files.pythonhosted.org/packages/d8/66/318272d79ac152f35627cec4a7cfc660e2ea896c8a0a506bed81995a41f9/anybox.testing.datetime-0.3.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "443558027a73897a1dee6cae6ac70973", "sha256": "16c31c28809e742281993ad44f7a3676147b7af7a9b3b68395883e1ed8d44a6f" }, "downloads": -1, "filename": "anybox.testing.datetime-0.3.1.tar.gz", "has_sig": false, "md5_digest": "443558027a73897a1dee6cae6ac70973", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4271, "upload_time": "2012-11-28T17:03:27", "url": "https://files.pythonhosted.org/packages/a8/f7/4f4020be861098be70efb4d18e0a9fd1ec1b755c5abbc00eb7bc584ec814/anybox.testing.datetime-0.3.1.tar.gz" } ], "0.4": [ { "comment_text": "", "digests": { "md5": "2255b57be2a0cd3a571184631139ae02", "sha256": "c39689bc53c3844cdd10867eb5ba85c60fe6cc15423d084d944b629c40990bd6" }, "downloads": -1, "filename": "anybox.testing.datetime-0.4.tar.gz", "has_sig": false, "md5_digest": "2255b57be2a0cd3a571184631139ae02", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5608, "upload_time": "2013-04-24T21:22:37", "url": "https://files.pythonhosted.org/packages/54/47/ec2a78b286d856cd3df2100185f75ddff21374f54bcd0da83f016bb34b1f/anybox.testing.datetime-0.4.tar.gz" } ], "0.4.1": [ { "comment_text": "", "digests": { "md5": "98b8cb470afd8747a5632948810f4120", "sha256": "20bf9f0954359069216feaecbe01420df04aa5e5d5543e4baeadf383fc6d897e" }, "downloads": -1, "filename": "anybox.testing.datetime-0.4.1.tar.gz", "has_sig": false, "md5_digest": "98b8cb470afd8747a5632948810f4120", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5614, "upload_time": "2013-04-24T21:25:21", "url": "https://files.pythonhosted.org/packages/a7/2a/0f7a87909f4bc1b61d4a492ac39b5d7f0284e732dc5d94f67dc58ad275fd/anybox.testing.datetime-0.4.1.tar.gz" } ], "0.4.2": [ { "comment_text": "", "digests": { "md5": "349f9aa1eb12a3ca0706e1cbc97bf6c3", "sha256": "83be65f8d55b37c765d0f919a5adaa625bc1b6f5e50de96d82d692480ec01869" }, "downloads": -1, "filename": "anybox.testing.datetime-0.4.2.tar.gz", "has_sig": false, "md5_digest": "349f9aa1eb12a3ca0706e1cbc97bf6c3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5828, "upload_time": "2013-06-11T08:44:27", "url": "https://files.pythonhosted.org/packages/b6/ac/df485f9b62b8f7e6b0340157b973f014a5cce6feee025cf7ef45db6e41cc/anybox.testing.datetime-0.4.2.tar.gz" } ], "0.5": [ { "comment_text": "", "digests": { "md5": "4f634645d98b69c486aff69ec81556b4", "sha256": "a35ece0d42866109255c46a02f13d539cca956418bd144a70e86b3feec0fb995" }, "downloads": -1, "filename": "anybox.testing.datetime-0.5.tar.gz", "has_sig": false, "md5_digest": "4f634645d98b69c486aff69ec81556b4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7369, "upload_time": "2015-04-12T17:18:09", "url": "https://files.pythonhosted.org/packages/49/d6/c7dbbe10d0dc3abdaa9a0950582f4f87f5a349987c8b1d8f3563c9ca0a8d/anybox.testing.datetime-0.5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "4f634645d98b69c486aff69ec81556b4", "sha256": "a35ece0d42866109255c46a02f13d539cca956418bd144a70e86b3feec0fb995" }, "downloads": -1, "filename": "anybox.testing.datetime-0.5.tar.gz", "has_sig": false, "md5_digest": "4f634645d98b69c486aff69ec81556b4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7369, "upload_time": "2015-04-12T17:18:09", "url": "https://files.pythonhosted.org/packages/49/d6/c7dbbe10d0dc3abdaa9a0950582f4f87f5a349987c8b1d8f3563c9ca0a8d/anybox.testing.datetime-0.5.tar.gz" } ] }