Name | hiro JSON |
Version |
1.1.1
JSON |
| download |
home_page | http://hiro.readthedocs.org |
Summary | time manipulation utilities for testing in python |
upload_time | 2023-01-11 18:53:07 |
maintainer | |
docs_url | None |
author | Ali-Akber Saifee |
requires_python | |
license | MIT |
keywords |
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
.. |ci| image:: https://github.com/alisaifee/hiro/workflows/CI/badge.svg?branch=master
:target: https://github.com/alisaifee/hiro/actions?query=branch%3Amaster+workflow%3ACI
.. |coveralls| image:: https://img.shields.io/coveralls/alisaifee/hiro/master.svg?style=flat-square
:target: https://coveralls.io/r/alisaifee/hiro?branch=master
.. |license| image:: https://img.shields.io/pypi/l/hiro.svg?style=flat-square
:target: https://pypi.python.org/pypi/hiro
.. |pypi| image:: https://img.shields.io/pypi/v/hiro.svg?style=flat-square
:target: https://pypi.python.org/pypi/hiro
.. |docs| image:: https://readthedocs.org/projects/hiro/badge
:target: https://hiro.readthedocs.org
********************************************************
Hiro - time manipulation utilities for testing in python
********************************************************
|ci| |coveralls| |pypi| |docs| |license|
Yatta!
-- Hiro Nakamura
====================
Hiro context manager
====================
Timeline context
================
The ``hiro.Timeline`` context manager hijacks a few commonly used time functions
to allow time manipulation within its context. Specifically ``time.sleep``, ``time.time``,
``time.gmtime``, ``datetime.now``, ``datetime.utcnow`` and ``datetime.today`` behave according the configuration of the context.
The context provides the following manipulation options:
* ``rewind``: accepts seconds as an integer or a ``timedelta`` object.
* ``forward``: accepts seconds as an integer or a ``timedelta`` object.
* ``freeze``: accepts a floating point time since epoch or ``datetime`` or ``date`` object to freeze the time at.
* ``unfreeze``: resumes time from the point it was frozen at.
* ``scale``: accepts a floating point to accelerate/decelerate time by. ``> 1 = acceleration, < 1 = deceleration``
* ``reset``: resets all time alterations.
.. code-block:: python
import hiro
from datetime import timedelta, datetime
import time
datetime.now().isoformat()
# OUT: '2013-12-01T06:55:41.706060'
with hiro.Timeline() as timeline:
# forward by an hour
timeline.forward(60*60)
datetime.now().isoformat()
# OUT: '2013-12-01T07:55:41.707383'
# jump forward by 10 minutes
timeline.forward(timedelta(minutes=10))
datetime.now().isoformat()
# OUT: '2013-12-01T08:05:41.707425'
# jump to yesterday and freeze
timeline.freeze(datetime.now() - timedelta(hours=24))
datetime.now().isoformat()
# OUT: '2013-11-30T09:15:41'
timeline.scale(5) # scale time by 5x
time.sleep(5) # this will effectively only sleep for 1 second
# since time is frozen the sleep has no effect
datetime.now().isoformat()
# OUT: '2013-11-30T09:15:41'
timeline.rewind(timedelta(days=365))
datetime.now().isoformat()
# OUT: '2012-11-30T09:15:41'
To reduce the amount of statements inside the context, certain timeline setup
tasks can be done via the constructor and/or by using the fluent interface.
.. code-block:: python
import hiro
import time
from datetime import timedelta, datetime
start_point = datetime(2012,12,12,0,0,0)
my_timeline = hiro.Timeline(scale=5).forward(60*60).freeze()
with my_timeline as timeline:
print datetime.now()
# OUT: '2012-12-12 01:00:00.000315'
time.sleep(5) # effectively 1 second
# no effect as time is frozen
datetime.now()
# OUT: '2012-12-12 01:00:00.000315'
timeline.unfreeze()
# back to starting point
datetime.now()
# OUT: '2012-12-12 01:00:00.000317'
time.sleep(5) # effectively 1 second
# takes effect (+5 seconds)
datetime.now()
# OUT: '2012-12-12 01:00:05.003100'
``Timeline`` can additionally be used as a decorator
.. code-block:: python
import hiro
import time, datetime
@hiro.Timeline(scale=50000)
def sleeper():
datetime.datetime.now()
# OUT: '2013-11-30 14:27:43.409291'
time.sleep(60*60) # effectively 72 ms
datetime.datetime.now()
# OUT: '2013-11-30 15:28:36.240675'
@hiro.Timeline()
def sleeper_aware(timeline):
datetime.datetime.now()
# OUT: '2013-11-30 14:27:43.409291'
timeline.forward(60*60)
datetime.datetime.now()
# OUT: '2013-11-30 15:28:36.240675'
==============
Hiro executors
==============
In order to execute certain callables within a ``Timeline`` context, two
shortcut functions are provided.
* ``run_sync(factor=1, callable, *args, **kwargs)``
* ``run_async(factor=1, callable, *args, **kwargs)``
Both functions return a ``ScaledRunner`` object which provides the following methods
* ``get_execution_time``: The actual execution time of the ``callable``
* ``get_response`` (will either return the actual return value of ``callable`` or raise the exception that was thrown)
``run_async`` returns a derived class of ``ScaledRunner`` that additionally provides the following methods
* ``is_running``: ``True/False`` depending on whether the callable has completed execution
* ``join``: blocks until the ``callable`` completes execution
Example
=======
.. code-block:: python
import hiro
import time
def _slow_function(n):
time.sleep(n)
if n > 10:
raise RuntimeError()
return n
runner = hiro.run_sync(10, _slow_function, 10)
runner.get_response()
# OUT: 10
# due to the scale factor 10 it only took 1s to execute
runner.get_execution_time()
# OUT: 1.1052658557891846
runner = hiro.run_async(10, _slow_function, 11)
runner.is_running()
# OUT: True
runner.join()
runner.get_execution_time()
# OUT: 1.1052658557891846
runner.get_response()
# OUT: Traceback (most recent call last):
# ....
# OUT: File "<input>", line 4, in _slow_function
# OUT: RuntimeError
.. :changelog:
Changelog
=========
v1.1.1
------
Release Date: 2023-01-11
Chore:
* Fix github release action
v1.1.0
------
Release Date: 2023-01-11
Features:
* Patch time.time_ns, time.monotonic, time.monotonic_ns, time.localtime
Bug Fix:
* Ensure time.gmtime and time.localtime work with 0 values
* Ensure Timeline can be instantiated with start=0 to reflect time=0
* Improve naming of threaded classes/functions
Deprecation:
* Deprecated `run_async` in favor of `run_threaded`
v1.0.2
------
Release Date: 2023-01-11
Chores:
* Update documentation theme
v1.0.1
------
Release Date: 2023-01-11
Compatibility:
* Update package classifiers to reflect python version support
v1.0.0
------
Release Date: 2023-01-10
Compatibility:
* Drop support for python < 3.7
* Update sources to not need six for compatibility
Chores:
* Standardize linting
* Add Asia/Shanghai to CI matrix
v0.5.1
------
Release Date: 2019-10-10
Code cleanup
v0.5
----
Release Date: 2017-07-26
Bug Fix:
* Account for microsecond resolution (`Pull Request 3 <https://github.com/alisaifee/hiro/pull/3>`_)
v0.1.8
------
Release Date: 2015-06-07
* Add Python 3.x support
v0.1.5
------
Release Date: 2014-04-03
Bug Fix:
* Imports from time weren't being patched.
v0.1.3
------
Release Date: 2014-04-01
Enhanced timeline decorator to pass generated timeline
to decorated function
v0.1.2
------
Release Date: 2014-02-20
* Added blacklist for unpatchable modules
* CI improvements
* removed ScaledTimeline
v0.1.1
------
Release Date: 2013-12-05
Added pypy support
v0.0.3
------
Release Date: 2013-11-30
Allow ScaledTimeline to be used as a decorator
v0.0.1
------
Release Date: 2013-11-30
Initial Release
Raw data
{
"_id": null,
"home_page": "http://hiro.readthedocs.org",
"name": "hiro",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "",
"author": "Ali-Akber Saifee",
"author_email": "ali@indydevs.org.com",
"download_url": "https://files.pythonhosted.org/packages/cf/95/599234434ba653eced63898e47ab4c2adcce301876cd223f25f8dcf84ca6/hiro-1.1.1.tar.gz",
"platform": null,
"description": ".. |ci| image:: https://github.com/alisaifee/hiro/workflows/CI/badge.svg?branch=master\n :target: https://github.com/alisaifee/hiro/actions?query=branch%3Amaster+workflow%3ACI\n.. |coveralls| image:: https://img.shields.io/coveralls/alisaifee/hiro/master.svg?style=flat-square\n :target: https://coveralls.io/r/alisaifee/hiro?branch=master\n.. |license| image:: https://img.shields.io/pypi/l/hiro.svg?style=flat-square\n :target: https://pypi.python.org/pypi/hiro\n.. |pypi| image:: https://img.shields.io/pypi/v/hiro.svg?style=flat-square\n :target: https://pypi.python.org/pypi/hiro\n.. |docs| image:: https://readthedocs.org/projects/hiro/badge\n :target: https://hiro.readthedocs.org\n\n\n********************************************************\nHiro - time manipulation utilities for testing in python\n********************************************************\n|ci| |coveralls| |pypi| |docs| |license|\n\n Yatta!\n\n -- Hiro Nakamura\n\n\n\n====================\nHiro context manager\n====================\n\n\nTimeline context\n================\nThe ``hiro.Timeline`` context manager hijacks a few commonly used time functions\nto allow time manipulation within its context. Specifically ``time.sleep``, ``time.time``,\n``time.gmtime``, ``datetime.now``, ``datetime.utcnow`` and ``datetime.today`` behave according the configuration of the context.\n\nThe context provides the following manipulation options:\n\n* ``rewind``: accepts seconds as an integer or a ``timedelta`` object.\n* ``forward``: accepts seconds as an integer or a ``timedelta`` object.\n* ``freeze``: accepts a floating point time since epoch or ``datetime`` or ``date`` object to freeze the time at.\n* ``unfreeze``: resumes time from the point it was frozen at.\n* ``scale``: accepts a floating point to accelerate/decelerate time by. ``> 1 = acceleration, < 1 = deceleration``\n* ``reset``: resets all time alterations.\n\n.. code-block:: python\n\n import hiro\n from datetime import timedelta, datetime\n import time\n\n datetime.now().isoformat()\n # OUT: '2013-12-01T06:55:41.706060'\n with hiro.Timeline() as timeline:\n\n # forward by an hour\n timeline.forward(60*60)\n datetime.now().isoformat()\n # OUT: '2013-12-01T07:55:41.707383'\n\n # jump forward by 10 minutes\n timeline.forward(timedelta(minutes=10))\n datetime.now().isoformat()\n # OUT: '2013-12-01T08:05:41.707425'\n\n # jump to yesterday and freeze\n timeline.freeze(datetime.now() - timedelta(hours=24))\n datetime.now().isoformat()\n # OUT: '2013-11-30T09:15:41'\n\n timeline.scale(5) # scale time by 5x\n time.sleep(5) # this will effectively only sleep for 1 second\n\n # since time is frozen the sleep has no effect\n datetime.now().isoformat()\n # OUT: '2013-11-30T09:15:41'\n\n timeline.rewind(timedelta(days=365))\n\n datetime.now().isoformat()\n # OUT: '2012-11-30T09:15:41'\n\n\n\nTo reduce the amount of statements inside the context, certain timeline setup\ntasks can be done via the constructor and/or by using the fluent interface.\n\n.. code-block:: python\n\n import hiro\n import time\n from datetime import timedelta, datetime\n\n start_point = datetime(2012,12,12,0,0,0)\n my_timeline = hiro.Timeline(scale=5).forward(60*60).freeze()\n with my_timeline as timeline:\n print datetime.now()\n # OUT: '2012-12-12 01:00:00.000315'\n time.sleep(5) # effectively 1 second\n # no effect as time is frozen\n datetime.now()\n # OUT: '2012-12-12 01:00:00.000315'\n timeline.unfreeze()\n # back to starting point\n datetime.now()\n # OUT: '2012-12-12 01:00:00.000317'\n time.sleep(5) # effectively 1 second\n # takes effect (+5 seconds)\n datetime.now()\n # OUT: '2012-12-12 01:00:05.003100'\n\n\n``Timeline`` can additionally be used as a decorator\n\n.. code-block:: python\n\n import hiro\n import time, datetime\n\n @hiro.Timeline(scale=50000)\n def sleeper():\n datetime.datetime.now()\n # OUT: '2013-11-30 14:27:43.409291'\n time.sleep(60*60) # effectively 72 ms\n datetime.datetime.now()\n # OUT: '2013-11-30 15:28:36.240675'\n\n @hiro.Timeline()\n def sleeper_aware(timeline):\n datetime.datetime.now()\n # OUT: '2013-11-30 14:27:43.409291'\n timeline.forward(60*60)\n datetime.datetime.now()\n # OUT: '2013-11-30 15:28:36.240675'\n\n==============\nHiro executors\n==============\n\nIn order to execute certain callables within a ``Timeline`` context, two\nshortcut functions are provided.\n\n* ``run_sync(factor=1, callable, *args, **kwargs)``\n* ``run_async(factor=1, callable, *args, **kwargs)``\n\nBoth functions return a ``ScaledRunner`` object which provides the following methods\n\n* ``get_execution_time``: The actual execution time of the ``callable``\n* ``get_response`` (will either return the actual return value of ``callable`` or raise the exception that was thrown)\n\n``run_async`` returns a derived class of ``ScaledRunner`` that additionally provides the following methods\n\n* ``is_running``: ``True/False`` depending on whether the callable has completed execution\n* ``join``: blocks until the ``callable`` completes execution\n\n\nExample\n=======\n\n.. code-block:: python\n\n\n import hiro\n import time\n\n def _slow_function(n):\n time.sleep(n)\n if n > 10:\n raise RuntimeError()\n return n\n\n runner = hiro.run_sync(10, _slow_function, 10)\n runner.get_response()\n # OUT: 10\n\n # due to the scale factor 10 it only took 1s to execute\n runner.get_execution_time()\n # OUT: 1.1052658557891846\n\n runner = hiro.run_async(10, _slow_function, 11)\n runner.is_running()\n # OUT: True\n runner.join()\n runner.get_execution_time()\n # OUT: 1.1052658557891846\n runner.get_response()\n # OUT: Traceback (most recent call last):\n # ....\n # OUT: File \"<input>\", line 4, in _slow_function\n # OUT: RuntimeError\n\n\n\n.. :changelog:\n\nChangelog\n=========\n\nv1.1.1\n------\nRelease Date: 2023-01-11\n\nChore:\n * Fix github release action\n\nv1.1.0\n------\nRelease Date: 2023-01-11\n\nFeatures:\n * Patch time.time_ns, time.monotonic, time.monotonic_ns, time.localtime\n\nBug Fix:\n * Ensure time.gmtime and time.localtime work with 0 values\n * Ensure Timeline can be instantiated with start=0 to reflect time=0\n * Improve naming of threaded classes/functions\n\nDeprecation:\n * Deprecated `run_async` in favor of `run_threaded`\n\nv1.0.2\n------\nRelease Date: 2023-01-11\n\nChores:\n * Update documentation theme\n\nv1.0.1\n------\nRelease Date: 2023-01-11\n\nCompatibility:\n * Update package classifiers to reflect python version support\n\nv1.0.0\n------\nRelease Date: 2023-01-10\n\nCompatibility:\n * Drop support for python < 3.7\n * Update sources to not need six for compatibility\n\nChores:\n * Standardize linting\n * Add Asia/Shanghai to CI matrix\n\n\nv0.5.1\n------\nRelease Date: 2019-10-10\n\nCode cleanup\n\nv0.5\n----\nRelease Date: 2017-07-26\n\nBug Fix:\n * Account for microsecond resolution (`Pull Request 3 <https://github.com/alisaifee/hiro/pull/3>`_)\n\nv0.1.8\n------\nRelease Date: 2015-06-07\n\n* Add Python 3.x support\n\nv0.1.5\n------\nRelease Date: 2014-04-03\n\nBug Fix:\n * Imports from time weren't being patched.\n\nv0.1.3\n------\nRelease Date: 2014-04-01\n\nEnhanced timeline decorator to pass generated timeline\nto decorated function\n\nv0.1.2\n------\nRelease Date: 2014-02-20\n\n* Added blacklist for unpatchable modules\n* CI improvements\n* removed ScaledTimeline\n\nv0.1.1\n------\nRelease Date: 2013-12-05\n\nAdded pypy support\n\nv0.0.3\n------\nRelease Date: 2013-11-30\n\nAllow ScaledTimeline to be used as a decorator\n\nv0.0.1\n------\nRelease Date: 2013-11-30\n\nInitial Release\n\n\n\n\n\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "time manipulation utilities for testing in python",
"version": "1.1.1",
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "7a92d3aaecfec045aa2f640438642f1524c8c59011b1a098d7aeab79c97d7f11",
"md5": "a48010f0916394f8576d79303fc68ad4",
"sha256": "72496af06a9dbec7f1da871f3a0ec207c7a962048563063a2a02797c5d27653d"
},
"downloads": -1,
"filename": "hiro-1.1.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "a48010f0916394f8576d79303fc68ad4",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 11425,
"upload_time": "2023-01-11T18:53:05",
"upload_time_iso_8601": "2023-01-11T18:53:05.833839Z",
"url": "https://files.pythonhosted.org/packages/7a/92/d3aaecfec045aa2f640438642f1524c8c59011b1a098d7aeab79c97d7f11/hiro-1.1.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "cf95599234434ba653eced63898e47ab4c2adcce301876cd223f25f8dcf84ca6",
"md5": "794159beac4d6bc5234d3918a47f672c",
"sha256": "da3339af1dc9a594cca9dc9c71c725272b2e306604e45d0e0575cd13c5f95d68"
},
"downloads": -1,
"filename": "hiro-1.1.1.tar.gz",
"has_sig": false,
"md5_digest": "794159beac4d6bc5234d3918a47f672c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 31024,
"upload_time": "2023-01-11T18:53:07",
"upload_time_iso_8601": "2023-01-11T18:53:07.839465Z",
"url": "https://files.pythonhosted.org/packages/cf/95/599234434ba653eced63898e47ab4c2adcce301876cd223f25f8dcf84ca6/hiro-1.1.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-01-11 18:53:07",
"github": false,
"gitlab": false,
"bitbucket": false,
"lcname": "hiro"
}