Skip to content

Commit

Permalink
Improved behaviour: most cases covered by errors
Browse files Browse the repository at this point in the history
kerim371 committed Oct 6, 2021
1 parent 38a124d commit eb91d18
Showing 3 changed files with 104 additions and 62 deletions.
157 changes: 99 additions & 58 deletions pythonguts/editpy.py
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@
import ast
import astor
import os
import warnings


def generate_unique_filename(filenames: list, filename: str) -> str:
@@ -44,7 +43,7 @@ def prepare_filename(destfile: str) -> str:


class WalkerSrc(astor.TreeWalk):
# KEY - func node; # VALUE - parent
# KEY - func node; VALUE - parent
found_nodes = dict()

def pre_body_name(self):
@@ -56,14 +55,17 @@ def pre_body_name(self):
self.walk(body[i])
return True

def reset(self):
self.found_nodes.clear()


class WalkerDest(astor.TreeWalk):
# KEY - func node; # VALUE - parent
# KEY - func node; VALUE - parent
found_nodes = dict()
# KEY - dest node; VALUE - src node
matching_nodes = dict()
walker_src = WalkerSrc()

# def __init__(self, walker_src: WalkerSrc):
# super().__init__()
# self.walker_src = walker_src
replace_nodes_when_walk = False

def pre_body_name(self):
body = self.cur_node
@@ -72,67 +74,95 @@ def pre_body_name(self):

for i, child in enumerate(body[:]):
if isinstance(body[i], ast.FunctionDef):
node_dest, node_src = self.match_node(body[i], self.parent)
if node_src:
body[i] = node_src
node_src, node_dest = self.match_nodes(body[i], self.parent)
if node_dest and node_src:
self.found_nodes[node_dest] = self.parent
self.matching_nodes[node_dest] = node_src
if self.replace_nodes_when_walk:
body[i] = node_src
if isinstance(body[i], ast.ClassDef):
self.walk(body[i])
return True

def match_node(self, node, parent):
def match_nodes(self, node_dest, parent_dest):
"""
Return two variables if matching nodes were found:
destination node and source node.
Otherwise return None.
:param node: node to compare with source nodes
:param parent: parent of a given node (may be None)
:return: (node_dest, node_src) or None
source node and destination node.
Otherwise return None and None.
:param node_dest:
:param parent_dest:
:return:
"""
matching_node_src = None
matching_node_dest = None
for node_src in self.walker_src.found_nodes:
if not node or not node_src:
continue

if type(node) != type(node_src):
continue

if hasattr(node, 'name') != hasattr(node_src, 'name'):
continue

if hasattr(node, 'name') and hasattr(node_src, 'name') and \
node.name != node_src.name:
continue

if hasattr(node, 'args') != hasattr(node_src, 'args'):
continue

if hasattr(node, 'args') and hasattr(node_src, 'args') and \
astor.to_source(node.args) != astor.to_source(node_src.args):
continue

parent_src = self.walker_src.found_nodes[node_src]
if not parent or not parent_src:
continue

if type(parent) != type(parent_src):
continue

if hasattr(parent, 'name') != hasattr(parent_src, 'name'):
continue

if hasattr(parent, 'name') and hasattr(parent_src, 'name') and \
parent.name != parent_src.name:
continue

if hasattr(parent, 'args') != hasattr(parent_src, 'args'):
continue

if hasattr(parent, 'args') and hasattr(parent_src, 'args') and \
astor.to_source(parent.args) != astor.to_source(parent_src.args):
continue
matching_node_src, matching_node_dest = self.match_node(node_src, parent_src, node_dest, parent_dest)
if matching_node_src and matching_node_dest:
return matching_node_src, matching_node_dest
return None, None

