Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for time.monotonic() #199

Closed
wants to merge 2 commits into from

Conversation

Artimi
Copy link

@Artimi Artimi commented Jul 13, 2017

Hello, for our testing purposes we needed freezegun to work also with time.monotonic() https://docs.python.org/3/library/time.html#time.monotonic . Specifically we need asyncio's call_later function to work properly with frozen time. Our use case is as follows:

import freezegun
async def consume(generator):
	with freezegun.freeze_time(None) as frozen_datetime:
		for message in generator:
			frozen_datetime.move_to(message.time)
			await process(message)      

So we need to have time frozen in process. But when in process is some asyncio.call_later it is called according to real time (time.monotonic()). To overcome this I have written this PR, that also patches time.monotonic() .
This works good for our purpose but there is a hidden catch: when you use await asyncio.sleep(delta) in process() it will hang indefinitely: it makes sense time.monotonic is stopped so it does not know how long it should wait. This might be surprising so I'm pointing this out if we want to have this behavior in freezegun by default or it should be an option to freeze_time.
I need to sleep for a moment in that loop so scheduled coroutines have chance to process so I'm using this little hack:

@contextlib.contextmanager
def freeze_sleep(frozen_datetime):

	original_asyncio_sleep = asyncio.sleep

	async def move_time(delta):
		frozen_datetime.tick(delta)

	async def freeze_sleep(delta):
		asyncio.ensure_future(move_time(delta))
		await original_asyncio_sleep(delta)

	asyncio.sleep = freeze_sleep

	yield

	asyncio.sleep = original_asyncio_sleep

That patches asyncio.sleep so it will perform but also will move frozen_datetime by time to sleep.
What do you think about this PR?

@coveralls
Copy link

coveralls commented Jul 13, 2017

Coverage Status

Coverage increased (+0.2%) to 96.164% when pulling 2c1a724 on qntln:feature/time-monotonic into 385a78d on spulec:master.

@Artimi
Copy link
Author

Artimi commented Aug 29, 2017

@spulec What do you think about this PR? I have added ability to ignore time.monotonic and also other functions.

@coveralls
Copy link

coveralls commented Aug 29, 2017

Coverage Status

Coverage decreased (-0.02%) to 95.949% when pulling d165c16 on qntln:feature/time-monotonic into 385a78d on spulec:master.

@vitawasalreadytaken
Copy link

Hi @spulec, what do you think about this PR? Is it good to be merged and released?

@spulec
Copy link
Owner

spulec commented Nov 4, 2017

It seems the tests are failing in a recursive loop. Any idea why?

@Artimi
Copy link
Author

Artimi commented Nov 9, 2017

@spulec I looked into this but with no success. When I run it using makefile it fails, but when I run nosetest directly from command line it ends with two errors:

$ nosetests --with-coverage ./tests/
nose.plugins.cover: ERROR: Coverage not available: unable to import coverage module
......................S..............SSS......S......S...S.........................EE...
======================================================================
ERROR: Failure: ImportError (No module named mock)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/nose/loader.py", line 418, in loadTestsFromName
    addr.filename, addr.module)
  File "/usr/lib/python2.7/dist-packages/nose/importer.py", line 47, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/usr/lib/python2.7/dist-packages/nose/importer.py", line 94, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
  File "/home/sebekpet/projects/freezegun/tests/test_ticking.py", line 3, in <module>
    import mock
ImportError: No module named mock

======================================================================
ERROR: Failure: ImportError (No module named mock)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/nose/loader.py", line 418, in loadTestsFromName
    addr.filename, addr.module)
  File "/usr/lib/python2.7/dist-packages/nose/importer.py", line 47, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/usr/lib/python2.7/dist-packages/nose/importer.py", line 94, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
  File "/home/sebekpet/projects/freezegun/tests/test_utils.py", line 1, in <module>
    import mock
ImportError: No module named mock

----------------------------------------------------------------------
Ran 88 tests in 0.828s

FAILED (SKIP=7, errors=2)

It is strange that problem occurs directly in nose before testing actually starts AFAIK:

  File "/home/sebekpet/.virtualenvs/freezegun2.6/lib/python2.6/site-packages/nose/core.py", line 207, in runTests
    result = self.testRunner.run(self.test)
  File "/home/sebekpet/.virtualenvs/freezegun2.6/lib/python2.6/site-packages/nose/core.py", line 65, in run
    stop = time.time()
  File "/home/sebekpet/projects/freezegun/freezegun/api.py", line 65, in __call__
    return calendar.timegm(current_time.timetuple()) + current_time.microsecond / 1000000.0
  File "/usr/lib/python2.6/calendar.py", line 608, in timegm
    days = datetime.date(year, month, 1).toordinal() - _EPOCH_ORD + day - 1
  File "/home/sebekpet/projects/freezegun/freezegun/api.py", line 130, in __new__
    return real_date.__new__(cls, *args, **kwargs)

Do you have some idea why is this happening?

@spulec
Copy link
Owner

spulec commented Mar 6, 2018

I'm not sure and unfortunately don't have time to look into it right now.

Feel free to rebase and dig into the tests and we can take another look.

@jmehnle
Copy link
Contributor

jmehnle commented Dec 23, 2020

This was added in #369. This PR can be closed.

@boxed boxed closed this Dec 23, 2020
@boxed
Copy link
Contributor

boxed commented Dec 23, 2020

Thanks @jmehnle for the heads up

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants