{"id":15501706,"url":"https://github.com/gonzalo-bulnes/stime","last_synced_at":"2025-04-06T04:17:46.288Z","repository":{"id":57471478,"uuid":"193195764","full_name":"gonzalo-bulnes/stime","owner":"gonzalo-bulnes","description":"🦉 A testing (and partial) replacement for Python's time package, for fully-controlled time-dependent tests.","archived":false,"fork":false,"pushed_at":"2019-06-23T05:39:46.000Z","size":53,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-04-04T20:12:31.876Z","etag":null,"topics":["simulation","testing-tools","time"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gonzalo-bulnes.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-06-22T05:35:52.000Z","updated_at":"2023-10-01T11:15:33.000Z","dependencies_parsed_at":"2022-09-26T17:40:27.422Z","dependency_job_id":null,"html_url":"https://github.com/gonzalo-bulnes/stime","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzalo-bulnes%2Fstime","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzalo-bulnes%2Fstime/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzalo-bulnes%2Fstime/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gonzalo-bulnes%2Fstime/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gonzalo-bulnes","download_url":"https://codeload.github.com/gonzalo-bulnes/stime/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247430976,"owners_count":20937876,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["simulation","testing-tools","time"],"created_at":"2024-10-02T09:05:23.255Z","updated_at":"2025-04-06T04:17:46.023Z","avatar_url":"https://github.com/gonzalo-bulnes.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align='center'\u003e\u003cimg width=\"128\" src='./vendor/noto-emoji-owl.png' alt=\"🦉 An owl emoji\"/\u003e\u003c/p\u003e\n\u003ch1 align='center'\u003eSimulated Time\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003eA testing (and partial) replacement for Python's \u003ccode\u003etime\u003c/code\u003e package, for fully-controlled time-dependent tests.\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://pypi.org/project/stime\"\u003e\u003cimg alt=\"PyPI\" src=\"https://img.shields.io/pypi/v/stime.svg\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://travis-ci.org/gonzalo-bulnes/stime\"\u003e\u003cimg alt=\"Build Status\" src=\"https://travis-ci.org/gonzalo-bulnes/stime.svg?branch=master\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cbr /\u003e\u003cbr /\u003e\n\nTesting functions that depend on time is always tricky, and can take long. To save time and avoid relying on `time.sleep()`, this package allows to fast-forward time arbitrarily.\n\nIt implements the functions `stime.time()` and `stime.monotonic()`.\n\n\u003cbr /\u003e\n\n\u003e **Note**: This package in not meant to replace [`time`][time] in production! Only in testing environments!\n\n  [time]: https://docs.python.org/3/library/time.html\n\nUsage\n-----\n\nThe idea is to make your code to use `stime.test()` instead of `time.test()` while it is being tested.\n\nIdeally, the code you want to test is receiving a time source through [dependency injection][di], like the `Timer` class in the example below.\n\n  [di]: https://www.jamesshore.com/Blog/Dependency-Injection-Demystified.html\n\nIf the code you are testing is not using dependency injection, it is likely that you can still override the time function in your tests. That is less elegant, but can be a fair trade-off to avoid having its test suite rely on `time.sleep()`.\n\nOnce your code is using `stime`, you can precisely control the output of `stime.time()` (or `stime.monotonic()`) using `stime.reset()` and `stime.tick()`:\n\n- **`tick(n)`**: increments the current time by `n` seconds (e.g. `1.3` seconds)\n- **`reset(t)`**: (re-)sets the current time to the timestamp `t` (e.g. `1561120200`)\n\n### Example\n\nFind the full code for this example in [`examples/timer`](./examples/timer)!\n\n```python\n# test_timer.py\n\nimport unittest\nimport stime # ①\nfrom timer import Timer # your package with time-dependent functions to be tested\n\nclass TestTimer(unittest.TestCase):\n\n    def test_timer_rings_for_five_seconds_starting_at_alarm_time(self):\n        # create a new timer using stime as a time source\n        cooking_timer = Timer(time_source=stime)\n        cooking_timer.set_alarm(1561120200) # Unix timestamp for 21 June 2019 around noon\n\n        stime.reset(1561120199) # ② a second before alarm time\n        is_ringing = cooking_timer.is_ringing() # calls stime.time() because it is the timer time_source\n        self.assertEqual(is_ringing, False, \"expected the timer NOT to ring before alarm time\")\n\n        stime.reset(1561120200) # ③ exactly alarm time\n        is_ringing = cooking_timer.is_ringing() # calls stime.time() because it is the timer time_source\n        self.assertEqual(is_ringing, True, \"expected the timer to ring at alarm time\")\n\n        stime.tick(5) # ④ 5 seconds after alarm time\n        is_ringing = cooking_timer.is_ringing() # calls stime.time() because it is the timer time_source\n        self.assertEqual(is_ringing, True, \"expected the timer to be ringing 5 seconds after alarm time\")\n\n        stime.tick() # ⑤ add 1 more second\n        is_ringing = cooking_timer.is_ringing() # calls stime.time() because it is the timer time_source\n        self.assertEqual(is_ringing, False, \"expected the timer NOT to be ringing 6 seconds after alarm time\")\n\n# [...]\n```\n\n- ① Import `stime` where you would have imported `time` if it wasn't testing.\n- ② Set the current time to whatever is convenient...\n- ③ Reset it as often as needed...\n- ④ Fast-forward when convenient...\n- ⑤ or progress one second at a time!\n\nDevelopment\n-----------\n\n### Getting started\n\nOptionally, create a virtual environment for this project and activate it.\n\n```bash\npython -m venv venv # assuming Python 3\n. venv/bin/activate\n```\n\nThen do your thing!\n\n```bash\n# run the test suite:\npython stime/test_stime.py\n\n# once you're done deactivate the virtual environment if you use one:\ndeactivate\n```\n\n### Release\n\n```bash\n# Install the latest setuptools and wheel (I put them in the same virtual environment)\npip install --upgrade setuptools wheel\n\n# Update the package version number and tag it:\nvim setup.py\ngit tag -a 'v1.0.0' -m 'Initial release'\ngit push origin master --tags\n\n# Build the distribution files\nmake build\n\n# And upload them to PyPI\nmake upload_to_pypi\n```\n\nContributing\n------------\n\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-e7359e.svg?style=popout)](http://makeapullrequest.com)\n![Code Review Welcome](https://img.shields.io/badge/code%20review-welcome-e7359e.svg?style=popout)\n\nI am [learning Python](https://github.com/gonzalo-bulnes/kata-python-web-app)! 🎉\n\nThis is the first package I publish and I did it very much to figure out how things work. That's to say that I'd love to hear your thoughts, maybe we can learn something together : )\n\nWhether it is your first pull request or your 100th, the [contributing guidelines][contributing] are here to help you get started!\n\nPlease note that by participating in this project, you agree to abide by its [code of conduct]. That is true for pull requests, and also when participating in issues.\n\n  [contributing]: ./CONTRIBUTING.md\n  [code of conduct]: ./CODE_OF_CONDUCT.md\n\nCredits\n-------\n\nThe owl emoji in the header was rendered from an SVG that belongs to Google and [was published under the Apache License v2.0 as part of Noto Emoji](https://github.com/googlei18n/noto-emoji).\n\nLicense\n-------\n\n    stime\n    Copyright (C) 2019 Gonzalo Bulnes Guilpain\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgonzalo-bulnes%2Fstime","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgonzalo-bulnes%2Fstime","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgonzalo-bulnes%2Fstime/lists"}