[WIP] Added implementation scanning
This commit is contained in:
parent
61b1838c40
commit
c53b3b7669
@ -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:
|
||||||
|
@ -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)
|
||||||
|
14
src/py_to_uxf_core/abc/implementation_scanner_abc.py
Normal file
14
src/py_to_uxf_core/abc/implementation_scanner_abc.py
Normal 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
|
@ -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
|
||||||
|
22
src/py_to_uxf_core/model/class_implementation.py
Normal file
22
src/py_to_uxf_core/model/class_implementation.py
Normal 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}'
|
32
src/py_to_uxf_core/service/implementation_scanner_service.py
Normal file
32
src/py_to_uxf_core/service/implementation_scanner_service.py
Normal 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
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user