pax_global_header00006660000000000000000000000064141752263430014521gustar00rootroot0000000000000052 comment=9c945414674072009d933e64054866cbc820b8e7 freezegun-1.1.0/000077500000000000000000000000001417522634300135125ustar00rootroot00000000000000freezegun-1.1.0/.coveragerc000066400000000000000000000000341417522634300156300ustar00rootroot00000000000000[run] include = freezegun/* freezegun-1.1.0/.travis.yml000066400000000000000000000002271417522634300156240ustar00rootroot00000000000000language: python python: - 3.5 - 3.6 - 3.7 - 3.8 - 3.9 - pypy3 install: pip install tox-travis script: tox after_success: - coveralls freezegun-1.1.0/AUTHORS.rst000066400000000000000000000014731417522634300153760ustar00rootroot00000000000000Patches and Suggestions ``````````````````````` - `Dan Miller `_ - `Matthew Schinckel `_ - `JJ Geewax `_ - `Roman Imankulov `_ - `Martin Geisler `_ - `Richard Eames `_ - `Tye Wang `_ - `Andreas Pelme `_ - `Jesse London `_ - `Zach Smith `_ - `Adam Johnson `_ - `Alex Ehlke `_ - `James Lu `_ - `Dan Elkis `_ - `Bastien Vallet `_ - `Julian Mehnle `_ - `Lukasz Balcerzak `_ freezegun-1.1.0/CHANGELOG000066400000000000000000000025161417522634300147300ustar00rootroot00000000000000Freezegun Changelog =================== 1.1.0 ----- * Add support for `time.monotonic` (and `…_ns`) * Allow to configure default ignore list, and also to just extend the default * Fixed when accessing from thread after stop() 1.0.0 ------ * Dropped Py2 support * Added as_kwarg argument in order to have the frozen time object passed with the name provided in as_kwarg argument 0.3.15 ------ * Fix locale timestamp bug. CC #328 0.3.14 ------ * Fix calendar.timegm behavior 0.3.13 ------ * Fix for Py3.8 * Reset time.time_ns on stop 0.3.12 ------ * Refactor classes to functions * Ignore Selenium * Move to pytest * Conditionally patch time.clock * Patch time.time_ns added in Python 3.7 0.3.11 ------ * Performance improvements * Fix nesting time.time * Add nanosecond property 0.3.10 ------ * Performance improvements * Coroutine support 0.3.9 ----- * If no time to be frozen, use current time * Fix uuid1 issues * Add support for python 3.6 0.3.8 ----- * Bugfix for old-style classes * Ignore warnings when patching * Add `move_to` method to change time 0.3.7 ----- * Fix CPython detection 0.3.6 ----- * Catch TypeError when fetching attribute values * Speed improvements * Add manual tick increment 0.3.5 ----- * Add `tick` argument to allow time to move forward * Performance improvements * Fix timezone example in README freezegun-1.1.0/LICENSE000066400000000000000000000251221417522634300145210ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2012 Steve Pulec Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.freezegun-1.1.0/MANIFEST.in000066400000000000000000000002151417522634300152460ustar00rootroot00000000000000include README.rst LICENSE AUTHORS.rst CHANGELOG pyproject.toml recursive-include tests * global-exclude __pycache__ global-exclude *.py[co] freezegun-1.1.0/Makefile000066400000000000000000000006021417522634300151500ustar00rootroot00000000000000SHELL := /bin/bash init: python setup.py develop pip install -r requirements.txt test: rm -f .coverage pytest travis: pytest --cov tdaemon: tdaemon -t nose ./tests/ --custom-args="--with-growl" tag: python create_tag.py publish: rm -rf dist python -m pep517.build --source --binary . twine upload dist/* venv: virtualenv venv venv/bin/pip install -r requirements.txt freezegun-1.1.0/README.rst000066400000000000000000000235671417522634300152160ustar00rootroot00000000000000FreezeGun: Let your Python tests travel through time ==================================================== .. image:: https://img.shields.io/pypi/v/freezegun.svg :target: https://pypi.python.org/pypi/freezegun/ .. image:: https://secure.travis-ci.org/spulec/freezegun.svg?branch=master :target: https://travis-ci.org/spulec/freezegun .. image:: https://coveralls.io/repos/spulec/freezegun/badge.svg?branch=master :target: https://coveralls.io/r/spulec/freezegun FreezeGun is a library that allows your Python tests to travel through time by mocking the datetime module. Usage ----- Once the decorator or context manager have been invoked, all calls to datetime.datetime.now(), datetime.datetime.utcnow(), datetime.date.today(), time.time(), time.localtime(), time.gmtime(), and time.strftime() will return the time that has been frozen. time.monotonic() will also be frozen, but as usual it makes no guarantees about its absolute value, only its changes over time. Decorator ~~~~~~~~~ .. code-block:: python from freezegun import freeze_time import datetime import unittest # Freeze time for a pytest style test: @freeze_time("2012-01-14") def test(): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) # Or a unittest TestCase - freezes for every test, from the start of setUpClass to the end of tearDownClass @freeze_time("1955-11-12") class MyTests(unittest.TestCase): def test_the_class(self): assert datetime.datetime.now() == datetime.datetime(1955, 11, 12) # Or any other class - freezes around each callable (may not work in every case) @freeze_time("2012-01-14") class Tester(object): def test_the_class(self): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) # Or method decorator, might also pass frozen time object as kwarg class TestUnitTestMethodDecorator(unittest.TestCase): @freeze_time('2013-04-09') def test_method_decorator_works_on_unittest(self): self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) @freeze_time('2013-04-09', as_kwarg='frozen_time') def test_method_decorator_works_on_unittest(self, frozen_time): self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) self.assertEqual(datetime.date(2013, 4, 9), frozen_time.time_to_freeze.today()) @freeze_time('2013-04-09', as_kwarg='hello') def test_method_decorator_works_on_unittest(self, **kwargs): self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) self.assertEqual(datetime.date(2013, 4, 9), kwargs.get('hello').time_to_freeze.today()) Context manager ~~~~~~~~~~~~~~~ .. code-block:: python from freezegun import freeze_time def test(): assert datetime.datetime.now() != datetime.datetime(2012, 1, 14) with freeze_time("2012-01-14"): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) assert datetime.datetime.now() != datetime.datetime(2012, 1, 14) Raw use ~~~~~~~ .. code-block:: python from freezegun import freeze_time freezer = freeze_time("2012-01-14 12:00:01") freezer.start() assert datetime.datetime.now() == datetime.datetime(2012, 1, 14, 12, 0, 1) freezer.stop() Timezones ~~~~~~~~~ .. code-block:: python from freezegun import freeze_time @freeze_time("2012-01-14 03:21:34", tz_offset=-4) def test(): assert datetime.datetime.utcnow() == datetime.datetime(2012, 1, 14, 3, 21, 34) assert datetime.datetime.now() == datetime.datetime(2012, 1, 13, 23, 21, 34) # datetime.date.today() uses local time assert datetime.date.today() == datetime.date(2012, 1, 13) @freeze_time("2012-01-14 03:21:34", tz_offset=-datetime.timedelta(hours=3, minutes=30)) def test_timedelta_offset(): assert datetime.datetime.now() == datetime.datetime(2012, 1, 13, 23, 51, 34) Nice inputs ~~~~~~~~~~~ FreezeGun uses dateutil behind the scenes so you can have nice-looking datetimes. .. code-block:: python @freeze_time("Jan 14th, 2012") def test_nice_datetime(): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) Function and generator objects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FreezeGun is able to handle function and generator objects. .. code-block:: python def test_lambda(): with freeze_time(lambda: datetime.datetime(2012, 1, 14)): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) def test_generator(): datetimes = (datetime.datetime(year, 1, 1) for year in range(2010, 2012)) with freeze_time(datetimes): assert datetime.datetime.now() == datetime.datetime(2010, 1, 1) with freeze_time(datetimes): assert datetime.datetime.now() == datetime.datetime(2011, 1, 1) # The next call to freeze_time(datetimes) would raise a StopIteration exception. ``tick`` argument ~~~~~~~~~~~~~~~~~ FreezeGun has an additional ``tick`` argument which will restart time at the given value, but then time will keep ticking. This is alternative to the default parameters which will keep time stopped. .. code-block:: python @freeze_time("Jan 14th, 2020", tick=True) def test_nice_datetime(): assert datetime.datetime.now() > datetime.datetime(2020, 1, 14) ``auto_tick_seconds`` argument ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FreezeGun has an additional ``auto_tick_seconds`` argument which will autoincrement the value every time by the given amount from the start value. This is alternative to the default parameters which will keep time stopped. Note that given ``auto_tick_seconds`` the ``tick`` parameter will be ignored. .. code-block:: python @freeze_time("Jan 14th, 2020", auto_tick_seconds=15) def test_nice_datetime(): first_time = datetime.datetime.now() auto_incremented_time = datetime.datetime.now() assert first_time + datetime.timedelta(seconds=15) == auto_incremented_time Manual ticks ~~~~~~~~~~~~ FreezeGun allows for the time to be manually forwarded as well. .. code-block:: python def test_manual_tick(): initial_datetime = datetime.datetime(year=1, month=7, day=12, hour=15, minute=6, second=3) with freeze_time(initial_datetime) as frozen_datetime: assert frozen_datetime() == initial_datetime frozen_datetime.tick() initial_datetime += datetime.timedelta(seconds=1) assert frozen_datetime() == initial_datetime frozen_datetime.tick(delta=datetime.timedelta(seconds=10)) initial_datetime += datetime.timedelta(seconds=10) assert frozen_datetime() == initial_datetime .. code-block:: python def test_monotonic_manual_tick(): initial_datetime = datetime.datetime(year=1, month=7, day=12, hour=15, minute=6, second=3) with freeze_time(initial_datetime) as frozen_datetime: monotonic_t0 = time.monotonic() frozen_datetime.tick(1.0) monotonic_t1 = time.monotonic() assert monotonic_t1 == monotonic_t0 + 1.0 Moving time to specify datetime ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FreezeGun allows moving time to specific dates. .. code-block:: python def test_move_to(): initial_datetime = datetime.datetime(year=1, month=7, day=12, hour=15, minute=6, second=3) other_datetime = datetime.datetime(year=2, month=8, day=13, hour=14, minute=5, second=0) with freeze_time(initial_datetime) as frozen_datetime: assert frozen_datetime() == initial_datetime frozen_datetime.move_to(other_datetime) assert frozen_datetime() == other_datetime frozen_datetime.move_to(initial_datetime) assert frozen_datetime() == initial_datetime @freeze_time("2012-01-14", as_arg=True) def test(frozen_time): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) frozen_time.move_to("2014-02-12") assert datetime.datetime.now() == datetime.datetime(2014, 2, 12) Parameter for ``move_to`` can be any valid ``freeze_time`` date (string, date, datetime). Default arguments ~~~~~~~~~~~~~~~~~ Note that FreezeGun will not modify default arguments. The following code will print the current date. See `here `_ for why. .. code-block:: python from freezegun import freeze_time import datetime as dt def test(default=dt.date.today()): print(default) with freeze_time('2000-1-1'): test() Installation ------------ To install FreezeGun, simply: .. code-block:: bash $ pip install freezegun On Debian systems: .. code-block:: bash $ sudo apt-get install python-freezegun Ignore packages --------------- Sometimes it's desired to ignore FreezeGun behaviour for particular packages (i.e. libraries). It's possible to ignore them for a single invocation: .. code-block:: python from freezegun import freeze_time with freeze_time('2020-10-06', ignore=['threading']): # ... By default FreezeGun ignores following packages: .. code-block:: python [ 'nose.plugins', 'six.moves', 'django.utils.six.moves', 'google.gax', 'threading', 'Queue', 'selenium', '_pytest.terminal.', '_pytest.runner.', 'gi', ] It's possible to set your own default ignore list: .. code-block:: python import freezegun freezegun.configure(default_ignore_list=['threading', 'tensorflow']) Please note this will override default ignore list. If you want to extend existing defaults please use: .. code-block:: python import freezegun freezegun.configure(extend_ignore_list=['tensorflow']) freezegun-1.1.0/create_tag.py000066400000000000000000000010641417522634300161630ustar00rootroot00000000000000import os import re def read_version(): with open(os.path.join('freezegun', '__init__.py')) as f: m = re.search(r'''__version__\s*=\s*['"]([^'"]*)['"]''', f.read()) if m: return m.group(1) raise ValueError("couldn't find version") def create_tag(): from subprocess import call version = read_version() errno = call(['git', 'tag', '--annotate', version, '--message', 'Version %s' % version]) if errno == 0: print("Added tag for version %s" % version) if __name__ == '__main__': create_tag() freezegun-1.1.0/freezegun/000077500000000000000000000000001417522634300155045ustar00rootroot00000000000000freezegun-1.1.0/freezegun/__init__.py000066400000000000000000000005301417522634300176130ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ freezegun ~~~~~~~~ :copyright: (c) 2012 by Steve Pulec. """ from .api import freeze_time from .config import configure __title__ = 'freezegun' __version__ = '1.1.0' __author__ = 'Steve Pulec' __license__ = 'Apache License 2.0' __copyright__ = 'Copyright 2012 Steve Pulec' __all__ = ["freeze_time", "configure"] freezegun-1.1.0/freezegun/_async.py000066400000000000000000000005721417522634300173360ustar00rootroot00000000000000import functools def wrap_coroutine(api, coroutine): @functools.wraps(coroutine) async def wrapper(*args, **kwargs): with api as time_factory: if api.as_arg: result = await coroutine(time_factory, *args, **kwargs) else: result = await coroutine(*args, **kwargs) return result return wrapper freezegun-1.1.0/freezegun/_async_coroutine.py000066400000000000000000000006451417522634300214260ustar00rootroot00000000000000import functools import asyncio def wrap_coroutine(api, coroutine): @functools.wraps(coroutine) @asyncio.coroutine def wrapper(*args, **kwargs): with api as time_factory: if api.as_arg: result = yield from coroutine(time_factory, *args, **kwargs) else: result = yield from coroutine(*args, **kwargs) return result return wrapper freezegun-1.1.0/freezegun/api.py000066400000000000000000000656171417522634300166460ustar00rootroot00000000000000from . import config import dateutil import datetime import functools import sys import time import uuid import calendar import unittest import platform import warnings import types import numbers import inspect from dateutil import parser from dateutil.tz import tzlocal try: from maya import MayaDT except ImportError: MayaDT = None _TIME_NS_PRESENT = hasattr(time, 'time_ns') _MONOTONIC_NS_PRESENT = hasattr(time, 'monotonic_ns') _EPOCH = datetime.datetime(1970, 1, 1) _EPOCHTZ = datetime.datetime(1970, 1, 1, tzinfo=dateutil.tz.UTC) real_time = time.time real_localtime = time.localtime real_gmtime = time.gmtime real_monotonic = time.monotonic real_strftime = time.strftime real_date = datetime.date real_datetime = datetime.datetime real_date_objects = [real_time, real_localtime, real_gmtime, real_monotonic, real_strftime, real_date, real_datetime] if _TIME_NS_PRESENT: real_time_ns = time.time_ns real_date_objects.append(real_time_ns) if _MONOTONIC_NS_PRESENT: real_monotonic_ns = time.monotonic_ns real_date_objects.append(real_monotonic_ns) _real_time_object_ids = {id(obj) for obj in real_date_objects} # time.clock is deprecated and was removed in Python 3.8 real_clock = getattr(time, 'clock', None) freeze_factories = [] tz_offsets = [] ignore_lists = [] tick_flags = [] # Python3 doesn't have basestring, but it does have str. try: # noinspection PyUnresolvedReferences _string_type = basestring except NameError: _string_type = str try: # noinspection PyUnresolvedReferences real_uuid_generate_time = uuid._uuid_generate_time uuid_generate_time_attr = '_uuid_generate_time' except AttributeError: # noinspection PyUnresolvedReferences uuid._load_system_functions() # noinspection PyUnresolvedReferences real_uuid_generate_time = uuid._generate_time_safe uuid_generate_time_attr = '_generate_time_safe' except ImportError: real_uuid_generate_time = None uuid_generate_time_attr = None try: # noinspection PyUnresolvedReferences real_uuid_create = uuid._UuidCreate except (AttributeError, ImportError): real_uuid_create = None try: import copy_reg as copyreg except ImportError: import copyreg try: iscoroutinefunction = inspect.iscoroutinefunction if sys.version_info < (3, 5): from freezegun._async_coroutine import wrap_coroutine else: from freezegun._async import wrap_coroutine except AttributeError: iscoroutinefunction = lambda x: False def wrap_coroutine(*args): raise NotImplementedError() # keep a cache of module attributes otherwise freezegun will need to analyze too many modules all the time _GLOBAL_MODULES_CACHE = {} def _get_module_attributes(module): result = [] try: module_attributes = dir(module) except (ImportError, TypeError): return result for attribute_name in module_attributes: try: attribute_value = getattr(module, attribute_name) except (ImportError, AttributeError, TypeError): # For certain libraries, this can result in ImportError(_winreg) or AttributeError (celery) continue else: result.append((attribute_name, attribute_value)) return result def _setup_module_cache(module): date_attrs = [] all_module_attributes = _get_module_attributes(module) for attribute_name, attribute_value in all_module_attributes: if id(attribute_value) in _real_time_object_ids: date_attrs.append((attribute_name, attribute_value)) _GLOBAL_MODULES_CACHE[module.__name__] = (_get_module_attributes_hash(module), date_attrs) def _get_module_attributes_hash(module): try: module_dir = dir(module) except (ImportError, TypeError): module_dir = [] return '{}-{}'.format(id(module), hash(frozenset(module_dir))) def _get_cached_module_attributes(module): module_hash, cached_attrs = _GLOBAL_MODULES_CACHE.get(module.__name__, ('0', [])) if _get_module_attributes_hash(module) == module_hash: return cached_attrs # cache miss: update the cache and return the refreshed value _setup_module_cache(module) # return the newly cached value module_hash, cached_attrs = _GLOBAL_MODULES_CACHE[module.__name__] return cached_attrs # Stolen from six def with_metaclass(meta, *bases): """Create a base class with a metaclass.""" return meta("NewBase", bases, {}) _is_cpython = ( hasattr(platform, 'python_implementation') and platform.python_implementation().lower() == "cpython" ) call_stack_inspection_limit = 5 def _should_use_real_time(): if not call_stack_inspection_limit: return False # Means stop() has already been called, so we can now return the real time if not ignore_lists: return True if not ignore_lists[-1]: return False frame = inspect.currentframe().f_back.f_back for _ in range(call_stack_inspection_limit): module_name = frame.f_globals.get('__name__') if module_name and module_name.startswith(ignore_lists[-1]): return True frame = frame.f_back if frame is None: break return False def get_current_time(): return freeze_factories[-1]() def fake_time(): if _should_use_real_time(): return real_time() current_time = get_current_time() return calendar.timegm(current_time.timetuple()) + current_time.microsecond / 1000000.0 if _TIME_NS_PRESENT: def fake_time_ns(): if _should_use_real_time(): return real_time_ns() return int(int(fake_time()) * 1e9) def fake_localtime(t=None): if t is not None: return real_localtime(t) if _should_use_real_time(): return real_localtime() shifted_time = get_current_time() - datetime.timedelta(seconds=time.timezone) return shifted_time.timetuple() def fake_gmtime(t=None): if t is not None: return real_gmtime(t) if _should_use_real_time(): return real_gmtime() return get_current_time().timetuple() def fake_monotonic(): if _should_use_real_time(): return real_monotonic() current_time = get_current_time() return calendar.timegm(current_time.timetuple()) + current_time.microsecond / 1000000.0 if _MONOTONIC_NS_PRESENT: def fake_monotonic_ns(): if _should_use_real_time(): return real_monotonic_ns() current_time = get_current_time() return ( calendar.timegm(current_time.timetuple()) * 1000000 + current_time.microsecond ) * 1000 def fake_strftime(format, time_to_format=None): if time_to_format is None: if not _should_use_real_time(): time_to_format = fake_localtime() if time_to_format is None: return real_strftime(format) else: return real_strftime(format, time_to_format) if real_clock is not None: def fake_clock(): if _should_use_real_time(): return real_clock() if len(freeze_factories) == 1: return 0.0 if not tick_flags[-1] else real_clock() first_frozen_time = freeze_factories[0]() last_frozen_time = get_current_time() timedelta = (last_frozen_time - first_frozen_time) total_seconds = timedelta.total_seconds() if tick_flags[-1]: total_seconds += real_clock() return total_seconds class FakeDateMeta(type): @classmethod def __instancecheck__(self, obj): return isinstance(obj, real_date) @classmethod def __subclasscheck__(cls, subclass): return issubclass(subclass, real_date) def datetime_to_fakedatetime(datetime): return FakeDatetime(datetime.year, datetime.month, datetime.day, datetime.hour, datetime.minute, datetime.second, datetime.microsecond, datetime.tzinfo) def date_to_fakedate(date): return FakeDate(date.year, date.month, date.day) class FakeDate(with_metaclass(FakeDateMeta, real_date)): def __new__(cls, *args, **kwargs): return real_date.__new__(cls, *args, **kwargs) def __add__(self, other): result = real_date.__add__(self, other) if result is NotImplemented: return result return date_to_fakedate(result) def __sub__(self, other): result = real_date.__sub__(self, other) if result is NotImplemented: return result if isinstance(result, real_date): return date_to_fakedate(result) else: return result @classmethod def today(cls): result = cls._date_to_freeze() + cls._tz_offset() return date_to_fakedate(result) @staticmethod def _date_to_freeze(): return get_current_time() @classmethod def _tz_offset(cls): return tz_offsets[-1] FakeDate.min = date_to_fakedate(real_date.min) FakeDate.max = date_to_fakedate(real_date.max) class FakeDatetimeMeta(FakeDateMeta): @classmethod def __instancecheck__(self, obj): return isinstance(obj, real_datetime) @classmethod def __subclasscheck__(cls, subclass): return issubclass(subclass, real_datetime) class FakeDatetime(with_metaclass(FakeDatetimeMeta, real_datetime, FakeDate)): def __new__(cls, *args, **kwargs): return real_datetime.__new__(cls, *args, **kwargs) def __add__(self, other): result = real_datetime.__add__(self, other) if result is NotImplemented: return result return datetime_to_fakedatetime(result) def __sub__(self, other): result = real_datetime.__sub__(self, other) if result is NotImplemented: return result if isinstance(result, real_datetime): return datetime_to_fakedatetime(result) else: return result def astimezone(self, tz=None): if tz is None: tz = tzlocal() return datetime_to_fakedatetime(real_datetime.astimezone(self, tz)) @classmethod def fromtimestamp(cls, t, tz=None): if tz is None: return real_datetime.fromtimestamp( t, tz=dateutil.tz.tzoffset("freezegun", cls._tz_offset()) ).replace(tzinfo=None) return datetime_to_fakedatetime(real_datetime.fromtimestamp(t, tz)) def timestamp(self): if self.tzinfo is None: return (self - _EPOCH - self._tz_offset()).total_seconds() return (self - _EPOCHTZ).total_seconds() @classmethod def now(cls, tz=None): now = cls._time_to_freeze() or real_datetime.now() if tz: result = tz.fromutc(now.replace(tzinfo=tz)) + cls._tz_offset() else: result = now + cls._tz_offset() return datetime_to_fakedatetime(result) def date(self): return date_to_fakedate(self) @property def nanosecond(self): try: # noinspection PyUnresolvedReferences return real_datetime.nanosecond except AttributeError: return 0 @classmethod def today(cls): return cls.now(tz=None) @classmethod def utcnow(cls): result = cls._time_to_freeze() or real_datetime.utcnow() return datetime_to_fakedatetime(result) @staticmethod def _time_to_freeze(): if freeze_factories: return get_current_time() @classmethod def _tz_offset(cls): return tz_offsets[-1] FakeDatetime.min = datetime_to_fakedatetime(real_datetime.min) FakeDatetime.max = datetime_to_fakedatetime(real_datetime.max) def convert_to_timezone_naive(time_to_freeze): """ Converts a potentially timezone-aware datetime to be a naive UTC datetime """ if time_to_freeze.tzinfo: time_to_freeze -= time_to_freeze.utcoffset() time_to_freeze = time_to_freeze.replace(tzinfo=None) return time_to_freeze def pickle_fake_date(datetime_): # A pickle function for FakeDate return FakeDate, ( datetime_.year, datetime_.month, datetime_.day, ) def pickle_fake_datetime(datetime_): # A pickle function for FakeDatetime return FakeDatetime, ( datetime_.year, datetime_.month, datetime_.day, datetime_.hour, datetime_.minute, datetime_.second, datetime_.microsecond, datetime_.tzinfo, ) def _parse_time_to_freeze(time_to_freeze_str): """Parses all the possible inputs for freeze_time :returns: a naive ``datetime.datetime`` object """ if time_to_freeze_str is None: time_to_freeze_str = datetime.datetime.utcnow() if isinstance(time_to_freeze_str, datetime.datetime): time_to_freeze = time_to_freeze_str elif isinstance(time_to_freeze_str, datetime.date): time_to_freeze = datetime.datetime.combine(time_to_freeze_str, datetime.time()) elif isinstance(time_to_freeze_str, datetime.timedelta): time_to_freeze = datetime.datetime.utcnow() + time_to_freeze_str else: time_to_freeze = parser.parse(time_to_freeze_str) return convert_to_timezone_naive(time_to_freeze) def _parse_tz_offset(tz_offset): if isinstance(tz_offset, datetime.timedelta): return tz_offset else: return datetime.timedelta(hours=tz_offset) class TickingDateTimeFactory(object): def __init__(self, time_to_freeze, start): self.time_to_freeze = time_to_freeze self.start = start def __call__(self): return self.time_to_freeze + (real_datetime.now() - self.start) class FrozenDateTimeFactory(object): def __init__(self, time_to_freeze): self.time_to_freeze = time_to_freeze def __call__(self): return self.time_to_freeze def tick(self, delta=datetime.timedelta(seconds=1)): if isinstance(delta, numbers.Real): # noinspection PyTypeChecker self.time_to_freeze += datetime.timedelta(seconds=delta) else: self.time_to_freeze += delta def move_to(self, target_datetime): """Moves frozen date to the given ``target_datetime``""" target_datetime = _parse_time_to_freeze(target_datetime) delta = target_datetime - self.time_to_freeze self.tick(delta=delta) class StepTickTimeFactory(object): def __init__(self, time_to_freeze, step_width): self.time_to_freeze = time_to_freeze self.step_width = step_width def __call__(self): return_time = self.time_to_freeze self.tick() return return_time def tick(self, delta=None): if not delta: delta = datetime.timedelta(seconds=self.step_width) self.time_to_freeze += delta def update_step_width(self, step_width): self.step_width = step_width def move_to(self, target_datetime): """Moves frozen date to the given ``target_datetime``""" target_datetime = _parse_time_to_freeze(target_datetime) delta = target_datetime - self.time_to_freeze self.tick(delta=delta) class _freeze_time(object): def __init__(self, time_to_freeze_str, tz_offset, ignore, tick, as_arg, as_kwarg, auto_tick_seconds): self.time_to_freeze = _parse_time_to_freeze(time_to_freeze_str) self.tz_offset = _parse_tz_offset(tz_offset) self.ignore = tuple(ignore) self.tick = tick self.auto_tick_seconds = auto_tick_seconds self.undo_changes = [] self.modules_at_start = set() self.as_arg = as_arg self.as_kwarg = as_kwarg def __call__(self, func): if inspect.isclass(func): return self.decorate_class(func) elif iscoroutinefunction(func): return self.decorate_coroutine(func) return self.decorate_callable(func) def decorate_class(self, klass): if issubclass(klass, unittest.TestCase): # If it's a TestCase, we assume you want to freeze the time for the # tests, from setUpClass to tearDownClass # Use getattr as in Python 2.6 they are optional orig_setUpClass = getattr(klass, 'setUpClass', None) orig_tearDownClass = getattr(klass, 'tearDownClass', None) # noinspection PyDecorator @classmethod def setUpClass(cls): self.start() if orig_setUpClass is not None: orig_setUpClass() # noinspection PyDecorator @classmethod def tearDownClass(cls): if orig_tearDownClass is not None: orig_tearDownClass() self.stop() klass.setUpClass = setUpClass klass.tearDownClass = tearDownClass return klass else: seen = set() klasses = klass.mro() if hasattr(klass, 'mro') else [klass] + list(klass.__bases__) for base_klass in klasses: for (attr, attr_value) in base_klass.__dict__.items(): if attr.startswith('_') or attr in seen: continue seen.add(attr) if not callable(attr_value) or inspect.isclass(attr_value): continue try: setattr(klass, attr, self(attr_value)) except (AttributeError, TypeError): # Sometimes we can't set this for built-in types and custom callables continue return klass def __enter__(self): return self.start() def __exit__(self, *args): self.stop() def start(self): if self.auto_tick_seconds: freeze_factory = StepTickTimeFactory(self.time_to_freeze, self.auto_tick_seconds) elif self.tick: freeze_factory = TickingDateTimeFactory(self.time_to_freeze, real_datetime.now()) else: freeze_factory = FrozenDateTimeFactory(self.time_to_freeze) is_already_started = len(freeze_factories) > 0 freeze_factories.append(freeze_factory) tz_offsets.append(self.tz_offset) ignore_lists.append(self.ignore) tick_flags.append(self.tick) if is_already_started: return freeze_factory # Change the modules datetime.datetime = FakeDatetime datetime.date = FakeDate time.time = fake_time time.monotonic = fake_monotonic time.localtime = fake_localtime time.gmtime = fake_gmtime time.strftime = fake_strftime if uuid_generate_time_attr: setattr(uuid, uuid_generate_time_attr, None) uuid._UuidCreate = None uuid._last_timestamp = None copyreg.dispatch_table[real_datetime] = pickle_fake_datetime copyreg.dispatch_table[real_date] = pickle_fake_date # Change any place where the module had already been imported to_patch = [ ('real_date', real_date, FakeDate), ('real_datetime', real_datetime, FakeDatetime), ('real_gmtime', real_gmtime, fake_gmtime), ('real_localtime', real_localtime, fake_localtime), ('real_monotonic', real_monotonic, fake_monotonic), ('real_strftime', real_strftime, fake_strftime), ('real_time', real_time, fake_time), ] if _TIME_NS_PRESENT: time.time_ns = fake_time_ns to_patch.append(('real_time_ns', real_time_ns, fake_time_ns)) if _MONOTONIC_NS_PRESENT: time.monotonic_ns = fake_monotonic_ns to_patch.append(('real_monotonic_ns', real_monotonic_ns, fake_monotonic_ns)) if real_clock is not None: # time.clock is deprecated and was removed in Python 3.8 time.clock = fake_clock to_patch.append(('real_clock', real_clock, fake_clock)) self.fake_names = tuple(fake.__name__ for real_name, real, fake in to_patch) self.reals = {id(fake): real for real_name, real, fake in to_patch} fakes = {id(real): fake for real_name, real, fake in to_patch} add_change = self.undo_changes.append # Save the current loaded modules self.modules_at_start = set(sys.modules.keys()) with warnings.catch_warnings(): warnings.filterwarnings('ignore') for mod_name, module in list(sys.modules.items()): if mod_name is None or module is None or mod_name == __name__: continue elif mod_name.startswith(self.ignore) or mod_name.endswith('.six.moves'): continue elif (not hasattr(module, "__name__") or module.__name__ in ('datetime', 'time')): continue module_attrs = _get_cached_module_attributes(module) for attribute_name, attribute_value in module_attrs: fake = fakes.get(id(attribute_value)) if fake: setattr(module, attribute_name, fake) add_change((module, attribute_name, attribute_value)) return freeze_factory def stop(self): freeze_factories.pop() ignore_lists.pop() tick_flags.pop() tz_offsets.pop() if not freeze_factories: datetime.datetime = real_datetime datetime.date = real_date copyreg.dispatch_table.pop(real_datetime) copyreg.dispatch_table.pop(real_date) for module, module_attribute, original_value in self.undo_changes: setattr(module, module_attribute, original_value) self.undo_changes = [] # Restore modules loaded after start() modules_to_restore = set(sys.modules.keys()) - self.modules_at_start self.modules_at_start = set() with warnings.catch_warnings(): warnings.simplefilter('ignore') for mod_name in modules_to_restore: module = sys.modules.get(mod_name, None) if mod_name is None or module is None: continue elif mod_name.startswith(self.ignore) or mod_name.endswith('.six.moves'): continue elif not hasattr(module, "__name__") or module.__name__ in ('datetime', 'time'): continue for module_attribute in dir(module): if module_attribute in self.fake_names: continue try: attribute_value = getattr(module, module_attribute) except (ImportError, AttributeError, TypeError): # For certain libraries, this can result in ImportError(_winreg) or AttributeError (celery) continue real = self.reals.get(id(attribute_value)) if real: setattr(module, module_attribute, real) time.time = real_time time.monotonic = real_monotonic time.gmtime = real_gmtime time.localtime = real_localtime time.strftime = real_strftime time.clock = real_clock if _TIME_NS_PRESENT: time.time_ns = real_time_ns if _MONOTONIC_NS_PRESENT: time.monotonic_ns = real_monotonic_ns if uuid_generate_time_attr: setattr(uuid, uuid_generate_time_attr, real_uuid_generate_time) uuid._UuidCreate = real_uuid_create uuid._last_timestamp = None def decorate_coroutine(self, coroutine): return wrap_coroutine(self, coroutine) def decorate_callable(self, func): def wrapper(*args, **kwargs): with self as time_factory: if self.as_arg and self.as_kwarg: assert False, "You can't specify both as_arg and as_kwarg at the same time. Pick one." elif self.as_arg: result = func(time_factory, *args, **kwargs) elif self.as_kwarg: kwargs[self.as_kwarg] = time_factory result = func(*args, **kwargs) else: result = func(*args, **kwargs) return result functools.update_wrapper(wrapper, func) # update_wrapper already sets __wrapped__ in Python 3.2+, this is only # needed for Python 2.x support wrapper.__wrapped__ = func return wrapper def freeze_time(time_to_freeze=None, tz_offset=0, ignore=None, tick=False, as_arg=False, as_kwarg='', auto_tick_seconds=0): acceptable_times = (type(None), _string_type, datetime.date, datetime.timedelta, types.FunctionType, types.GeneratorType) if MayaDT is not None: acceptable_times += MayaDT, if not isinstance(time_to_freeze, acceptable_times): raise TypeError(('freeze_time() expected None, a string, date instance, datetime ' 'instance, MayaDT, timedelta instance, function or a generator, but got ' 'type {}.').format(type(time_to_freeze))) if tick and not _is_cpython: raise SystemError('Calling freeze_time with tick=True is only compatible with CPython') if isinstance(time_to_freeze, types.FunctionType): return freeze_time(time_to_freeze(), tz_offset, ignore, tick, auto_tick_seconds) if isinstance(time_to_freeze, types.GeneratorType): return freeze_time(next(time_to_freeze), tz_offset, ignore, tick, auto_tick_seconds) if MayaDT is not None and isinstance(time_to_freeze, MayaDT): return freeze_time(time_to_freeze.datetime(), tz_offset, ignore, tick, as_arg) if ignore is None: ignore = [] ignore = ignore[:] if config.settings.default_ignore_list: ignore.extend(config.settings.default_ignore_list) return _freeze_time( time_to_freeze_str=time_to_freeze, tz_offset=tz_offset, ignore=ignore, tick=tick, as_arg=as_arg, as_kwarg=as_kwarg, auto_tick_seconds=auto_tick_seconds, ) # Setup adapters for sqlite try: # noinspection PyUnresolvedReferences import sqlite3 except ImportError: # Some systems have trouble with this pass else: # These are copied from Python sqlite3.dbapi2 def adapt_date(val): return val.isoformat() def adapt_datetime(val): return val.isoformat(" ") sqlite3.register_adapter(FakeDate, adapt_date) sqlite3.register_adapter(FakeDatetime, adapt_datetime) # Setup converters for pymysql try: import pymysql.converters except ImportError: pass else: pymysql.converters.encoders[FakeDate] = pymysql.converters.encoders[real_date] pymysql.converters.conversions[FakeDate] = pymysql.converters.encoders[real_date] pymysql.converters.encoders[FakeDatetime] = pymysql.converters.encoders[real_datetime] pymysql.converters.conversions[FakeDatetime] = pymysql.converters.encoders[real_datetime] freezegun-1.1.0/freezegun/config.py000066400000000000000000000017051417522634300173260ustar00rootroot00000000000000 DEFAULT_IGNORE_LIST = [ 'nose.plugins', 'six.moves', 'django.utils.six.moves', 'google.gax', 'threading', 'Queue', 'selenium', '_pytest.terminal.', '_pytest.runner.', 'gi', ] class Settings: def __init__(self, default_ignore_list=None): self.default_ignore_list = default_ignore_list or DEFAULT_IGNORE_LIST[:] settings = Settings() class ConfigurationError(Exception): pass def configure(default_ignore_list=None, extend_ignore_list=None): if default_ignore_list is not None and extend_ignore_list is not None: raise ConfigurationError("Either default_ignore_list or extend_ignore_list might be given, not both") if default_ignore_list: settings.default_ignore_list = default_ignore_list if extend_ignore_list: settings.default_ignore_list = [*settings.default_ignore_list, *extend_ignore_list] def reset_config(): global settings settings = Settings() freezegun-1.1.0/pyproject.toml000066400000000000000000000001321417522634300164220ustar00rootroot00000000000000[build-system] requires = ["setuptools", "wheel"] build-backend = "setuptools.build_meta" freezegun-1.1.0/requirements.txt000066400000000000000000000000771417522634300170020ustar00rootroot00000000000000pytest pytest-coverage coveralls maya; python_version >= '3.7' freezegun-1.1.0/setup.cfg000066400000000000000000000001541417522634300153330ustar00rootroot00000000000000[nosetests] verbosity=1 detailed-errors=1 with-coverage=1 cover-package=freezegun [bdist_wheel] universal=1freezegun-1.1.0/setup.py000066400000000000000000000017341417522634300152310ustar00rootroot00000000000000#!/usr/bin/env python from setuptools import setup with open('README.rst') as f: readme = f.read() setup( name='freezegun', version='1.0.0', description='Let your Python tests travel through time', long_description=readme, author='Steve Pulec', author_email='spulec@gmail.com', url='https://github.com/spulec/freezegun', packages=['freezegun'], install_requires=['python-dateutil>=2.7'], include_package_data=True, license='Apache 2.0', python_requires='>=3.5', classifiers=[ 'License :: OSI Approved :: Apache Software License', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', ], ) freezegun-1.1.0/tests/000077500000000000000000000000001417522634300146545ustar00rootroot00000000000000freezegun-1.1.0/tests/__init__.py000066400000000000000000000000001417522634300167530ustar00rootroot00000000000000freezegun-1.1.0/tests/another_module.py000066400000000000000000000013751417522634300202410ustar00rootroot00000000000000from datetime import date, datetime from time import time, localtime, gmtime, strftime from freezegun.api import ( FakeDatetime, FakeDate, fake_time, fake_localtime, fake_gmtime, fake_strftime, ) # Reals def get_datetime(): return datetime def get_date(): return date def get_time(): return time def get_localtime(): return localtime def get_gmtime(): return gmtime def get_strftime(): return strftime # Fakes def get_fake_datetime(): return FakeDatetime def get_fake_date(): return FakeDate def get_fake_time(): return fake_time def get_fake_localtime(): return fake_localtime def get_fake_gmtime(): return fake_gmtime def get_fake_strftime(): return fake_strftime freezegun-1.1.0/tests/fake_module.py000066400000000000000000000011771417522634300175070ustar00rootroot00000000000000from datetime import date, datetime from time import time, localtime, gmtime, strftime def fake_datetime_function(): return datetime.now() def fake_date_function(): return date.today() def fake_time_function(): return time() def fake_localtime_function(): return localtime() def fake_gmtime_function(): return gmtime() def fake_strftime_function(): return strftime("%Y") class EqualToAnything(object): description = 'This is the equal_to_anything object' def __eq__(self, other): return True def __neq__(self, other): return False equal_to_anything = EqualToAnything() freezegun-1.1.0/tests/test_asyncio.py000066400000000000000000000015141417522634300177330ustar00rootroot00000000000000import asyncio import datetime from textwrap import dedent from unittest import SkipTest from freezegun import freeze_time def test_time_freeze_coroutine(): if not asyncio: raise SkipTest('asyncio required') @freeze_time('1970-01-01') async def frozen_coroutine(): assert datetime.date.today() == datetime.date(1970, 1, 1) asyncio.get_event_loop().run_until_complete(frozen_coroutine()) def test_time_freeze_async_def(): try: exec('async def foo(): pass') except SyntaxError: raise SkipTest('async def not supported') else: exec(dedent(''' @freeze_time('1970-01-01') async def frozen_coroutine(): assert datetime.date.today() == datetime.date(1970, 1, 1) asyncio.get_event_loop().run_until_complete(frozen_coroutine()) ''')) freezegun-1.1.0/tests/test_class_import.py000066400000000000000000000136521417522634300207730ustar00rootroot00000000000000import time import sys from .fake_module import ( fake_date_function, fake_datetime_function, fake_gmtime_function, fake_localtime_function, fake_strftime_function, fake_time_function, ) from . import fake_module from freezegun import freeze_time from freezegun.api import ( FakeDatetime, FakeDate, fake_time, fake_localtime, fake_gmtime, fake_strftime, ) import datetime @freeze_time("2012-01-14") def test_import_datetime_works(): assert fake_datetime_function().day == 14 @freeze_time("2012-01-14") def test_import_date_works(): assert fake_date_function().day == 14 @freeze_time("2012-01-14") def test_import_time(): local_time = datetime.datetime(2012, 1, 14) utc_time = local_time - datetime.timedelta(seconds=time.timezone) expected_timestamp = time.mktime(utc_time.timetuple()) assert fake_time_function() == expected_timestamp def test_start_and_stop_works(): freezer = freeze_time("2012-01-14") result = fake_datetime_function() assert result.__class__ == datetime.datetime assert result.__class__ != FakeDatetime freezer.start() assert fake_datetime_function().day == 14 assert isinstance(fake_datetime_function(), datetime.datetime) assert isinstance(fake_datetime_function(), FakeDatetime) freezer.stop() result = fake_datetime_function() assert result.__class__ == datetime.datetime assert result.__class__ != FakeDatetime def test_isinstance_works(): date = datetime.date.today() now = datetime.datetime.now() freezer = freeze_time('2011-01-01') freezer.start() assert isinstance(date, datetime.date) assert not isinstance(date, datetime.datetime) assert isinstance(now, datetime.datetime) assert isinstance(now, datetime.date) freezer.stop() def test_issubclass_works(): real_date = datetime.date real_datetime = datetime.datetime freezer = freeze_time('2011-01-01') freezer.start() assert issubclass(real_date, datetime.date) assert issubclass(real_datetime, datetime.datetime) freezer.stop() def test_fake_uses_real_when_ignored(): real_time_before = time.time() with freeze_time('2012-01-14', ignore=['tests.fake_module']): real_time = fake_time_function() real_time_after = time.time() assert real_time_before <= real_time <= real_time_after def test_can_ignore_email_module(): from email.utils import formatdate with freeze_time('2012-01-14'): faked_date_str = formatdate() before_date_str = formatdate() with freeze_time('2012-01-14', ignore=['email']): date_str = formatdate() after_date_str = formatdate() assert date_str != faked_date_str assert before_date_str <= date_str <= after_date_str @freeze_time('2011-01-01') def test_avoid_replacing_equal_to_anything(): assert fake_module.equal_to_anything.description == 'This is the equal_to_anything object' @freeze_time("2012-01-14 12:00:00") def test_import_localtime(): struct = fake_localtime_function() assert struct.tm_year == 2012 assert struct.tm_mon == 1 assert struct.tm_mday >= 13 # eg. GMT+14 assert struct.tm_mday <= 15 # eg. GMT-14 @freeze_time("2012-01-14 12:00:00") def test_fake_gmtime_function(): struct = fake_gmtime_function() assert struct.tm_year == 2012 assert struct.tm_mon == 1 assert struct.tm_mday == 14 @freeze_time("2012-01-14") def test_fake_strftime_function(): assert fake_strftime_function() == '2012' def test_import_after_start(): with freeze_time('2012-01-14'): assert 'tests.another_module' not in sys.modules.keys() from tests import another_module # Reals assert another_module.get_datetime() is datetime.datetime assert another_module.get_datetime() is FakeDatetime assert another_module.get_date() is datetime.date assert another_module.get_date() is FakeDate assert another_module.get_time() is time.time assert another_module.get_time() is fake_time assert another_module.get_localtime() is time.localtime assert another_module.get_localtime() is fake_localtime assert another_module.get_gmtime() is time.gmtime assert another_module.get_gmtime() is fake_gmtime assert another_module.get_strftime() is time.strftime assert another_module.get_strftime() is fake_strftime # Fakes assert another_module.get_fake_datetime() is FakeDatetime assert another_module.get_fake_date() is FakeDate assert another_module.get_fake_time() is fake_time assert another_module.get_fake_localtime() is fake_localtime assert another_module.get_fake_gmtime() is fake_gmtime assert another_module.get_fake_strftime() is fake_strftime # Reals assert another_module.get_datetime() is datetime.datetime assert not another_module.get_datetime() is FakeDatetime assert another_module.get_date() is datetime.date assert not another_module.get_date() is FakeDate assert another_module.get_time() is time.time assert not another_module.get_time() is fake_time assert another_module.get_localtime() is time.localtime assert not another_module.get_localtime() is fake_localtime assert another_module.get_gmtime() is time.gmtime assert not another_module.get_gmtime() is fake_gmtime assert another_module.get_strftime() is time.strftime assert not another_module.get_strftime() is fake_strftime # Fakes assert another_module.get_fake_datetime() is FakeDatetime assert another_module.get_fake_date() is FakeDate assert another_module.get_fake_time() is fake_time assert another_module.get_fake_localtime() is fake_localtime assert another_module.get_fake_gmtime() is fake_gmtime assert another_module.get_fake_strftime() is fake_strftime def test_none_as_initial(): with freeze_time() as ft: ft.move_to('2012-01-14') assert fake_strftime_function() == '2012' freezegun-1.1.0/tests/test_configure.py000066400000000000000000000032661417522634300202550ustar00rootroot00000000000000from unittest import mock import freezegun import freezegun.config def setup_function(): freezegun.config.reset_config() def teardown_function(): freezegun.config.reset_config() def test_default_ignore_list_is_overridden(): freezegun.configure(default_ignore_list=['threading', 'tensorflow']) with mock.patch("freezegun.api._freeze_time.__init__", return_value=None) as _freeze_time_init_mock: freezegun.freeze_time("2020-10-06") expected_ignore_list = [ 'threading', 'tensorflow', ] _freeze_time_init_mock.assert_called_once_with( time_to_freeze_str="2020-10-06", tz_offset=0, ignore=expected_ignore_list, tick=False, as_arg=False, as_kwarg='', auto_tick_seconds=0, ) def test_extend_default_ignore_list(): freezegun.configure(extend_ignore_list=['tensorflow']) with mock.patch("freezegun.api._freeze_time.__init__", return_value=None) as _freeze_time_init_mock: freezegun.freeze_time("2020-10-06") expected_ignore_list = [ 'nose.plugins', 'six.moves', 'django.utils.six.moves', 'google.gax', 'threading', 'Queue', 'selenium', '_pytest.terminal.', '_pytest.runner.', 'gi', 'tensorflow', ] _freeze_time_init_mock.assert_called_once_with( time_to_freeze_str="2020-10-06", tz_offset=0, ignore=expected_ignore_list, tick=False, as_arg=False, as_kwarg='', auto_tick_seconds=0, ) freezegun-1.1.0/tests/test_datetimes.py000066400000000000000000000657141417522634300202610ustar00rootroot00000000000000import time import calendar import datetime import unittest import locale import sys from unittest import SkipTest from dateutil.tz import UTC import pytest from tests import utils from freezegun import freeze_time from freezegun.api import FakeDatetime, FakeDate try: import maya except ImportError: maya = None # time.clock was removed in Python 3.8 HAS_CLOCK = hasattr(time, 'clock') HAS_TIME_NS = hasattr(time, 'time_ns') HAS_MONOTONIC_NS = hasattr(time, 'monotonic_ns') class temp_locale(object): """Temporarily change the locale.""" def __init__(self, *targets): self.targets = targets def __enter__(self): self.old = locale.setlocale(locale.LC_ALL) for target in self.targets: try: locale.setlocale(locale.LC_ALL, target) return except locale.Error: pass msg = 'could not set locale to any of: %s' % ', '.join(self.targets) raise SkipTest(msg) def __exit__(self, *args): locale.setlocale(locale.LC_ALL, self.old) # Small sample of locales where '%x' expands to a dd/mm/yyyy string, # which can cause trouble when parsed with dateutil. _dd_mm_yyyy_locales = ['da_DK.UTF-8', 'de_DE.UTF-8', 'fr_FR.UTF-8'] def test_simple_api(): # time to freeze is always provided in UTC freezer = freeze_time("2012-01-14") # expected timestamp must be a timestamp, corresponding to 2012-01-14 UTC local_time = datetime.datetime(2012, 1, 14) utc_time = local_time - datetime.timedelta(seconds=time.timezone) expected_timestamp = time.mktime(utc_time.timetuple()) freezer.start() assert time.time() == expected_timestamp assert time.monotonic() >= 0.0 assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) assert datetime.datetime.utcnow() == datetime.datetime(2012, 1, 14) assert datetime.date.today() == datetime.date(2012, 1, 14) assert datetime.datetime.now().today() == datetime.datetime(2012, 1, 14) freezer.stop() assert time.time() != expected_timestamp assert time.monotonic() >= 0.0 assert datetime.datetime.now() != datetime.datetime(2012, 1, 14) assert datetime.datetime.utcnow() != datetime.datetime(2012, 1, 14) freezer = freeze_time("2012-01-10 13:52:01") freezer.start() assert datetime.datetime.now() == datetime.datetime(2012, 1, 10, 13, 52, 1) freezer.stop() def test_tz_offset(): freezer = freeze_time("2012-01-14 03:21:34", tz_offset=-4) # expected timestamp must be a timestamp, # corresponding to 2012-01-14 03:21:34 UTC # and it doesn't depend on tz_offset local_time = datetime.datetime(2012, 1, 14, 3, 21, 34) utc_time = local_time - datetime.timedelta(seconds=time.timezone) expected_timestamp = time.mktime(utc_time.timetuple()) freezer.start() assert datetime.datetime.now() == datetime.datetime(2012, 1, 13, 23, 21, 34) assert datetime.datetime.utcnow() == datetime.datetime(2012, 1, 14, 3, 21, 34) assert time.time() == expected_timestamp freezer.stop() def test_timedelta_tz_offset(): freezer = freeze_time("2012-01-14 03:21:34", tz_offset=-datetime.timedelta(hours=3, minutes=30)) freezer.start() assert datetime.datetime.now() == datetime.datetime(2012, 1, 13, 23, 51, 34) assert datetime.datetime.utcnow() == datetime.datetime(2012, 1, 14, 3, 21, 34) freezer.stop() def test_tz_offset_with_today(): freezer = freeze_time("2012-01-14", tz_offset=-4) freezer.start() assert datetime.date.today() == datetime.date(2012, 1, 13) freezer.stop() assert datetime.date.today() != datetime.date(2012, 1, 13) def test_zero_tz_offset_with_time(): # we expect the system to behave like a system with UTC timezone # at the beginning of the Epoch freezer = freeze_time('1970-01-01') freezer.start() assert datetime.date.today() == datetime.date(1970, 1, 1) assert datetime.datetime.now() == datetime.datetime(1970, 1, 1) assert datetime.datetime.utcnow() == datetime.datetime(1970, 1, 1) assert time.time() == 0.0 assert time.monotonic() >= 0.0 freezer.stop() def test_tz_offset_with_time(): # we expect the system to behave like a system with UTC-4 timezone # at the beginning of the Epoch (wall clock should be 4 hrs late) freezer = freeze_time('1970-01-01', tz_offset=-4) freezer.start() assert datetime.date.today() == datetime.date(1969, 12, 31) assert datetime.datetime.now() == datetime.datetime(1969, 12, 31, 20) assert datetime.datetime.utcnow() == datetime.datetime(1970, 1, 1) assert time.time() == 0.0 assert time.monotonic() >= 0 freezer.stop() def test_time_with_microseconds(): freezer = freeze_time(datetime.datetime(1970, 1, 1, 0, 0, 1, 123456)) freezer.start() assert time.time() == 1.123456 freezer.stop() def test_time_with_dst(): freezer = freeze_time(datetime.datetime(1970, 6, 1, 0, 0, 1, 123456)) freezer.start() assert time.time() == 13046401.123456 freezer.stop() def test_manual_increment(): initial_datetime = datetime.datetime(year=1, month=7, day=12, hour=15, minute=6, second=3) with freeze_time(initial_datetime) as frozen_datetime: assert frozen_datetime() == initial_datetime frozen_datetime.tick() initial_datetime += datetime.timedelta(seconds=1) assert frozen_datetime() == initial_datetime frozen_datetime.tick(delta=datetime.timedelta(seconds=10)) initial_datetime += datetime.timedelta(seconds=10) assert frozen_datetime() == initial_datetime def test_manual_increment_seconds(): initial_datetime = datetime.datetime(year=1, month=7, day=12, hour=15, minute=6, second=3) with freeze_time(initial_datetime) as frozen_datetime: assert frozen_datetime() == initial_datetime frozen_datetime.tick() initial_datetime += datetime.timedelta(seconds=1) assert frozen_datetime() == initial_datetime frozen_datetime.tick(10) initial_datetime += datetime.timedelta(seconds=10) assert frozen_datetime() == initial_datetime def test_move_to(): initial_datetime = datetime.datetime(year=1, month=7, day=12, hour=15, minute=6, second=3) other_datetime = datetime.datetime(year=2, month=8, day=13, hour=14, minute=5, second=0) with freeze_time(initial_datetime) as frozen_datetime: assert frozen_datetime() == initial_datetime frozen_datetime.move_to(other_datetime) assert frozen_datetime() == other_datetime frozen_datetime.move_to(initial_datetime) assert frozen_datetime() == initial_datetime def test_bad_time_argument(): try: freeze_time("2012-13-14", tz_offset=-4) except ValueError: pass else: assert False, "Bad values should raise a ValueError" def test_time_monotonic(): initial_datetime = datetime.datetime(year=1, month=7, day=12, hour=15, minute=6, second=3) with freeze_time(initial_datetime) as frozen_datetime: monotonic_t0 = time.monotonic() if HAS_MONOTONIC_NS: monotonic_ns_t0 = time.monotonic_ns() frozen_datetime.tick() monotonic_t1 = time.monotonic() assert monotonic_t1 == monotonic_t0 + 1.0 if HAS_MONOTONIC_NS: monotonic_ns_t1 = time.monotonic_ns() assert monotonic_ns_t1 == monotonic_ns_t0 + 1000000000 frozen_datetime.tick(10) monotonic_t11 = time.monotonic() assert monotonic_t11 == monotonic_t1 + 10.0 if HAS_MONOTONIC_NS: monotonic_ns_t11 = time.monotonic_ns() assert monotonic_ns_t11 == monotonic_ns_t1 + 10000000000 def test_time_gmtime(): with freeze_time('2012-01-14 03:21:34'): time_struct = time.gmtime() assert time_struct.tm_year == 2012 assert time_struct.tm_mon == 1 assert time_struct.tm_mday == 14 assert time_struct.tm_hour == 3 assert time_struct.tm_min == 21 assert time_struct.tm_sec == 34 assert time_struct.tm_wday == 5 assert time_struct.tm_yday == 14 assert time_struct.tm_isdst == -1 @pytest.mark.skipif(not HAS_CLOCK, reason="time.clock was removed in Python 3.8") def test_time_clock(): with freeze_time('2012-01-14 03:21:34'): assert time.clock() == 0 with freeze_time('2012-01-14 03:21:35'): assert time.clock() == 1 with freeze_time('2012-01-14 03:21:36'): assert time.clock() == 2 class modify_timezone(object): def __init__(self, new_timezone): self.new_timezone = new_timezone self.original_timezone = time.timezone def __enter__(self): time.timezone = self.new_timezone def __exit__(self, *args): time.timezone = self.original_timezone def test_time_localtime(): with modify_timezone(-3600): # Set this for UTC-1 with freeze_time('2012-01-14 03:21:34'): time_struct = time.localtime() assert time_struct.tm_year == 2012 assert time_struct.tm_mon == 1 assert time_struct.tm_mday == 14 assert time_struct.tm_hour == 4 # offset of 1 hour due to time zone assert time_struct.tm_min == 21 assert time_struct.tm_sec == 34 assert time_struct.tm_wday == 5 assert time_struct.tm_yday == 14 assert time_struct.tm_isdst == -1 assert time.localtime().tm_year != 2012 def test_strftime(): with modify_timezone(0): with freeze_time('1970-01-01'): assert time.strftime("%Y") == "1970" def test_real_strftime_fall_through(): this_real_year = datetime.datetime.now().year with freeze_time(): assert time.strftime('%Y') == str(this_real_year) assert time.strftime('%Y', (2001, 1, 1, 1, 1, 1, 1, 1, 1)) == '2001' def test_date_object(): frozen_date = datetime.date(year=2012, month=11, day=10) date_freezer = freeze_time(frozen_date) regular_freezer = freeze_time('2012-11-10') assert date_freezer.time_to_freeze == regular_freezer.time_to_freeze def test_old_date_object(): frozen_date = datetime.date(year=1, month=1, day=1) with freeze_time(frozen_date): assert datetime.date.today() == frozen_date def test_date_with_locale(): with temp_locale(*_dd_mm_yyyy_locales): frozen_date = datetime.date(year=2012, month=1, day=2) date_freezer = freeze_time(frozen_date) assert date_freezer.time_to_freeze.date() == frozen_date def test_invalid_type(): try: freeze_time(int(4)) except TypeError: pass else: assert False, "Bad types should raise a TypeError" def test_datetime_object(): frozen_datetime = datetime.datetime(year=2012, month=11, day=10, hour=4, minute=15, second=30) datetime_freezer = freeze_time(frozen_datetime) regular_freezer = freeze_time('2012-11-10 04:15:30') assert datetime_freezer.time_to_freeze == regular_freezer.time_to_freeze def test_function_object(): frozen_datetime = datetime.datetime(year=2012, month=11, day=10, hour=4, minute=15, second=30) def function(): return frozen_datetime with freeze_time(function): assert frozen_datetime == datetime.datetime.now() def test_lambda_object(): frozen_datetime = datetime.datetime(year=2012, month=11, day=10, hour=4, minute=15, second=30) with freeze_time(lambda: frozen_datetime): assert frozen_datetime == datetime.datetime.now() def test_generator_object(): frozen_datetimes = (datetime.datetime(year=y, month=1, day=1) for y in range(2010, 2012)) with freeze_time(frozen_datetimes): assert datetime.datetime(2010, 1, 1) == datetime.datetime.now() with freeze_time(frozen_datetimes): assert datetime.datetime(2011, 1, 1) == datetime.datetime.now() with pytest.raises(StopIteration): freeze_time(frozen_datetimes) def test_maya_datetimes(): if not maya: raise SkipTest("maya is optional since it's not supported for " "enough python versions") with freeze_time(maya.when("October 2nd, 1997")): assert datetime.datetime.now() == datetime.datetime( year=1997, month=10, day=2 ) def test_old_datetime_object(): frozen_datetime = datetime.datetime(year=1, month=7, day=12, hour=15, minute=6, second=3) with freeze_time(frozen_datetime): assert datetime.datetime.now() == frozen_datetime def test_datetime_with_locale(): with temp_locale(*_dd_mm_yyyy_locales): frozen_datetime = datetime.datetime(year=2012, month=1, day=2) date_freezer = freeze_time(frozen_datetime) assert date_freezer.time_to_freeze == frozen_datetime @freeze_time("2012-01-14") def test_decorator(): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) def test_decorator_wrapped_attribute(): def to_decorate(): pass wrapped = freeze_time("2014-01-14")(to_decorate) assert wrapped.__wrapped__ is to_decorate class Callable(object): def __call__(self, *args, **kws): return (args, kws) @freeze_time("2012-01-14") class Tester(object): def test_the_class(self): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) def test_still_the_same(self): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) def test_class_name_preserved_by_decorator(self): assert self.__class__.__name__ == "Tester" class NotATestClass(object): def perform_operation(self): return datetime.date.today() @freeze_time('2001-01-01') def test_class_decorator_ignores_nested_class(self): not_a_test = self.NotATestClass() assert not_a_test.perform_operation() == datetime.date(2001, 1, 1) a_mock = Callable() def test_class_decorator_skips_callable_object_py2(self): if sys.version_info[0] != 2: raise SkipTest("test target is Python2") assert self.a_mock.__class__ == Callable def test_class_decorator_wraps_callable_object_py3(self): if sys.version_info[0] == 2: raise SkipTest("test target is Python3+") assert self.a_mock.__wrapped__.__class__ == Callable @staticmethod def helper(): return datetime.date.today() def test_class_decorator_respects_staticmethod(self): assert self.helper() == datetime.date(2012, 1, 14) @freeze_time("Jan 14th, 2012") def test_nice_datetime(): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) @freeze_time("2012-01-14") def test_datetime_date_method(): now = datetime.datetime.now() assert now.date() == FakeDate(2012, 1, 14) def test_context_manager(): with freeze_time("2012-01-14"): assert datetime.datetime.now() == datetime.datetime(2012, 1, 14) assert datetime.datetime.now() != datetime.datetime(2012, 1, 14) def test_nested_context_manager(): with freeze_time("2012-01-14"): with freeze_time("2012-12-25"): _assert_datetime_date_and_time_are_all_equal(datetime.datetime(2012, 12, 25)) _assert_datetime_date_and_time_are_all_equal(datetime.datetime(2012, 1, 14)) assert datetime.datetime.now() > datetime.datetime(2013, 1, 1) def _assert_datetime_date_and_time_are_all_equal(expected_datetime): assert datetime.datetime.now() == expected_datetime assert datetime.date.today() == expected_datetime.date() assert datetime.datetime.fromtimestamp(time.time()) == expected_datetime def test_nested_context_manager_with_tz_offsets(): with freeze_time("2012-01-14 23:00:00", tz_offset=2): with freeze_time("2012-12-25 19:00:00", tz_offset=6): assert datetime.datetime.now() == datetime.datetime(2012, 12, 26, 1) assert datetime.date.today() == datetime.date(2012, 12, 26) # no assertion for time.time() since it's not affected by tz_offset assert datetime.datetime.now() == datetime.datetime(2012, 1, 15, 1) assert datetime.date.today() == datetime.date(2012, 1, 15) assert datetime.datetime.now() > datetime.datetime(2013, 1, 1) @freeze_time("Jan 14th, 2012") def test_isinstance_with_active(): now = datetime.datetime.now() assert utils.is_fake_datetime(now) assert utils.is_fake_date(now.date()) today = datetime.date.today() assert utils.is_fake_date(today) def test_isinstance_without_active(): now = datetime.datetime.now() assert isinstance(now, datetime.datetime) assert isinstance(now, datetime.date) assert isinstance(now.date(), datetime.date) today = datetime.date.today() assert isinstance(today, datetime.date) class TestUnitTestMethodDecorator(unittest.TestCase): @freeze_time('2013-04-09') def test_method_decorator_works_on_unittest(self): self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) @freeze_time('2013-04-09', as_kwarg='frozen_time') def test_method_decorator_works_on_unittest_kwarg_frozen_time(self, frozen_time): self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) self.assertEqual(datetime.date(2013, 4, 9), frozen_time.time_to_freeze.today()) @freeze_time('2013-04-09', as_kwarg='hello') def test_method_decorator_works_on_unittest_kwarg_hello(self, **kwargs): self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) self.assertEqual(datetime.date(2013, 4, 9), kwargs.get('hello').time_to_freeze.today()) @freeze_time('2013-04-09') class TestUnitTestClassDecorator(unittest.TestCase): @classmethod def setUpClass(cls): assert datetime.date(2013, 4, 9) == datetime.date.today() def setUp(self): self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) def tearDown(self): self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) @classmethod def tearDownClass(cls): assert datetime.date(2013, 4, 9) == datetime.date.today() def test_class_decorator_works_on_unittest(self): self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) def test_class_name_preserved_by_decorator(self): self.assertEqual(self.__class__.__name__, "TestUnitTestClassDecorator") @freeze_time('2013-04-09') class TestUnitTestClassDecoratorWithNoSetUpOrTearDown(unittest.TestCase): def test_class_decorator_works_on_unittest(self): self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) class TestUnitTestClassDecoratorSubclass(TestUnitTestClassDecorator): @classmethod def setUpClass(cls): # the super() call can fail if the class decoration was done wrong super(TestUnitTestClassDecoratorSubclass, cls).setUpClass() @classmethod def tearDownClass(cls): # the super() call can fail if the class decoration was done wrong super(TestUnitTestClassDecoratorSubclass, cls).tearDownClass() def test_class_name_preserved_by_decorator(self): self.assertEqual(self.__class__.__name__, "TestUnitTestClassDecoratorSubclass") class BaseInheritanceFreezableTests(unittest.TestCase): @classmethod def setUpClass(cls): pass @classmethod def tearDownClass(cls): pass class UnfrozenInheritedTests(BaseInheritanceFreezableTests): def test_time_is_not_frozen(self): # In this class, time should not be frozen - and the below decorated # class shouldn't affect that self.assertNotEqual(datetime.date(2013, 4, 9), datetime.date.today()) @freeze_time('2013-04-09') class FrozenInheritedTests(BaseInheritanceFreezableTests): def test_time_is_frozen(self): # In this class, time should be frozen self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today()) class TestOldStyleClasses: def test_direct_method(self): # Make sure old style classes (not inheriting from object) is supported @freeze_time('2013-04-09') class OldStyleClass: def method(self): return datetime.date.today() assert OldStyleClass().method() == datetime.date(2013, 4, 9) def test_inherited_method(self): class OldStyleBaseClass: def inherited_method(self): return datetime.date.today() @freeze_time('2013-04-09') class OldStyleClass(OldStyleBaseClass): pass assert OldStyleClass().inherited_method() == datetime.date(2013, 4, 9) def test_min_and_max(): freezer = freeze_time("2012-01-14") real_datetime = datetime.datetime real_date = datetime.date freezer.start() assert datetime.datetime.min.__class__ == FakeDatetime assert datetime.datetime.max.__class__ == FakeDatetime assert datetime.date.min.__class__ == FakeDate assert datetime.date.max.__class__ == FakeDate assert datetime.datetime.min.__class__ != real_datetime assert datetime.datetime.max.__class__ != real_datetime assert datetime.date.min.__class__ != real_date assert datetime.date.max.__class__ != real_date freezer.stop() assert datetime.datetime.min.__class__ == datetime.datetime assert datetime.datetime.max.__class__ == datetime.datetime assert datetime.date.min.__class__ == datetime.date assert datetime.date.max.__class__ == datetime.date assert datetime.datetime.min.__class__ != FakeDatetime assert datetime.datetime.max.__class__ != FakeDatetime assert datetime.date.min.__class__ != FakeDate assert datetime.date.max.__class__ != FakeDate @freeze_time("2014-07-30T01:00:00Z") def test_freeze_with_timezone_aware_datetime_in_utc(): """ utcnow() should always return a timezone naive datetime """ utc_now = datetime.datetime.utcnow() assert utc_now.tzinfo is None @freeze_time("1970-01-01T00:00:00-04:00") def test_freeze_with_timezone_aware_datetime_in_non_utc(): """ we expect the system to behave like a system with UTC-4 timezone at the beginning of the Epoch (wall clock should be 4 hrs late) """ utc_now = datetime.datetime.utcnow() assert utc_now.tzinfo is None assert utc_now == datetime.datetime(1970, 1, 1, 4) @freeze_time('2015-01-01') def test_time_with_nested(): from time import time first = 1420070400.0 second = 1420070760.0 assert time() == first with freeze_time('2015-01-01T00:06:00'): assert time() == second def test_monotonic_with_nested(): from time import monotonic with freeze_time('2015-01-01') as frozen_datetime_1: initial_monotonic_1 = time.monotonic() with freeze_time('2015-12-25') as frozen_datetime_2: initial_monotonic_2 = time.monotonic() frozen_datetime_2.tick() assert time.monotonic() == initial_monotonic_2 + 1 assert time.monotonic() == initial_monotonic_1 frozen_datetime_1.tick() assert time.monotonic() == initial_monotonic_1 + 1 def test_should_use_real_time(): frozen = datetime.datetime(2015, 3, 5) expected_frozen = 1425513600.0 # TODO: local time seems to leak the local timezone, so this test fails in CI # expected_frozen_local = (2015, 3, 5, 1, 0, 0, 3, 64, -1) expected_frozen_gmt = (2015, 3, 5, 0, 0, 0, 3, 64, -1) expected_clock = 0 from freezegun import api api.call_stack_inspection_limit = 100 # just to increase coverage timestamp_to_convert = 1579602312 time_tuple = time.gmtime(timestamp_to_convert) with freeze_time(frozen): assert time.time() == expected_frozen # assert time.localtime() == expected_frozen_local assert time.gmtime() == expected_frozen_gmt if HAS_CLOCK: assert time.clock() == expected_clock if HAS_TIME_NS: assert time.time_ns() == expected_frozen * 1e9 assert calendar.timegm(time.gmtime()) == expected_frozen assert calendar.timegm(time_tuple) == timestamp_to_convert with freeze_time(frozen, ignore=['_pytest', 'nose']): assert time.time() != expected_frozen # assert time.localtime() != expected_frozen_local assert time.gmtime() != expected_frozen_gmt if HAS_CLOCK: assert time.clock() != expected_clock if HAS_TIME_NS: assert time.time_ns() != expected_frozen * 1e9 assert calendar.timegm(time.gmtime()) != expected_frozen assert calendar.timegm(time_tuple) == timestamp_to_convert @pytest.mark.skipif(not HAS_TIME_NS, reason="time.time_ns is present only on 3.7 and above") def test_time_ns(): freezer = freeze_time("2012-01-14") local_time = datetime.datetime(2012, 1, 14) utc_time = local_time - datetime.timedelta(seconds=time.timezone) expected_timestamp = time.mktime(utc_time.timetuple()) freezer.start() assert time.time() == expected_timestamp assert time.time_ns() == expected_timestamp * 1e9 freezer.stop() assert time.time() != expected_timestamp assert time.time_ns() != expected_timestamp * 1e9 def test_compare_datetime_and_time_with_timezone(monkeypatch): """ Compare the result of datetime.datetime.now() and time.time() in a non-UTC timezone. These should be consistent. """ try: with monkeypatch.context() as m, freeze_time("1970-01-01 00:00:00"): m.setenv("TZ", "Europe/Berlin") time.tzset() now = datetime.datetime.now() assert now == datetime.datetime.fromtimestamp(time.time()) assert now == datetime.datetime.utcfromtimestamp(time.time()) assert now == datetime.datetime.utcnow() assert now.timestamp() == time.time() finally: time.tzset() # set the timezone back to what is was before def test_timestamp_with_tzoffset(): with freeze_time("2000-01-01", tz_offset=6): utcnow = datetime.datetime(2000, 1, 1, 0) nowtz = datetime.datetime(2000, 1, 1, 0, tzinfo=UTC) now = datetime.datetime(2000, 1, 1, 6) assert now == datetime.datetime.now() assert now == datetime.datetime.fromtimestamp(time.time()) assert now.timestamp() == time.time() assert nowtz.timestamp() == time.time() assert utcnow == datetime.datetime.utcfromtimestamp(time.time()) assert utcnow == datetime.datetime.utcnow() @pytest.mark.skip("timezone handling is currently incorrect") def test_datetime_in_timezone(monkeypatch): """ It is assumed that the argument passed to freeze_time is in UTC, unless explicitly indicated otherwise. Therefore datetime.now() should return the frozen time with an offset. """ try: with monkeypatch.context() as m, freeze_time("1970-01-01 00:00:00"): m.setenv("TZ", "Europe/Berlin") time.tzset() assert datetime.datetime.now() == datetime.datetime(1970, 1, 1, 1, 0, 0) finally: time.tzset() # set the timezone back to what is was before freezegun-1.1.0/tests/test_errors.py000066400000000000000000000031021417522634300175750ustar00rootroot00000000000000import contextlib import datetime import sys import pytest from freezegun import freeze_time class ModuleWithError(object): """ A module that triggers an error on __dir__ access. This could happen with modules that overrides its __dir__ method and performing non standard operations. One such example is IPython which adds shim modules when certain packages are imported. (Eg. `import IPython.html`) This leads to errors upon activating freezegun if the modules being shimmed are not installed. See: https://github.com/ipython/ipython/blob/5.8.0/IPython/utils/shimmodule.py#L75 """ __name__ = 'module_with_error' __dict__ = {} def __init__(self, error_type): self.error_triggered = False self.error_type = error_type def __dir__(self): try: raise self.error_type() finally: self.error_triggered = True @contextlib.contextmanager def assert_module_with_raised_error(error_type): """Install a module into sys.modules that raises an error upon invoking __dir__.""" module = sys.modules['module_with_error'] = ModuleWithError(error_type) try: yield finally: del sys.modules['module_with_error'] assert module.error_triggered @pytest.mark.parametrize('error_type', [ImportError, TypeError]) def test_ignore_errors_in_start(error_type): with assert_module_with_raised_error(error_type): freezer = freeze_time(datetime.datetime(2019, 1, 11, 9, 34)) try: freezer.start() finally: freezer.stop() freezegun-1.1.0/tests/test_import_alias.py000066400000000000000000000012501417522634300207460ustar00rootroot00000000000000from freezegun import freeze_time from datetime import datetime as datetime_aliased from time import time as time_aliased @freeze_time("1980-01-01") def test_datetime_alias(): assert datetime_aliased.now() == datetime_aliased(1980, 1, 1) @freeze_time("1970-01-01") def test_time_alias(): assert time_aliased() == 0.0 @freeze_time('2013-04-09') class TestCallOtherFuncInTestClassDecoratorWithAlias(object): def test_calls_other_method(self): assert datetime_aliased(2013, 4, 9) == datetime_aliased.today() self.some_other_func() assert datetime_aliased(2013, 4, 9) == datetime_aliased.today() def some_other_func(self): pass freezegun-1.1.0/tests/test_operations.py000066400000000000000000000060221417522634300204500ustar00rootroot00000000000000import datetime from freezegun import freeze_time from dateutil.relativedelta import relativedelta from datetime import timedelta, tzinfo from tests import utils @freeze_time("2012-01-14") def test_addition(): now = datetime.datetime.now() later = now + datetime.timedelta(days=1) other_later = now + relativedelta(days=1) assert utils.is_fake_datetime(later) assert utils.is_fake_datetime(other_later) today = datetime.date.today() tomorrow = today + datetime.timedelta(days=1) other_tomorrow = today + relativedelta(days=1) assert utils.is_fake_date(tomorrow) assert utils.is_fake_date(other_tomorrow) @freeze_time("2012-01-14") def test_subtraction(): now = datetime.datetime.now() before = now - datetime.timedelta(days=1) other_before = now - relativedelta(days=1) how_long = now - before assert utils.is_fake_datetime(before) assert utils.is_fake_datetime(other_before) assert isinstance(how_long, datetime.timedelta) today = datetime.date.today() yesterday = today - datetime.timedelta(days=1) other_yesterday = today - relativedelta(days=1) how_long = today - yesterday assert utils.is_fake_date(yesterday) assert utils.is_fake_date(other_yesterday) assert isinstance(how_long, datetime.timedelta) @freeze_time("2012-01-14") def test_datetime_timezone_none(): now = datetime.datetime.now(tz=None) assert now == datetime.datetime(2012, 1, 14) class GMT5(tzinfo): def utcoffset(self, dt): return timedelta(hours=5) def tzname(self, dt): return "GMT +5" def dst(self, dt): return timedelta(0) @freeze_time("2012-01-14 2:00:00") def test_datetime_timezone_real(): now = datetime.datetime.now(tz=GMT5()) assert now == datetime.datetime(2012, 1, 14, 7, tzinfo=GMT5()) assert now.utcoffset() == timedelta(0, 60 * 60 * 5) @freeze_time("2012-01-14 2:00:00", tz_offset=-4) def test_datetime_timezone_real_with_offset(): now = datetime.datetime.now(tz=GMT5()) assert now == datetime.datetime(2012, 1, 14, 3, tzinfo=GMT5()) assert now.utcoffset() == timedelta(0, 60 * 60 * 5) @freeze_time("2012-01-14 00:00:00") def test_astimezone(): now = datetime.datetime.now(tz=GMT5()) converted = now.astimezone(GMT5()) assert utils.is_fake_datetime(converted) @freeze_time("2012-01-14 00:00:00") def test_astimezone_tz_none(): now = datetime.datetime.now(tz=GMT5()) converted = now.astimezone() assert utils.is_fake_datetime(converted) @freeze_time("2012-01-14 00:00:00") def test_replace(): now = datetime.datetime.now() modified_time = now.replace(year=2013) assert utils.is_fake_datetime(modified_time) today = datetime.date.today() modified_date = today.replace(year=2013) assert utils.is_fake_date(modified_date) @freeze_time("Jan 14th, 2020", auto_tick_seconds=15) def test_auto_tick(): first_time = datetime.datetime.now() auto_incremented_time = datetime.datetime.now() assert first_time + datetime.timedelta(seconds=15) == auto_incremented_time freezegun-1.1.0/tests/test_pickle.py000066400000000000000000000037131417522634300175400ustar00rootroot00000000000000import datetime import pickle from freezegun import freeze_time def assert_pickled_datetimes_equal_original(): min_datetime = datetime.datetime.min max_datetime = datetime.datetime.max min_date = datetime.date.min max_date = datetime.date.max now = datetime.datetime.now() today = datetime.date.today() utc_now = datetime.datetime.utcnow() assert pickle.loads(pickle.dumps(min_datetime)) == min_datetime assert pickle.loads(pickle.dumps(max_datetime)) == max_datetime assert pickle.loads(pickle.dumps(min_date)) == min_date assert pickle.loads(pickle.dumps(max_date)) == max_date assert pickle.loads(pickle.dumps(now)) == now assert pickle.loads(pickle.dumps(today)) == today assert pickle.loads(pickle.dumps(utc_now)) == utc_now def test_pickle(): freezer = freeze_time("2012-01-14") freezer.start() assert_pickled_datetimes_equal_original() freezer.stop() assert_pickled_datetimes_equal_original() def test_pickle_real_datetime(): real_datetime = datetime.datetime(1970, 2, 1) pickle.loads(pickle.dumps(real_datetime)) == real_datetime freezer = freeze_time("1970-01-01") freezer.start() fake_datetime = datetime.datetime.now() assert pickle.loads(pickle.dumps(fake_datetime)) == fake_datetime pickle.loads(pickle.dumps(real_datetime)) freezer.stop() assert pickle.loads(pickle.dumps(fake_datetime)) == fake_datetime assert pickle.loads(pickle.dumps(real_datetime)) == real_datetime def test_pickle_real_date(): real_date = datetime.date(1970, 2, 1) assert pickle.loads(pickle.dumps(real_date)) == real_date freezer = freeze_time("1970-01-01") freezer.start() fake_date = datetime.datetime.now() assert pickle.loads(pickle.dumps(fake_date)) == fake_date pickle.loads(pickle.dumps(real_date)) freezer.stop() assert pickle.loads(pickle.dumps(fake_date)) == fake_date assert pickle.loads(pickle.dumps(real_date)) == real_date freezegun-1.1.0/tests/test_sqlite3.py000066400000000000000000000005671417522634300176610ustar00rootroot00000000000000import datetime from freezegun import freeze_time import sqlite3 @freeze_time("2013-01-01") def test_fake_datetime_select(): db = sqlite3.connect("/tmp/foo") db.execute("""select ?""", (datetime.datetime.now(),)) @freeze_time("2013-01-01") def test_fake_date_select(): db = sqlite3.connect("/tmp/foo") db.execute("""select ?""", (datetime.date.today(),)) freezegun-1.1.0/tests/test_ticking.py000066400000000000000000000052331417522634300177200ustar00rootroot00000000000000import datetime import time from unittest import mock import pytest from freezegun import freeze_time from tests import utils @utils.cpython_only def test_ticking_datetime(): with freeze_time("Jan 14th, 2012", tick=True): time.sleep(0.001) # Deal with potential clock resolution problems assert datetime.datetime.now() > datetime.datetime(2012, 1, 14) @pytest.mark.skipif(not hasattr(time, "clock"), reason="time.clock was removed in Python 3.8") @utils.cpython_only def test_ticking_time_clock(): with freeze_time('2012-01-14 03:21:34', tick=True): first = time.clock() time.sleep(0.001) # Deal with potential clock resolution problems with freeze_time('2012-01-14 03:21:35', tick=True): second = time.clock() time.sleep(0.001) # Deal with potential clock resolution problems with freeze_time('2012-01-14 03:21:36', tick=True): third = time.clock() time.sleep(0.001) # Rewind time backwards with freeze_time('2012-01-14 03:20:00', tick=True): fourth = time.clock() time.sleep(0.001) fifth = time.clock() assert first > 0 assert second > first assert second > 1 assert third > second assert third > 2 assert third > fourth assert second > fourth assert first > fourth assert fifth > fourth @utils.cpython_only def test_ticking_date(): with freeze_time("Jan 14th, 2012, 23:59:59.9999999", tick=True): time.sleep(0.001) # Deal with potential clock resolution problems assert datetime.date.today() == datetime.date(2012, 1, 15) @utils.cpython_only def test_ticking_time(): with freeze_time("Jan 14th, 2012, 23:59:59", tick=True): time.sleep(0.001) # Deal with potential clock resolution problems assert time.time() > 1326585599.0 @utils.cpython_only def test_ticking_monotonic(): with freeze_time("Jan 14th, 2012, 23:59:59", tick=True): initial_monotonic = time.monotonic() time.sleep(0.001) # Deal with potential clock resolution problems assert time.monotonic() > initial_monotonic @mock.patch('freezegun.api._is_cpython', False) def test_pypy_compat(): try: freeze_time("Jan 14th, 2012, 23:59:59", tick=True) except SystemError: pass else: raise AssertionError("tick=True should error on non-CPython") @mock.patch('freezegun.api._is_cpython', True) def test_non_pypy_compat(): try: freeze_time("Jan 14th, 2012, 23:59:59", tick=True) except Exception: raise AssertionError("tick=True should not error on CPython") freezegun-1.1.0/tests/test_utils.py000066400000000000000000000017161417522634300174320ustar00rootroot00000000000000from unittest import SkipTest, mock from freezegun import api from tests import utils try: reload except NameError: try: from importlib import reload except ImportError: from imp import reload @mock.patch('platform.python_implementation', lambda: 'CPython') def test_should_not_skip_cpython(): reload(api) reload(utils) function_mock = mock.MagicMock(__name__='function') try: utils.cpython_only(function_mock)() except SkipTest: raise AssertionError("Test was skipped in CPython") assert function_mock.called @mock.patch('platform.python_implementation', lambda: 'not-CPython') def test_should_skip_non_cpython(): reload(api) reload(utils) function_mock = mock.MagicMock(__name__='function', skipped=False) try: utils.cpython_only(function_mock)() except SkipTest: function_mock.skipped = True assert not function_mock.called assert function_mock.skipped freezegun-1.1.0/tests/test_uuid.py000066400000000000000000000025601417522634300172360ustar00rootroot00000000000000import datetime import uuid from freezegun import freeze_time def time_from_uuid(value): """ Converts an UUID(1) to it's datetime value """ uvalue = value if isinstance(value, uuid.UUID) else uuid.UUID(value) assert uvalue.version == 1 return (datetime.datetime(1582, 10, 15) + datetime.timedelta(microseconds=uvalue.time // 10)) def test_uuid1_future(): """ Test that we can go back in time after setting a future date. Normally UUID1 would disallow this, since it keeps track of the _last_timestamp, but we override that now. """ future_target = datetime.datetime(2056, 2, 6, 14, 3, 21) with freeze_time(future_target): assert time_from_uuid(uuid.uuid1()) == future_target past_target = datetime.datetime(1978, 7, 6, 23, 6, 31) with freeze_time(past_target): assert time_from_uuid(uuid.uuid1()) == past_target def test_uuid1_past(): """ Test that we can go forward in time after setting some time in the past. This is simply the opposite of test_uuid1_future() """ past_target = datetime.datetime(1978, 7, 6, 23, 6, 31) with freeze_time(past_target): assert time_from_uuid(uuid.uuid1()) == past_target future_target = datetime.datetime(2056, 2, 6, 14, 3, 21) with freeze_time(future_target): assert time_from_uuid(uuid.uuid1()) == future_target freezegun-1.1.0/tests/test_warnings.py000066400000000000000000000054061417522634300201220ustar00rootroot00000000000000import contextlib import datetime import sys import types import warnings from freezegun import freeze_time class ModuleWithWarning(object): """ A module that triggers warnings on attribute access. This does not happen with regular modules, there has to be a bit of lazy module magic going on in order for this to happen. Examples of modules that uses this pattern in real projects can be found at: py.code - the compiler package import causes a warning to be emitted: https://github.com/pytest-dev/py/blob/67987e26aadddbbe7d1ec76c16ea9be346ae9811/py/__init__.py https://github.com/pytest-dev/py/blob/67987e26aadddbbe7d1ec76c16ea9be346ae9811/py/_code/_assertionold.py#L3 celery.task - the sets module is listed in __all__ in celery.task and freeze_time accesses it: https://github.com/celery/celery/blob/46c92025cdec07a4a30ad44901cf66cb27346638/celery/task/__init__.py https://github.com/celery/celery/blob/46c92025cdec07a4a30ad44901cf66cb27346638/celery/task/sets.py """ __name__ = 'module_with_warning' __dict__ = {} warning_triggered = False counter = 0 @property def attribute_that_emits_a_warning(self): # Use unique warning messages to avoid messages being only reported once self.__class__.counter += 1 warnings.warn('this is test warning #{counter}'.format(counter=self.__class__.counter)) self.warning_triggered = True @contextlib.contextmanager def assert_module_with_emitted_warning(): """Install a module that triggers warnings into sys.modules and ensure the warning was triggered in the with-block. """ module = sys.modules['module_with_warning'] = ModuleWithWarning() try: yield finally: del sys.modules['module_with_warning'] assert module.warning_triggered @contextlib.contextmanager def assert_no_warnings(): """A context manager that makes sure no warnings was emitted.""" with warnings.catch_warnings(record=True) as caught_warnings: warnings.filterwarnings('always') yield assert not caught_warnings def test_ignore_warnings_in_start(): """Make sure that modules being introspected in start() does not emit warnings.""" with assert_module_with_emitted_warning(): freezer = freeze_time(datetime.datetime(2016, 10, 27, 9, 56)) try: with assert_no_warnings(): freezer.start() finally: freezer.stop() def test_ignore_warnings_in_stop(): """Make sure that modules that was loaded after start() does not trigger warnings in stop()""" freezer = freeze_time(datetime.datetime(2016, 10, 27, 9, 56)) freezer.start() with assert_module_with_emitted_warning(): with assert_no_warnings(): freezer.stop() freezegun-1.1.0/tests/utils.py000066400000000000000000000006711417522634300163720ustar00rootroot00000000000000from functools import wraps from unittest import SkipTest from freezegun.api import FakeDate, FakeDatetime, _is_cpython def is_fake_date(obj): return obj.__class__ is FakeDate def is_fake_datetime(obj): return obj.__class__ is FakeDatetime def cpython_only(func): @wraps(func) def wrapper(*args): if not _is_cpython: raise SkipTest("Requires CPython") return func(*args) return wrapper freezegun-1.1.0/tox.ini000066400000000000000000000005501417522634300150250ustar00rootroot00000000000000# Tox (http://tox.testrun.org/) is a tool for running tests # in multiple virtualenvs. This configuration file will run the # test suite on all supported python versions. To use it, "pip install tox" # and then run "tox" from this directory. [tox] envlist = py35, py36, py37, py38, pypy3 [testenv] commands = pytest --cov {posargs} deps = -rrequirements.txt