pytest-dev / py

Python development support library (note: maintenance only)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

py 1.5 breaks freezegun on Windows

Kwpolska opened this issue · comments

My AppVeyor (Windows) tests recently started failing with this:

================================== FAILURES ===================================
________________________ TestScheduling.test_get_date _________________________
c:\python36\lib\site-packages\freezegun\api.py:494: in wrapper
    with self:
c:\python36\lib\site-packages\freezegun\api.py:365: in __enter__
    return self.start()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <freezegun.api._freeze_time object at 0x052C2270>

    def start(self):
        if self.tick:
            time_to_freeze = TickingDateTimeFactory(self.time_to_freeze, real_datetime.now())
        else:
            time_to_freeze = FrozenDateTimeFactory(self.time_to_freeze)
    
        # Change the modules
        datetime.datetime = FakeDatetime
        datetime.date = FakeDate
        fake_time = FakeTime(time_to_freeze, time.time)
        fake_localtime = FakeLocalTime(time_to_freeze, time.localtime)
        fake_gmtime = FakeGMTTime(time_to_freeze, time.gmtime)
        fake_strftime = FakeStrfTime(time_to_freeze, time.strftime)
        time.time = fake_time
        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
    
        # Change any place where the module had already been imported
        to_patch = [
            ('real_date', real_date, 'FakeDate', FakeDate),
            ('real_datetime', real_datetime, 'FakeDatetime', FakeDatetime),
            ('real_gmtime', real_gmtime, 'FakeGMTTime', fake_gmtime),
            ('real_localtime', real_localtime, 'FakeLocalTime', fake_localtime),
            ('real_strftime', real_strftime, 'FakeStrfTime', fake_strftime),
            ('real_time', real_time, 'FakeTime', fake_time),
        ]
        real_names = tuple(real_name for real_name, real, fake_name, fake in to_patch)
        self.fake_names = tuple(fake_name for real_name, real, fake_name, fake in to_patch)
        self.reals = dict((id(fake), real) for real_name, real, fake_name, fake in to_patch)
        fakes = dict((id(real), fake) for real_name, real, fake_name, 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:
                    continue
                elif mod_name.startswith(self.ignore):
                    continue
                elif (not hasattr(module, "__name__") or module.__name__ in ('datetime', 'time')):
                    continue
>               for module_attribute in dir(module):
E               ModuleNotFoundError: No module named 'syslog'

c:\python36\lib\site-packages\freezegun\api.py:421: ModuleNotFoundError
================ 1 failed, 202 passed in -133582692.64 seconds ================

I investigated a little, and I found out that this appears only with py 1.5.x. Rolling back to py==1.4.34 fixes the issue. Is this a bug in py or freezegun?

(see also: spulec/freezegun#214)

@Kwpolska unfortunately this is a bug in py, see #170 .

I will work on a fix ASAP.

It's not just freezegun. It happened to the mypy project too, and we fixed it the same way. There's an AppVeyor support ticket but honestly I think the problem is here, in the py.log module -- it now unconditionally imports syslog which AFAICT is UNIX only -- it's in the doc section labeled "Unix specific services".

@gvanrossum your assessment is correct. At the time some refactoring was done, there was no proper Windows CI and that import escaped unnoticed.

@gvanrossum and @Kwpolska, 1.5.2 has been released with the fix, thanks again for the reports! 👍

My build passes, thanks!

@nicoddemus It seems like setup.py has changed to drop Python 3.3 support between the 1.5.0 release and 1.5.2 release. Was this intentional? It seems to be pinning my Python 3.3 Windows builds to the broken 1.5.0 build.

@pganssle thanks for writing. Are you having an error using 1.5.0 in py33, or are you just wondering if this was intentional?

It was intentional to drop support for py26 and py33 on 1.5.0, but we failed to add the proper metadata to 1.5.0 to indicate that, unfortunately. We were considering removing 1.5.0 from PyPI because >=1.5.1 is identical to it but with correct meta data, but we are reluctant to do that because it is considered a bad idea in general to pull releases from PyPI, but in this case might be the only solution.

cc @RonnyPfannschmidt

@nicoddemus Yes, my build is breaking because 1.5.0 doesn't have this fix but does have the metadata wrong.

I believe you can just edit the metadata directly on PyPI though, irrespective of the release. Dropping Python 3.3 from the 1.5.0 release should also fix my build.

I believe you can just edit the metadata directly on PyPI though

That would be ideal, but I'm not sure it is possible: the metadata resides inside the package, and changing its contents is not possible (AFAIK).

Perhaps pulling it is the right solution.

I believe you can fix your build by explicitly pinning <1.5 btw (which is the proper solution because >1.5 drops 3.3 support).

@nicoddemus Yes, I can try this, but the problem is that py is an indirect dependency, so it gets a bit complicated and I'd rather not be messing with it explicitly. Not to mention anything on Appveyor involves batch scripting, which is far from my forte...

I think you are right that pypi metadata is immutable once it's up there. I was a bit confused by this.

I think the traditional solution to "I need to pull a release" (though I doubt it will make a difference in this case) is to upload a .post1 version with the same version number. Not sure if the "which version can I download" logic will pick up the 3.3 trove classifier in the base 1.5.0 package and fall back to that, but if so, I think that even if you remove the 1.5.0 package, ==1.5.0 rules will still match 1.5.0.post1 (though I don't have time to test this right now).

@pganssle opened dateutil/dateutil#527 with a possible fix, please take a look.

Thanks for the PR. I have a different approach that's more complicated but somewhat more limited. Either one will ultimately get removed when either the trove classifiers are fixed for 1.5.0 or whoever is including py as a direct dependency on Python 3.3 starts pinning. Later this afternoon I'll try and track that down and open an issue or PR on that repo.

OK sounds good. Sorry for not being able to help more because I'm at work at the moment and can't spare much time.

Btw, pytest itself depends on py and won't drop the dependency anytime soon.

Btw, pytest itself depends on py and won't drop the dependency anytime soon.

I just realized this might not be clear as I wanted: I mention this because you can probably safely add the py<1.5 restriction on py33 if pytest is also a dependency, because pytest won't be dropping py anytime soon, and by the time it does you probably will have dropped py33 yourself.