Skip to content

functools.wraps can pollute a function's global namespace #242

Description

@pierreglaser

using functools.wraps

functools.wraps(f)
defg():
pass

changes a g's __module__ attribute to f.__module__, but not its __globals__. Because we retrieve globals from state['module'] at unpickling time, this will pollute a depickled version of g with the globals of f.__module__

As an illustration:

importfunctoolsimportpickleimportcloudpickle@functools.wraps(pickle._dumps)deff():
passdepickled_f=pickle.loads(cloudpickle.dumps(f))
assertdepickled_f.__globals__isvars(pickle)

passes.

This is tricky:
On one hand one can spot if a function is wrapping another by checking for a __wrapped__ attribute. On the other hand, once wraps is used, there is no way back, and f's attributes are lost forever.
The side effects are not life threatening, but this may be worth adding a warning at pickling time. I am thinking about (roughly):

ifhasattr(func, '__wrapped__'):
msg= ("This function seems decorated by functools.wraps. This"" may cause {}'s __globals__ to be populated with"" unnecessary global variables at unpickling time."" To fix it, change the assigned argument of"" functools.wraps so that is does not include __module__ ")
raiseUserWarning(msg.format(func.__code__.co_name))

Inside extract_func_data.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions