PyCQA / redbaron

Bottom-up approach to refactoring in python
http://redbaron.pycqa.org/
694 stars 74 forks source link

Inserting node causes `.help()` to crash #176

Open jrs65 opened 5 years ago

jrs65 commented 5 years ago

I'm trying to use Red Baron (which seems great), but I'm having a bit of a weird crash when inserting nodes. This actually fails with the example given in the documentation

red = RedBaron("foo = 42\nprint('bar')\n")
red.help()  # Works fine as expected
red.print_.insert_before("baz")
red.help()  # Crashes with output below.

However, other then .help() everything seems to work fine after the insertion. For instance:

>>> print red.dumps()
foo = 42
baz
print('bar')

I'm using:

$ pip list | grep baron
baron                              0.8
redbaron                           0.8

on Python 2.7.15.

The full output and traceback of the .help() call is:

0 -----------------------------------------------------
AssignmentNode()
  # identifiers: assign, assignment, assignment_, assignmentnode
  operator=''
  target ->
    NameNode()
      # identifiers: name, name_, namenode
      value=u'foo'
  value ->
    IntNode()
      # identifiers: int, int_, intnode
      value=u'42'
1 -----------------------------------------------------
EndlNode()
  # identifiers: endl, endl_, endlnode
  value=u'\n'
  indent=''
2 -----------------------------------------------------
NameNode()
  # identifiers: name, name_, namenode
  value=u'baz'
3 -----------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/redbaron/base_nodes.py", line 36, in wrapper
    return function(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/redbaron/base_nodes.py", line 293, in root
    current = current.parent
AttributeError: 'NoneType' object has no attribute 'parent'
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/redbaron/base_nodes.py", line 36, in wrapper
    return function(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/redbaron/base_nodes.py", line 227, in absolute_bounding_box
    return baron.path.path_to_bounding_box(self.root.fst(), path)
  File "/usr/local/lib/python2.7/site-packages/redbaron/base_nodes.py", line 718, in __getattr__
    self.__class__.__name__, key, key))
AttributeError: EndlNode instance has no attribute 'root' and 'root' is not a valid identifier of another node
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-12-857370972330> in <module>()
----> 1 red.help()

/usr/local/lib/python2.7/site-packages/redbaron/base_nodes.pyc in help(self, deep, with_formatting)
    420         for num, i in enumerate(self.data):
    421             sys.stdout.write(str(num) + " -----------------------------------------------------\n")
--> 422             i.help(deep=deep, with_formatting=with_formatting)
    423 
    424     def __help__(self, deep=2, with_formatting=False):

/usr/local/lib/python2.7/site-packages/redbaron/base_nodes.pyc in help(self, deep, with_formatting)
    953     def help(self, deep=2, with_formatting=False):
    954         if runned_from_ipython():
--> 955             sys.stdout.write(help_highlight(self.__help__(deep=deep, with_formatting=with_formatting) + "\n"))
    956         else:
    957             sys.stdout.write(self.__help__(deep=deep, with_formatting=with_formatting) + "\n")

/usr/local/lib/python2.7/site-packages/redbaron/base_nodes.pyc in __help__(self, deep, with_formatting)
    966         else:
    967             to_join.append("# identifiers: %s" % ", ".join(self.generate_identifiers()))
--> 968             if self._get_helpers():
    969                 to_join.append("# helpers: %s" % ", ".join(self._get_helpers()))
    970             if self._default_test_value != "value":

/usr/local/lib/python2.7/site-packages/redbaron/base_nodes.pyc in _get_helpers(self)
    929         ])
    930         return [x for x in dir(self) if
--> 931                 not x.startswith("_") and x not in not_helpers and inspect.ismethod(getattr(self, x))]
    932 
    933     def fst(self):

/usr/local/lib/python2.7/site-packages/redbaron/base_nodes.pyc in __getattr__(self, key)
    716             raise AttributeError(
    717                 "%s instance has no attribute '%s' and '%s' is not a valid identifier of another node" % (
--> 718                     self.__class__.__name__, key, key))
    719 
    720         return self.find(key)

AttributeError: EndlNode instance has no attribute 'absolute_bounding_box' and 'absolute_bounding_box' is not a valid identifier of another node
chrahunt commented 5 years ago

Same here. Running with redbaron.DEBUG shows the following:

