Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Global declaration in extracted method #392

Merged
merged 26 commits into from Sep 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c7d1446
extraction with global simple case
Sep 16, 2021
6c7654d
extract with global definition
Sep 16, 2021
ef4cb67
global in oneliner
Sep 17, 2021
d31065d
refactored getting function body
Sep 17, 2021
ba4746f
Fix detection of read/written variables when extract method of code i…
lieryan Sep 12, 2021
ef6f23a
Refactor handling of loop_depth to use contextmanager
lieryan Sep 12, 2021
681fd0a
Rename _FunctionInformationCollector.{_handle_loop_node->_handle_loop…
lieryan Sep 12, 2021
11f38c5
Refactor _handle_conditional_context()
lieryan Sep 12, 2021
91743c4
Fix write-only variable when extracting method in a loop
lieryan Sep 12, 2021
a450ebb
extracting static WIP
Sep 9, 2021
c88e77c
some refactorings
Sep 9, 2021
2eb9e61
raise error when extracting to static with self in body
Sep 9, 2021
f1ac028
kind option to refactoring
Sep 9, 2021
8498cf5
cannot extract from function to staticmethod
Sep 9, 2021
cf1b657
extracting from classmethod
Sep 11, 2021
c850ad8
refactored test
Sep 11, 2021
b4692ef
working classmethod
Sep 11, 2021
48d9b34
use kind like in PyFunctionDef
Sep 12, 2021
1b5d5e2
removed f-string
Sep 12, 2021
80882e9
assertraisesregex not supported in 2.7
Sep 12, 2021
d0b5eaf
refactor and docs
Sep 13, 2021
0944ad9
fixed bug in self name
Sep 15, 2021
b7d7af2
dont check self in body condition
Sep 16, 2021
e1f6103
Change workflow to run on pull_request_target
lieryan Sep 17, 2021
7e70f63
merge master and change getting globals
climbus Sep 18, 2021
edbacda
merged with master
climbus Sep 18, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
53 changes: 47 additions & 6 deletions rope/refactor/extract.py
Expand Up @@ -670,16 +670,42 @@ def _find_function_returns(self):

def _get_unindented_function_body(self, returns):
if self.info.one_line:
if self.info.returning_named_expr:
return 'return ' + '(' + _join_lines(self.info.extracted) + ')'
else:
return 'return ' + _join_lines(self.info.extracted)
extracted_body = self.info.extracted
unindented_body = sourceutils.fix_indentation(extracted_body, 0)
return self._get_one_line_function_body()
return self._get_multiline_function_body(returns)

def _get_multiline_function_body(self, returns):
unindented_body = sourceutils.fix_indentation(self.info.extracted, 0)
unindented_body = self._insert_globals(unindented_body)
if returns:
unindented_body += '\nreturn %s' % self._get_comma_form(returns)
return unindented_body

def _get_one_line_function_body(self):
if self.info.returning_named_expr:
body = 'return ' + '(' + _join_lines(self.info.extracted) + ')'
else:
body = 'return ' + _join_lines(self.info.extracted)
return self._insert_globals(body)

def _insert_globals(self, unindented_body):
globals_in_body = self._get_globals_in_body(unindented_body)
globals_ = self.info_collector.globals_ & self._get_internal_variables()
globals_ = globals_ - globals_in_body

if globals_:
unindented_body = "global {}\n{}".format(", ".join(globals_), unindented_body)
return unindented_body

@staticmethod
def _get_globals_in_body(unindented_body):
node = _parse_text(unindented_body)
visitor = _GlobalFinder()
ast.walk(node, visitor)
return visitor.globals_

def _get_internal_variables(self):
return self.info_collector.read | self.info_collector.written | self.info_collector.maybe_written


class _ExtractVariableParts(object):

Expand Down Expand Up @@ -715,6 +741,10 @@ def __init__(self, start, end, is_global):
self.postwritten = OrderedSet()
self.host_function = True
self.conditional = False
self.surrounded_by_loop = 0
self.globals_ = OrderedSet()
self.surrounded_by_loop = 0
self.loop_depth = 0
self.loop_depth = 0

def _read_variable(self, name, lineno):
Expand Down Expand Up @@ -754,6 +784,9 @@ def _FunctionDef(self, node):
for name in visitor.read - visitor.written:
self._read_variable(name, node.lineno)

def _Global(self, node):
self.globals_.add(*node.names)

def _AsyncFunctionDef(self, node):
self._FunctionDef(node)

Expand Down Expand Up @@ -939,6 +972,14 @@ def _ClassDef(self, node):
pass


class _GlobalFinder(object):
def __init__(self):
self.globals_ = OrderedSet()

def _Global(self, node):
self.globals_.add(*node.names)


def _get_function_kind(scope):
return scope.pyobject.get_kind()

Expand Down
95 changes: 95 additions & 0 deletions ropetest/refactor/extracttest.py
Expand Up @@ -1811,6 +1811,101 @@ def second_method(someargs):

self.assertEqual(expected, refactored)

def test_extraction_method_with_global_variable(self):
code = dedent('''\
g = None

def f():
global g

g = 2

f()
print(g)
''')
extract_target = 'g = 2'
start, end = code.index(extract_target), code.index(extract_target) + len(extract_target)
refactored = self.do_extract_method(code, start, end, '_g')
expected = dedent('''\
g = None

def f():
global g

_g()

def _g():
global g
g = 2

f()
print(g)
''')
self.assertEqual(expected, refactored)

def test_extraction_method_with_global_variable_and_global_declaration(self):
code = dedent('''\
g = None

def f():
global g

g = 2

f()
print(g)
''')
start, end = 23, 42
refactored = self.do_extract_method(code, start, end, '_g')
expected = dedent('''\
g = None

def f():
_g()

def _g():
global g

g = 2

f()
print(g)
''')
self.assertEqual(expected, refactored)

def test_extraction_one_line_with_global_variable(self):
code = dedent('''\
g = None

def f():
global g

a = g

f()
print(g)
''')
extract_target = '= g'
start, end = code.index(extract_target) + 2, code.index(extract_target) + 3
refactored = self.do_extract_method(code, start, end, '_g')
print(refactored)
expected = dedent('''\
g = None

def f():
global g

a = _g()

def _g():
global g
return g

f()
print(g)
''')
self.assertEqual(expected, refactored)


if __name__ == '__main__':
unittest.main()