[WIP] Added implementation scanning

This commit is contained in:
Sven Heidemann 2022-01-16 16:10:20 +01:00
parent 61b1838c40
commit c53b3b7669
7 changed files with 143 additions and 6 deletions

View File

@ -4,9 +4,11 @@ from cpl_core.application import ApplicationABC
from cpl_core.configuration import ConfigurationABC from cpl_core.configuration import ConfigurationABC
from cpl_core.console import Console from cpl_core.console import Console
from cpl_core.dependency_injection import ServiceProviderABC from cpl_core.dependency_injection import ServiceProviderABC
from cpl_query.extension import List
from py_to_uxf_core.abc.python_parser_abc import PythonParserABC from py_to_uxf_core.abc.python_parser_abc import PythonParserABC
from py_to_uxf_core.abc.umlet_creator_abc import UmletCreatorABC from py_to_uxf_core.abc.umlet_creator_abc import UmletCreatorABC
from py_to_uxf_core.model.class_implementation import ClassImplementation
from py_to_uxf_core.model.python_class import PythonClass from py_to_uxf_core.model.python_class import PythonClass
@ -58,8 +60,11 @@ class Application(ApplicationABC):
Console.write_line(f'Output path:', self._file) Console.write_line(f'Output path:', self._file)
xml = '' xml = ''
try: try:
classes: list[PythonClass] = self._parser.parse() classes: List[PythonClass] = self._parser.parse_classes()
Console.write_line(f'Found {len(classes)} classes') Console.write_line(f'Found {classes.count()} classes')
implementations: List[ClassImplementation] = self._parser.parse_implementations(classes)
Console.write_line(f'Found {implementations.count()} implementations')
Console.write_line(implementations)
# self._console_output(classes) # self._console_output(classes)
xml = self._umlet_creator.generate_xml(classes) xml = self._umlet_creator.generate_xml(classes)
except Exception as e: except Exception as e:

View File

@ -9,12 +9,14 @@ from py_to_uxf_core.abc.attribute_scanner_abc import AttributeScannerABC
from py_to_uxf_core.abc.class_scanner_abc import ClassScannerABC from py_to_uxf_core.abc.class_scanner_abc import ClassScannerABC
from py_to_uxf_core.abc.file_scanner_abc import FileScannerABC from py_to_uxf_core.abc.file_scanner_abc import FileScannerABC
from py_to_uxf_core.abc.function_scanner_abc import FunctionScannerABC from py_to_uxf_core.abc.function_scanner_abc import FunctionScannerABC
from py_to_uxf_core.abc.implementation_scanner_abc import ImplementationScannerABC
from py_to_uxf_core.abc.python_parser_abc import PythonParserABC from py_to_uxf_core.abc.python_parser_abc import PythonParserABC
from py_to_uxf_core.abc.umlet_creator_abc import UmletCreatorABC from py_to_uxf_core.abc.umlet_creator_abc import UmletCreatorABC
from py_to_uxf_core.service.attribute_scanner_service import AttributeScannerService from py_to_uxf_core.service.attribute_scanner_service import AttributeScannerService
from py_to_uxf_core.service.class_scanner_service import ClassScannerService from py_to_uxf_core.service.class_scanner_service import ClassScannerService
from py_to_uxf_core.service.file_scanner_service import FileScannerService from py_to_uxf_core.service.file_scanner_service import FileScannerService
from py_to_uxf_core.service.function_scanner_service import FunctionScannerService from py_to_uxf_core.service.function_scanner_service import FunctionScannerService
from py_to_uxf_core.service.implementation_scanner_service import ImplementationScannerService
from py_to_uxf_core.service.python_parser_service import PythonParserService from py_to_uxf_core.service.python_parser_service import PythonParserService
from py_to_uxf_core.service.umlet_creator_service import UmletCreatorService from py_to_uxf_core.service.umlet_creator_service import UmletCreatorService
@ -38,6 +40,7 @@ class Startup(StartupABC):
services.add_transient(ClassScannerABC, ClassScannerService) services.add_transient(ClassScannerABC, ClassScannerService)
services.add_transient(FunctionScannerABC, FunctionScannerService) services.add_transient(FunctionScannerABC, FunctionScannerService)
services.add_transient(AttributeScannerABC, AttributeScannerService) services.add_transient(AttributeScannerABC, AttributeScannerService)
services.add_transient(ImplementationScannerABC, ImplementationScannerService)
services.add_singleton(PythonParserABC, PythonParserService) services.add_singleton(PythonParserABC, PythonParserService)
services.add_singleton(UmletCreatorABC, UmletCreatorService) services.add_singleton(UmletCreatorABC, UmletCreatorService)

View File

@ -0,0 +1,14 @@
from abc import ABC, abstractmethod
from typing import Optional
from py_to_uxf_core.model.class_implementation import ClassImplementation
from py_to_uxf_core.model.python_class import PythonClass
class ImplementationScannerABC(ABC):
@abstractmethod
def __init__(self): pass
@abstractmethod
def scan_line_for_implementation(self, line: str, classes: list[PythonClass]) -> Optional[ClassImplementation]: pass

View File

@ -2,6 +2,7 @@ from abc import ABC, abstractmethod
from cpl_query.extension import List from cpl_query.extension import List
from py_to_uxf_core.model.class_implementation import ClassImplementation
from py_to_uxf_core.model.python_class import PythonClass from py_to_uxf_core.model.python_class import PythonClass
@ -11,4 +12,7 @@ class PythonParserABC(ABC):
def __init__(self): pass def __init__(self): pass
@abstractmethod @abstractmethod
def parse(self) -> List[PythonClass]: pass def parse_classes(self) -> List[PythonClass]: pass
@abstractmethod
def parse_implementations(self, classes: List[PythonClass]) -> List[ClassImplementation]: pass

View File

@ -0,0 +1,22 @@
from py_to_uxf_core.model.python_class import PythonClass
class ClassImplementation:
def __init__(self, base: PythonClass, subclass: PythonClass):
self._base = base
self._subclass = subclass
@property
def base(self) -> PythonClass:
return self._base
@property
def subclass(self) -> PythonClass:
return self._subclass
def __str__(self):
return f'{self._subclass.name} -> {self._base.name}'
def __repr__(self):
return f'{self._subclass.name} -> {self._base.name}'

View File

@ -0,0 +1,32 @@
from typing import Optional
from cpl_core.console import Console
from cpl_query.extension import List
from py_to_uxf_core.abc.implementation_scanner_abc import ImplementationScannerABC
from py_to_uxf_core.model.class_implementation import ClassImplementation
from py_to_uxf_core.model.python_class import PythonClass
class ImplementationScannerService(ImplementationScannerABC):
def __init__(self):
pass
def scan_line_for_implementation(self, line: str, classes: List[PythonClass]) -> Optional[ClassImplementation]:
line = line.replace(' ', '')
line = line.replace('\t', '')
if line.startswith('class ') and '(' in line and ')' in line:
sub_name = line.split('class ')[1].split('(')[0]
sub: Optional[PythonClass] = classes.where(lambda c: c.name == sub_name).first_or_default()
if sub is None:
return None
base_name = line.split('(')[1].split(')')[0]
base: Optional[PythonClass] = classes.where(lambda c: c.name == base_name).first_or_default()
if base is None:
return None
return ClassImplementation(base, sub)
return None

View File

@ -8,7 +8,9 @@ from py_to_uxf_core.abc.attribute_scanner_abc import AttributeScannerABC
from py_to_uxf_core.abc.class_scanner_abc import ClassScannerABC from py_to_uxf_core.abc.class_scanner_abc import ClassScannerABC
from py_to_uxf_core.abc.file_scanner_abc import FileScannerABC from py_to_uxf_core.abc.file_scanner_abc import FileScannerABC
from py_to_uxf_core.abc.function_scanner_abc import FunctionScannerABC from py_to_uxf_core.abc.function_scanner_abc import FunctionScannerABC
from py_to_uxf_core.abc.implementation_scanner_abc import ImplementationScannerABC
from py_to_uxf_core.abc.python_parser_abc import PythonParserABC from py_to_uxf_core.abc.python_parser_abc import PythonParserABC
from py_to_uxf_core.model.class_implementation import ClassImplementation
from py_to_uxf_core.model.python_class import PythonClass from py_to_uxf_core.model.python_class import PythonClass
@ -19,7 +21,8 @@ class PythonParserService(PythonParserABC):
file_scanner: FileScannerABC, file_scanner: FileScannerABC,
class_scanner: ClassScannerABC, class_scanner: ClassScannerABC,
function_scanner: FunctionScannerABC, function_scanner: FunctionScannerABC,
attribute_scanner: AttributeScannerABC attribute_scanner: AttributeScannerABC,
implementation_scanner: ImplementationScannerABC
): ):
PythonParserABC.__init__(self) PythonParserABC.__init__(self)
@ -27,8 +30,11 @@ class PythonParserService(PythonParserABC):
self._class_scanner = class_scanner self._class_scanner = class_scanner
self._function_scanner = function_scanner self._function_scanner = function_scanner
self._attribute_scanner = attribute_scanner self._attribute_scanner = attribute_scanner
self._implementation_scanner = implementation_scanner
def parse(self) -> List[PythonClass]: self._files_with_classes: list[str] = []
def parse_classes(self) -> List[PythonClass]:
files = self._file_scanner.scan_files() files = self._file_scanner.scan_files()
classes = List(PythonClass) classes = List(PythonClass)
for file in files: for file in files:
@ -74,6 +80,7 @@ class PythonParserService(PythonParserABC):
cls = self._class_scanner.scan_line_for_classes(line) cls = self._class_scanner.scan_line_for_classes(line)
if cls is not None: if cls is not None:
classes.append(cls) classes.append(cls)
self._files_with_classes.append(file)
continue continue
func = self._function_scanner.scan_line_for_function(line) func = self._function_scanner.scan_line_for_function(line)
@ -90,6 +97,56 @@ class PythonParserService(PythonParserABC):
cls.add_attribute(attribute) cls.add_attribute(attribute)
except Exception as e: except Exception as e:
Console.error(f'Parsing {file}@{i}', f'{e} -> {traceback.format_exc()}') Console.error(f'Parsing {file}@{i}', f'{e} -> {traceback.format_exc()}')
file_content.close()
exit() exit()
file_content.close()
return classes return classes
def parse_implementations(self, classes: List[PythonClass]) -> List[ClassImplementation]:
implementations = List()
files = self._files_with_classes
for file in files:
is_comment = False
with open(file, 'r') as file_content:
implementation: Optional[ClassImplementation] = None
lines = file_content.readlines()
for i in range(len(lines)):
try:
line = lines[i]
line = line.replace(' ', '')
line = line.replace('\t', '')
# replace line break at the end of line
if line.endswith('\n'):
line = line.replace('\n', '')
if line == '\n' or line == '':
continue
# one line comments
if line != '"""' and line.startswith('"""') and line.endswith('"""') or line.startswith('#'):
continue
# start multi line comment
if line.startswith('"""') or line.count('"""') == 1 and not is_comment:
is_comment = True
continue
# end multi line comment
if line.startswith('"""') or line.endswith('"""') or line.count('"""') == 1 and is_comment:
is_comment = False
continue
if is_comment:
continue
if implementation is None:
implementation = self._implementation_scanner.scan_line_for_implementation(line, classes)
if implementation is not None:
implementations.append(implementation)
except Exception as e:
Console.error(f'Parsing {file}@{i}', f'{e} -> {traceback.format_exc()}')
file_content.close()
exit()
file_content.close()
return implementations