# Buggy code
def __getattr__(self, name):
    return getattr(self.parsed, name)


# Traceback (RecursionError)
---------------------------------------------------------------------------
RecursionError                            Traceback (most recent call last)
<ipython-input-7-90086e6e0e64> in <module>
----> 1 r.graph()[0].reverse()

~/miniconda3/envs/py36_v11/lib/python3.6/site-packages/networkx/classes/digraph.py in reverse(self, copy)
1195             H = self.__class__()
1196             H.graph.update(deepcopy(self.graph))
-> 1197             H.add_nodes_from((n, deepcopy(d)) for n, d in self.node.items())
1198             H.add_edges_from((v, u, deepcopy(d)) for u, v, d
1199                              in self.edges(data=True))

~/miniconda3/envs/py36_v11/lib/python3.6/site-packages/networkx/classes/digraph.py in add_nodes_from(self, nodes_for_adding, **attr)
470
471         """
--> 472         for n in nodes_for_adding:
473             # keep all this inside try/except because
474             # CPython throws TypeError on n not in self._succ,

~/miniconda3/envs/py36_v11/lib/python3.6/site-packages/networkx/classes/digraph.py in <genexpr>(.0)
1195             H = self.__class__()
1196             H.graph.update(deepcopy(self.graph))
-> 1197             H.add_nodes_from((n, deepcopy(d)) for n, d in self.node.items())
1198             H.add_edges_from((v, u, deepcopy(d)) for u, v, d
1199                              in self.edges(data=True))

~/miniconda3/envs/py36_v11/lib/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:

~/miniconda3/envs/py36_v11/lib/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

~/miniconda3/envs/py36_v11/lib/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.

~/miniconda3/envs/py36_v11/lib/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)

~/miniconda3/envs/py36_v11/lib/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:

~/miniconda3/envs/py36_v11/lib/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

~/miniconda3/envs/py36_v11/lib/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.

~/miniconda3/envs/py36_v11/lib/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)

~/miniconda3/envs/py36_v11/lib/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:

~/miniconda3/envs/py36_v11/lib/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

~/miniconda3/envs/py36_v11/lib/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.

~/miniconda3/envs/py36_v11/lib/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)

~/miniconda3/envs/py36_v11/lib/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:

~/miniconda3/envs/py36_v11/lib/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

~/miniconda3/envs/py36_v11/lib/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.

~/miniconda3/envs/py36_v11/lib/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)

~/miniconda3/envs/py36_v11/lib/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:

~/miniconda3/envs/py36_v11/lib/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

~/miniconda3/envs/py36_v11/lib/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.

~/miniconda3/envs/py36_v11/lib/python3.6/copy.py in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
279         if deep:
280             state = deepcopy(state, memo)
--> 281         if hasattr(y, '__setstate__'):
282             y.__setstate__(state)
283         else:

~/miniconda3/envs/py36_v11/lib/python3.6/site-packages/dvc/path_info.py in __getattr__(self, name)
185
186     def __getattr__(self, name):
--> 187         return getattr(self.parsed, name)
188
189     @cached_property

... last 1 frames repeated, from the frame below ...

~/miniconda3/envs/py36_v11/lib/python3.6/site-packages/dvc/path_info.py in __getattr__(self, name)
185
186     def __getattr__(self, name):
--> 187         return getattr(self.parsed, name)
188
189     @cached_property

RecursionError: maximum recursion depth exceeded

# Fixed code
def __getattr__(self, name):
    # When deepcopy is called, it creates and object without __init__,
    # self.parsed is not initialized and it causes infinite recursion.
    # More on this special casing here:
    # https://stackoverflow.com/a/47300262/298182
    if name.startswith("__"):
        raise AttributeError(name)
    return getattr(self.parsed, name)