This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: deepcopy() fails on ArgumentParser instances
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.6
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: Nosy List: mkolman, nitishch, terry.reedy
Priority: normal Keywords:

Created on 2018-01-25 16:39 by mkolman, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (3)
msg310686 - (view) Author: Martin Kolman (mkolman) Date: 2018-01-25 16:39
We (the Anaconda OS intaller team) are in the process of switching to a new version of a library (Pykickstart), which among other things switched from using optparse to argparse. And during this endeavour we found that it's apparently not possible to deepcopy ArgumentParser instances:


$ ipython3
Python 3.6.3 (default, Oct  9 2017, 12:07:10) 
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import argparse

In [2]: from copy import deepcopy

In [3]: parser = argparse.ArgumentParser()

In [4]: deepcopy(parser)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-53dc517e3ecc> in <module>()
----> 1 deepcopy(parser)

/usr/lib64/python3.6/copy.py in deepcopy(x, memo, _nil)
    178                     y = x
    179                 else:
--> 180                     y = _reconstruct(x, memo, *rv)
    181 
    182     # If is its own copy, don't memoize.

/usr/lib64/python3.6/copy.py in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    278     if state is not None:
    279         if deep:
--> 280             state = deepcopy(state, memo)
    281         if hasattr(y, '__setstate__'):
    282             y.__setstate__(state)

/usr/lib64/python3.6/copy.py in deepcopy(x, memo, _nil)
    148     copier = _deepcopy_dispatch.get(cls)
    149     if copier:
--> 150         y = copier(x, memo)
    151     else:
    152         try:

/usr/lib64/python3.6/copy.py in _deepcopy_dict(x, memo, deepcopy)
    238     memo[id(x)] = y
    239     for key, value in x.items():
--> 240         y[deepcopy(key, memo)] = deepcopy(value, memo)
    241     return y
    242 d[dict] = _deepcopy_dict

/usr/lib64/python3.6/copy.py in deepcopy(x, memo, _nil)
    148     copier = _deepcopy_dispatch.get(cls)
    149     if copier:
--> 150         y = copier(x, memo)
    151     else:
    152         try:

/usr/lib64/python3.6/copy.py in _deepcopy_list(x, memo, deepcopy)
    213     append = y.append
    214     for a in x:
--> 215         append(deepcopy(a, memo))
    216     return y
    217 d[list] = _deepcopy_list

/usr/lib64/python3.6/copy.py in deepcopy(x, memo, _nil)
    178                     y = x
    179                 else:
--> 180                     y = _reconstruct(x, memo, *rv)
    181 
    182     # If is its own copy, don't memoize.

/usr/lib64/python3.6/copy.py in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    278     if state is not None:
    279         if deep:
--> 280             state = deepcopy(state, memo)
    281         if hasattr(y, '__setstate__'):
    282             y.__setstate__(state)

/usr/lib64/python3.6/copy.py in deepcopy(x, memo, _nil)
    148     copier = _deepcopy_dispatch.get(cls)
    149     if copier:
--> 150         y = copier(x, memo)
    151     else:
    152         try:

/usr/lib64/python3.6/copy.py in _deepcopy_dict(x, memo, deepcopy)
    238     memo[id(x)] = y
    239     for key, value in x.items():
--> 240         y[deepcopy(key, memo)] = deepcopy(value, memo)
    241     return y
    242 d[dict] = _deepcopy_dict

/usr/lib64/python3.6/copy.py in deepcopy(x, memo, _nil)
    178                     y = x
    179                 else:
--> 180                     y = _reconstruct(x, memo, *rv)
    181 
    182     # If is its own copy, don't memoize.

/usr/lib64/python3.6/copy.py in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    278     if state is not None:
    279         if deep:
--> 280             state = deepcopy(state, memo)
    281         if hasattr(y, '__setstate__'):
    282             y.__setstate__(state)

/usr/lib64/python3.6/copy.py in deepcopy(x, memo, _nil)
    148     copier = _deepcopy_dispatch.get(cls)
    149     if copier:
--> 150         y = copier(x, memo)
    151     else:
    152         try:

/usr/lib64/python3.6/copy.py in _deepcopy_dict(x, memo, deepcopy)
    238     memo[id(x)] = y
    239     for key, value in x.items():
--> 240         y[deepcopy(key, memo)] = deepcopy(value, memo)
    241     return y
    242 d[dict] = _deepcopy_dict

/usr/lib64/python3.6/copy.py in deepcopy(x, memo, _nil)
    159             copier = getattr(x, "__deepcopy__", None)
    160             if copier:
--> 161                 y = copier(memo)
    162             else:
    163                 reductor = dispatch_table.get(cls)

TypeError: cannot deepcopy this pattern object


This should either be fixed or documented in proper places (the argparse documentation does not mention any pottential deepcopy issues as far as we can tell).
msg310827 - (view) Author: Nitish (nitishch) * Date: 2018-01-27 01:34
This seems to have been fixed in the latest master.

Commit I tested: 37420deb80dcf0fc41a728838b0340b93ca01d90
msg310844 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-01-27 05:38
Hi, you seem to be in luck, regardless of version.

Python 3.7.0a4+ (heads/master:a49ac99029, Jan 27 2018, 00:11:50) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import argparse
>>> from copy import deepcopy
>>> parser = argparse.ArgumentParser()
>>> deepcopy(parser)
ArgumentParser(prog='', usage=None, description=None, formatter_class=<class 'argparse.HelpFormatter'>, conflict_handler='error', add_help=True)

Fresh 3.6.4+ build also runs, but without enhanced repr.
...
<class 'argparse.ArgumentParser'>

(Note: 'crash' here means segfault rather than Python exception.)
History
Date User Action Args
2022-04-11 14:58:57adminsetgithub: 76849
2018-01-27 05:38:33terry.reedysetstatus: open -> closed

type: crash -> behavior

nosy: + terry.reedy
messages: + msg310844
resolution: out of date
stage: resolved
2018-01-27 01:34:33nitishchsetnosy: + nitishch
messages: + msg310827
2018-01-25 16:39:40mkolmancreate