Output ``` [ins] In [181]: redbaron.DEBUG = True [ins] In [182]: r = RedBaron('a = 1') [ins] In [183]: r.insert(0, 'b = 2') Before synchronise, self.data = '[]' + '0 a = 1 ' Start _generate_expected_list for LineProxyList >>> current list '[[b = 2 , None], [a = 1 , []]]' Detect indentation has '' [0] [b = 2 , None] >> Append node to expected_list: '[b = 2 ]' -- current result: ['b = 2'] current HAS None for formatting >> Current is not last and not endl, append a separator -- current result: ['b = 2\n'] [1] [a = 1 , []] >> Append node to expected_list: '[a = 1 ]' -- current result: ['b = 2\na = 1'] current doesn't have None for formatting >> Append formatting to expected_list: [] -- current result: ['b = 2\na = 1'] End of loop -- result before end list procedure: self.parent is NOT followed by another node, last indentation is empty string >> List is empty or last node is not a CodeBlockNode or EndlNode, append a separator to it and set identation to it -- current result: ['b = 2\na = 1\n'] -- final result: End After synchronise, self.data = '[]' + '0 b = 2 1 '\n' 2 a = 1 3 '\n' ' [ins] In [184]: r.help() 0 ----------------------------------------------------- AssignmentNode() # identifiers: assign, assignment, assignment_, assignmentnode operator='' target -> NameNode() # identifiers: name, name_, namenode value='b' annotation -> None value -> IntNode() # identifiers: int, int_, intnode value='2' 1 ----------------------------------------------------- Traceback (most recent call last): File "/home/chris/.virtualenvs/tmp.RD9yDcNxAp/lib/python3.7/site-packages/redbaron/base_nodes.py", line 36, in wrapper return function(*args, **kwargs) File "/home/chris/.virtualenvs/tmp.RD9yDcNxAp/lib/python3.7/site-packages/redbaron/base_nodes.py", line 293, in root current = current.parent AttributeError: 'NoneType' object has no attribute 'parent' Traceback (most recent call last): File "/home/chris/.virtualenvs/tmp.RD9yDcNxAp/lib/python3.7/site-packages/redbaron/base_nodes.py", line 36, in wrapper return function(*args, **kwargs) File "/home/chris/.virtualenvs/tmp.RD9yDcNxAp/lib/python3.7/site-packages/redbaron/base_nodes.py", line 227, in absolute_bounding_box return baron.path.path_to_bounding_box(self.root.fst(), path) File "/home/chris/.virtualenvs/tmp.RD9yDcNxAp/lib/python3.7/site-packages/redbaron/base_nodes.py", line 718, in __getattr__ self.__class__.__name__, key, key)) AttributeError: EndlNode instance has no attribute 'root' and 'root' is not a valid identifier of another node --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) in ----> 1 r.help() ~/.virtualenvs/tmp.RD9yDcNxAp/lib/python3.7/site-packages/redbaron/base_nodes.py in help(self, deep, with_formatting) 420 for num, i in enumerate(self.data): 421 sys.stdout.write(str(num) + " -----------------------------------------------------\n") --> 422 i.help(deep=deep, with_formatting=with_formatting) 423 424 def __help__(self, deep=2, with_formatting=False): ~/.virtualenvs/tmp.RD9yDcNxAp/lib/python3.7/site-packages/redbaron/base_nodes.py in help(self, deep, with_formatting) 953 def help(self, deep=2, with_formatting=False): 954 if runned_from_ipython(): --> 955 sys.stdout.write(help_highlight(self.__help__(deep=deep, with_formatting=with_formatting) + "\n")) 956 else: 957 sys.stdout.write(self.__help__(deep=deep, with_formatting=with_formatting) + "\n") ~/.virtualenvs/tmp.RD9yDcNxAp/lib/python3.7/site-packages/redbaron/base_nodes.py in __help__(self, deep, with_formatting) 966 else: 967 to_join.append("# identifiers: %s" % ", ".join(self.generate_identifiers())) --> 968 if self._get_helpers(): 969 to_join.append("# helpers: %s" % ", ".join(self._get_helpers())) 970 if self._default_test_value != "value": ~/.virtualenvs/tmp.RD9yDcNxAp/lib/python3.7/site-packages/redbaron/base_nodes.py in _get_helpers(self) 928 'to_python', 929 ]) --> 930 return [x for x in dir(self) if 931 not x.startswith("_") and x not in not_helpers and inspect.ismethod(getattr(self, x))] 932 ~/.virtualenvs/tmp.RD9yDcNxAp/lib/python3.7/site-packages/redbaron/base_nodes.py in (.0) 929 ]) 930 return [x for x in dir(self) if --> 931 not x.startswith("_") and x not in not_helpers and inspect.ismethod(getattr(self, x))] 932 933 def fst(self): ~/.virtualenvs/tmp.RD9yDcNxAp/lib/python3.7/site-packages/redbaron/base_nodes.py in __getattr__(self, key) 716 raise AttributeError( 717 "%s instance has no attribute '%s' and '%s' is not a valid identifier of another node" % ( --> 718 self.__class__.__name__, key, key)) 719 720 return self.find(key) AttributeError: EndlNode instance has no attribute 'absolute_bounding_box' and 'absolute_bounding_box' is not a valid identifier of another node ```

The first error

Traceback (most recent call last):
  File "/home/chris/.virtualenvs/tmp.RD9yDcNxAp/lib/python3.7/site-packages/redbaron/base_nodes.py", line 36, in wrapper
    return function(*args, **kwargs)
  File "/home/chris/.virtualenvs/tmp.RD9yDcNxAp/lib/python3.7/site-packages/redbaron/base_nodes.py", line 293, in root
    current = current.parent
AttributeError: 'NoneType' object has no attribute 'parent'

seems to be fundamentally the following: r.node_list[1].parent.parent.parent, which fails because the node list itself does not have a parent. This happens here, but the change was several years ago, so it doesn't really explain why this is happening now.