return node, node_src
@staticmethod
def match_node(node_src, parent_src, node_dest, parent_dest):
"""
Return two variables if matching nodes were found:
source node and destination node.
Otherwise return None and None.
:param node_src:
:param parent_src:
:param node_dest:
:param parent_dest:
:return:
"""
if not node_dest or not node_src:
return None, None
if type(node_dest) != type(node_src):
return None, None
if hasattr(node_dest, 'name') != hasattr(node_src, 'name'):
return None, None
if hasattr(node_dest, 'name') and hasattr(node_src, 'name') and \
node_dest.name != node_src.name:
return None, None
if hasattr(node_dest, 'args') != hasattr(node_src, 'args'):
return None, None
if hasattr(node_dest, 'args') and hasattr(node_src, 'args') and \
astor.to_source(node_dest.args) != astor.to_source(node_src.args):
return None, None
if not parent_dest or not parent_src:
return None, None
if type(parent_dest) != type(parent_src):
return None, None
if hasattr(parent_dest, 'name') != hasattr(parent_src, 'name'):
return None, None
if hasattr(parent_dest, 'name') and hasattr(parent_src, 'name') and \
parent_dest.name != parent_src.name:
return None, None
if hasattr(parent_dest, 'args') != hasattr(parent_src, 'args'):
return None, None
if hasattr(parent_dest, 'args') and hasattr(parent_src, 'args') and \
astor.to_source(parent_dest.args) != astor.to_source(parent_src.args):
return None, None
return node_src, node_dest

def get_unresolved_src_nodes(self) -> list:
unresolved_nodes_src = list()
matching_node_src = None
matching_node_dest = None
for node_src in self.walker_src.found_nodes:
parent_src = self.walker_src.found_nodes[node_src]
for node_dest in self.found_nodes:
parent_dest = self.found_nodes[node_dest]
matching_node_src, matching_node_dest = self.match_node(node_src, parent_src, node_dest, parent_dest)
if matching_node_src:
break
if not matching_node_src:
unresolved_nodes_src.append(node_src)
return unresolved_nodes_src

return None, None
def reset(self):
self.found_nodes.clear()
self.matching_nodes.clear()
self.walker_src = WalkerSrc()


def main():
@@ -168,10 +198,21 @@ def main():

walker_src = WalkerSrc()
walker_src.walk(tree_src)
if not walker_src.found_nodes:
parser.error(f"unable to find any function definition in source file:\n{args.srcfile}\n")

walker_dest = WalkerDest()
walker_dest.walker_src = walker_src
walker_dest.walk(tree_dest)
walker_dest.walk(tree_dest) # walk only to check if everything is Ok
unresolved_nodes_src = walker_dest.get_unresolved_src_nodes()
if unresolved_nodes_src:
err_msg = (f"unable to find destination functions matching for the following source functions:\n")
for n in unresolved_nodes_src:
err_msg += f"{astor.to_source(n)}\n"
parser.error(err_msg)

walker_dest.replace_nodes_when_walk = True
walker_dest.walk(tree_dest) # now replace nodes when walk

prepared_filename = prepare_filename(args.destfile)
with open(prepared_filename, "w") as file:
5 changes: 3 additions & 2 deletions pythonguts/tests/test_pythonguts.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import os
from pathlib import Path
import shutil
import subprocess, os, filecmp
import unittest
import subprocess
import sys
import unittest


class test_basics(unittest.TestCase):
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@

setuptools.setup(
name='pythonguts',
version='0.1.0',
version='0.2.0',
packages=setuptools.find_packages(),
url='https://github.com/tierra-colada/pythonguts',
license='MIT',
@@ -17,7 +17,7 @@
'automatically find and replace function definition',
long_description=long_description,
long_description_content_type='text/markdown',
download_url='https://github.com/tierra-colada/pythonguts/archive/refs/tags/v0.1.0.tar.gz',
download_url='https://github.com/tierra-colada/pythonguts/archive/refs/tags/v0.2.0.tar.gz',
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Console',

0 comments on commit eb91d18

Please sign in to comment.