Commit eb75dec2 authored by Federico Ceratto's avatar Federico Ceratto

New upstream version 0.3.9

parent bffec654
Freezegun Changelog
===================
Latest
------
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
\ No newline at end of file
include README.rst LICENSE AUTHORS.rst
include README.rst LICENSE AUTHORS.rst CHANGELOG
recursive-include tests *
global-exclude __pycache__
global-exclude *.py[co]
Metadata-Version: 1.1
Name: freezegun
Version: 0.3.7
Version: 0.3.9
Summary: Let your Python tests travel through time
Home-page: https://github.com/spulec/freezegun
Author: Steve Pulec
Author-email: spulec@gmail
Author-email: spulec@gmail.com
License: Apache 2.0
Description: UNKNOWN
Platform: UNKNOWN
......
......@@ -2,9 +2,9 @@ FreezeGun: Let your Python tests travel through time
====================================================
.. image:: https://secure.travis-ci.org/spulec/freezegun.png?branch=master
.. 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.png?branch=master
.. 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.
......@@ -85,7 +85,7 @@ Timezones
Nice inputs
~~~~~~~~~~~
FreezeGun uses dateutil behind the scenes so you can have nice-looking datetimes
FreezeGun uses dateutil behind the scenes so you can have nice-looking datetimes.
.. code-block:: python
......@@ -93,10 +93,10 @@ FreezeGun uses dateutil behind the scenes so you can have nice-looking datetimes
def test_nice_datetime():
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
`tick` argument
~~~~~~~~~~~
``tick`` argument
~~~~~~~~~~~~~~~~~
FreezeGun has an additional `tick` argument which will restart time at the given
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.
......@@ -109,7 +109,7 @@ parameters which will keep time stopped.
Manual ticks
~~~~~~~~~~~~
Freezegun allows for the time to be manually forwarded as well
Freezegun allows for the time to be manually forwarded as well.
.. code-block:: python
......@@ -127,6 +127,48 @@ Freezegun allows for the time to be manually forwarded as well
initial_datetime += datetime.timedelta(seconds=10)
assert frozen_datetime() == initial_datetime
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
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 <http://docs.python-guide.org/en/latest/writing/gotchas/#mutable-default-arguments>`_ 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
------------
......
Metadata-Version: 1.1
Name: freezegun
Version: 0.3.7
Version: 0.3.9
Summary: Let your Python tests travel through time
Home-page: https://github.com/spulec/freezegun
Author: Steve Pulec
Author-email: spulec@gmail
Author-email: spulec@gmail.com
License: Apache 2.0
Description: UNKNOWN
Platform: UNKNOWN
......
AUTHORS.rst
CHANGELOG
LICENSE
MANIFEST.in
README.rst
......@@ -22,4 +23,6 @@ tests/test_pickle.py
tests/test_sqlite3.py
tests/test_ticking.py
tests/test_utils.py
tests/test_uuid.py
tests/test_warnings.py
tests/utils.py
\ No newline at end of file
......@@ -9,7 +9,7 @@ freezegun
from .api import freeze_time
__title__ = 'freezegun'
__version__ = '0.3.7'
__version__ = '0.3.9'
__author__ = 'Steve Pulec'
__license__ = 'Apache License 2.0'
__copyright__ = 'Copyright 2012 Steve Pulec'
......
......@@ -3,11 +3,14 @@ import functools
import inspect
import sys
import time
import uuid
import calendar
import unittest
import platform
import warnings
from dateutil import parser
from dateutil.tz import tzlocal
real_time = time.time
real_localtime = time.localtime
......@@ -16,6 +19,16 @@ real_strftime = time.strftime
real_date = datetime.date
real_datetime = datetime.datetime
try:
real_uuid_generate_time = uuid._uuid_generate_time
except ImportError:
real_uuid_generate_time = None
try:
real_uuid_create = uuid._UuidCreate
except ImportError:
real_uuid_create = None
try:
import copy_reg as copyreg
except ImportError:
......@@ -168,15 +181,18 @@ class FakeDatetime(with_metaclass(FakeDatetimeMeta, real_datetime, FakeDate)):
else:
return result
def astimezone(self, tz):
def astimezone(self, tz=None):
if tz is None:
tz = tzlocal()
return datetime_to_fakedatetime(real_datetime.astimezone(self, tz))
@classmethod
def now(cls, tz=None):
now = cls._time_to_freeze() or real_datetime.now()
if tz:
result = tz.fromutc(cls._time_to_freeze().replace(tzinfo=tz)) + datetime.timedelta(hours=cls._tz_offset())
result = tz.fromutc(now.replace(tzinfo=tz)) + datetime.timedelta(hours=cls._tz_offset())
else:
result = cls._time_to_freeze() + datetime.timedelta(hours=cls._tz_offset())
result = now + datetime.timedelta(hours=cls._tz_offset())
return datetime_to_fakedatetime(result)
def date(self):
......@@ -188,11 +204,12 @@ class FakeDatetime(with_metaclass(FakeDatetimeMeta, real_datetime, FakeDate)):
@classmethod
def utcnow(cls):
result = cls._time_to_freeze()
result = cls._time_to_freeze() or real_datetime.utcnow()
return datetime_to_fakedatetime(result)
@classmethod
def _time_to_freeze(cls):
if cls.times_to_freeze:
return cls.times_to_freeze[-1]()
@classmethod
......@@ -236,6 +253,23 @@ def pickle_fake_datetime(datetime_):
)
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())
else:
time_to_freeze = parser.parse(time_to_freeze_str)
return convert_to_timezone_naive(time_to_freeze)
class TickingDateTimeFactory(object):
def __init__(self, time_to_freeze, start):
......@@ -257,21 +291,18 @@ class FrozenDateTimeFactory(object):
def tick(self, delta=datetime.timedelta(seconds=1)):
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 _freeze_time(object):
def __init__(self, time_to_freeze_str, tz_offset, ignore, tick):
if time_to_freeze_str is None:
time_to_freeze = 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())
else:
time_to_freeze = parser.parse(time_to_freeze_str)
time_to_freeze = convert_to_timezone_naive(time_to_freeze)
self.time_to_freeze = time_to_freeze
self.time_to_freeze = _parse_time_to_freeze(time_to_freeze_str)
self.tz_offset = tz_offset
self.ignore = tuple(ignore)
self.tick = tick
......@@ -312,7 +343,9 @@ class _freeze_time(object):
else:
seen = set()
for base_klass in klass.mro():
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
......@@ -351,6 +384,8 @@ class _freeze_time(object):
time.localtime = fake_localtime
time.gmtime = fake_gmtime
time.strftime = fake_strftime
uuid._uuid_generate_time = None
uuid._UuidCreate = None
copyreg.dispatch_table[real_datetime] = pickle_fake_datetime
copyreg.dispatch_table[real_date] = pickle_fake_date
......@@ -373,6 +408,9 @@ class _freeze_time(object):
# 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:
continue
......@@ -419,6 +457,8 @@ class _freeze_time(object):
# 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:
......@@ -428,6 +468,7 @@ class _freeze_time(object):
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:
......@@ -445,6 +486,9 @@ class _freeze_time(object):
time.localtime = time.localtime.previous_localtime_function
time.strftime = time.strftime.previous_strftime_function
uuid._uuid_generate_time = real_uuid_generate_time
uuid._UuidCreate = real_uuid_create
def decorate_callable(self, func):
def wrapper(*args, **kwargs):
with self:
......@@ -466,7 +510,7 @@ def freeze_time(time_to_freeze=None, tz_offset=0, ignore=None, tick=False):
except NameError:
string_type = str
if not isinstance(time_to_freeze, (string_type, datetime.date)):
if not isinstance(time_to_freeze, (type(None), string_type, datetime.date)):
raise TypeError(('freeze_time() expected None, a string, date instance, or '
'datetime instance, but got type {0}.').format(type(time_to_freeze)))
if tick and not _is_cpython:
......@@ -476,6 +520,8 @@ def freeze_time(time_to_freeze=None, tz_offset=0, ignore=None, tick=False):
ignore = []
ignore.append('six.moves')
ignore.append('django.utils.six.moves')
ignore.append('threading')
ignore.append('Queue')
return _freeze_time(time_to_freeze, tz_offset, ignore, tick)
......@@ -504,4 +550,6 @@ 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]
......@@ -13,10 +13,10 @@ else:
setup(
name='freezegun',
version='0.3.7',
version='0.3.9',
description='Let your Python tests travel through time',
author='Steve Pulec',
author_email='spulec@gmail',
author_email='spulec@gmail.com',
url='https://github.com/spulec/freezegun',
packages=['freezegun'],
install_requires=requires,
......
......@@ -80,7 +80,8 @@ def test_import_localtime():
struct = fake_localtime_function()
assert struct.tm_year == 2012
assert struct.tm_mon == 1
assert struct.tm_mday == 14
assert struct.tm_mday >= 13 # eg. GMT+14
assert struct.tm_mday <= 15 # eg. GMT-14
@freeze_time("2012-01-14 12:00:00")
......@@ -144,3 +145,9 @@ def test_import_after_start():
assert another_module.get_fake_localtime() is FakeLocalTime
assert another_module.get_fake_gmtime() is FakeGMTTime
assert another_module.get_fake_strftime() is FakeStrfTime
def test_none_as_initial():
with freeze_time() as ft:
ft.move_to('2012-01-14')
assert fake_strftime_function() == '2012'
......@@ -137,6 +137,22 @@ def test_manual_increment():
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)
......@@ -442,6 +458,28 @@ class FrozenInheritedTests(BaseInheritanceFreezableTests):
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
......
......@@ -77,6 +77,13 @@ def test_astimezone():
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()
......
import 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():
# Test that the uuid.uuid1() methods generate a value from the freezed date
# This was not always the case as python is
# using the system's one if available through ctypes
target = datetime.datetime(2017, 2, 6, 14, 8, 21)
with freeze_time(target):
assert time_from_uuid(uuid.uuid1()) == target
import 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()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment