Added width and height rendering
This commit is contained in:
parent
4b7f0e8231
commit
61b1838c40
@ -1,3 +1,5 @@
|
|||||||
|
import traceback
|
||||||
|
|
||||||
from cpl_core.application import ApplicationABC
|
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
|
||||||
@ -54,13 +56,19 @@ class Application(ApplicationABC):
|
|||||||
|
|
||||||
Console.write_line(f'Input path:', self._path)
|
Console.write_line(f'Input path:', self._path)
|
||||||
Console.write_line(f'Output path:', self._file)
|
Console.write_line(f'Output path:', self._file)
|
||||||
classes: list[PythonClass] = self._parser.parse()
|
xml = ''
|
||||||
# self._console_output(classes)
|
try:
|
||||||
xml = self._umlet_creator.generate_xml(classes)
|
classes: list[PythonClass] = self._parser.parse()
|
||||||
|
Console.write_line(f'Found {len(classes)} classes')
|
||||||
|
# self._console_output(classes)
|
||||||
|
xml = self._umlet_creator.generate_xml(classes)
|
||||||
|
except Exception as e:
|
||||||
|
Console.error('Parsing failed', f'{e} -> {traceback.format_exc()}')
|
||||||
|
exit()
|
||||||
|
|
||||||
if not self._file.endswith('.uxf'):
|
if not self._file.endswith('.uxf'):
|
||||||
Console.error(f'Unexpected file {self._file}')
|
Console.error(f'Unexpected file {self._file}')
|
||||||
return
|
exit()
|
||||||
|
|
||||||
with open(self._file, 'w+') as file:
|
with open(self._file, 'w+') as file:
|
||||||
file.write(xml)
|
file.write(xml)
|
||||||
|
@ -16,11 +16,11 @@ class PythonClass:
|
|||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def functions(self) -> list[PythonFunction]:
|
def functions(self) -> List[PythonFunction]:
|
||||||
return self._functions
|
return self._functions
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def attributes(self) -> list[PythonClassAttribute]:
|
def attributes(self) -> List[PythonClassAttribute]:
|
||||||
return self._attributes
|
return self._attributes
|
||||||
|
|
||||||
def add_function(self, func: PythonFunction):
|
def add_function(self, func: PythonFunction):
|
||||||
|
@ -27,22 +27,43 @@ class UMLClass:
|
|||||||
def position(self) -> Position:
|
def position(self) -> Position:
|
||||||
return self._position
|
return self._position
|
||||||
|
|
||||||
|
@position.setter
|
||||||
|
def position(self, value: int):
|
||||||
|
self._position = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def dimension(self) -> Dimension:
|
def dimension(self) -> Dimension:
|
||||||
return self._dimension
|
return self._dimension
|
||||||
|
|
||||||
|
@dimension.setter
|
||||||
|
def dimension(self, value: int):
|
||||||
|
self._dimension = value
|
||||||
|
|
||||||
def as_xml(self) -> str:
|
def as_xml(self) -> str:
|
||||||
|
px_per_line = 16
|
||||||
|
px_per_char = 2.9
|
||||||
|
self._dimension.height += (self._cls.attributes.count() + self._cls.functions.count()) * px_per_line
|
||||||
|
longest_line_length = self._dimension.width / px_per_char
|
||||||
|
|
||||||
attributes = ''
|
attributes = ''
|
||||||
functions = ''
|
functions = ''
|
||||||
|
|
||||||
if len(self._cls.attributes) > 0:
|
if len(self._cls.attributes) > 0:
|
||||||
for atr in self._cls.attributes:
|
for atr in self._cls.attributes:
|
||||||
attributes += f'{atr.access_modifier.value}{atr.name}: {atr.type}\n'
|
attribute = f'{atr.access_modifier.value}{atr.name}: {atr.type}\n'
|
||||||
|
if len(attribute) > longest_line_length:
|
||||||
|
longest_line_length = len(attribute)
|
||||||
|
attributes += attribute
|
||||||
|
|
||||||
if len(self._cls.functions) > 0:
|
if len(self._cls.functions) > 0:
|
||||||
for func in self._cls.functions:
|
for func in self._cls.functions:
|
||||||
args = ''
|
args = ''
|
||||||
functions += f'{func.access_modifier.value}{func.name}({args}): {func.return_type}\n'
|
function = f'{func.access_modifier.value}{func.name}({args}): {func.return_type}\n'
|
||||||
|
if len(function) > longest_line_length:
|
||||||
|
longest_line_length = len(function)
|
||||||
|
functions += function
|
||||||
|
|
||||||
|
self._dimension.width = round(longest_line_length * px_per_char * px_per_char)
|
||||||
|
|
||||||
return f"""\
|
return f"""\
|
||||||
<element>
|
<element>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from cpl_core.console import Console
|
||||||
from cpl_query.extension import List
|
from cpl_query.extension import List
|
||||||
|
|
||||||
from py_to_uxf_core.abc.function_scanner_abc import FunctionScannerABC
|
from py_to_uxf_core.abc.function_scanner_abc import FunctionScannerABC
|
||||||
@ -20,47 +21,48 @@ class FunctionScannerService(FunctionScannerABC):
|
|||||||
# async def xy(x: int, y: int) -> int:
|
# async def xy(x: int, y: int) -> int:
|
||||||
# async def _xy(x: int, y: int) -> int:
|
# async def _xy(x: int, y: int) -> int:
|
||||||
# async def __xy(x: int, y: int) -> int:
|
# async def __xy(x: int, y: int) -> int:
|
||||||
if line.startswith('def') or line.startswith('async def'):
|
if not line.startswith('def ') and not line.startswith('async def '):
|
||||||
line = line.replace('\t', '')
|
return None
|
||||||
# name
|
|
||||||
name = line.split('def ')[1]
|
line = line.replace('\t', '')
|
||||||
name = name.split('(')[0]
|
# name
|
||||||
|
name = line.split('def ')[1]
|
||||||
|
name = name.split('(')[0]
|
||||||
|
access_modifier = AccessModifierEnum.public
|
||||||
|
args = List()
|
||||||
|
return_type = 'None'
|
||||||
|
|
||||||
|
# access_modifier
|
||||||
|
if name == '__init__' or name == '__repr__' or name == '__str__':
|
||||||
access_modifier = AccessModifierEnum.public
|
access_modifier = AccessModifierEnum.public
|
||||||
args = List()
|
elif name.startswith('_'):
|
||||||
return_type = 'None'
|
access_modifier = AccessModifierEnum.protected
|
||||||
|
elif name.startswith('__'):
|
||||||
|
access_modifier = AccessModifierEnum.private
|
||||||
|
|
||||||
# access_modifier
|
# args
|
||||||
if name == '__init__' or name == '__repr__' or name == '__str__':
|
args_str = line.split('(')[1]
|
||||||
access_modifier = AccessModifierEnum.public
|
args_str = args_str.split(')')[0]
|
||||||
elif name.startswith('_'):
|
# multiple arguments
|
||||||
access_modifier = AccessModifierEnum.protected
|
if ',' in args_str:
|
||||||
elif name.startswith('__'):
|
for argument in args_str.split(','):
|
||||||
access_modifier = AccessModifierEnum.private
|
# with type
|
||||||
|
type_str = 'any'
|
||||||
|
arg_name = argument
|
||||||
|
if ':' in argument:
|
||||||
|
type_str = argument.split(': ')[1]
|
||||||
|
arg_name = argument.split(': ')[0]
|
||||||
|
# without type
|
||||||
|
if arg_name.startswith(' '):
|
||||||
|
arg_name = arg_name.split(' ')[1]
|
||||||
|
args.append(PythonFunctionArgument(arg_name, type_str))
|
||||||
|
# single argument
|
||||||
|
elif args_str != '':
|
||||||
|
pass
|
||||||
|
|
||||||
# args
|
# return_type
|
||||||
args_str = line.split('(')[1]
|
if '->' in line:
|
||||||
args_str = args_str.split(')')[0]
|
return_type_str = line.split('-> ')[1]
|
||||||
# multiple arguments
|
return_type = return_type_str.split(':')[0]
|
||||||
if ',' in args_str:
|
|
||||||
for argument in args_str.split(','):
|
|
||||||
# with type
|
|
||||||
type_str = 'any'
|
|
||||||
arg_name = argument
|
|
||||||
if ':' in argument:
|
|
||||||
type_str = argument.split(': ')[1]
|
|
||||||
arg_name = argument.split(': ')[0]
|
|
||||||
# without type
|
|
||||||
if arg_name.startswith(' '):
|
|
||||||
arg_name = arg_name.split(' ')[1]
|
|
||||||
args.append(PythonFunctionArgument(arg_name, type_str))
|
|
||||||
# single argument
|
|
||||||
elif args_str != '':
|
|
||||||
pass
|
|
||||||
|
|
||||||
# return_type
|
return PythonFunction(access_modifier, name, args, return_type)
|
||||||
if '->' in line:
|
|
||||||
return_type_str = line.split('-> ')[1]
|
|
||||||
return_type = return_type_str.split(':')[0]
|
|
||||||
|
|
||||||
return PythonFunction(access_modifier, name, args, return_type)
|
|
||||||
return None
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import traceback
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from cpl_core.console import Console
|
from cpl_core.console import Console
|
||||||
@ -35,53 +36,60 @@ class PythonParserService(PythonParserABC):
|
|||||||
is_function = False
|
is_function = False
|
||||||
with open(file, 'r') as file_content:
|
with open(file, 'r') as file_content:
|
||||||
cls: Optional[PythonClass] = None
|
cls: Optional[PythonClass] = None
|
||||||
for line in file_content.readlines():
|
lines = file_content.readlines()
|
||||||
line_with_tabs = line
|
|
||||||
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 == '':
|
for i in range(len(lines)):
|
||||||
if is_function:
|
try:
|
||||||
is_function = False
|
line = lines[i]
|
||||||
continue
|
line_with_tabs = line
|
||||||
|
line = line.replace(' ', '')
|
||||||
|
line = line.replace('\t', '')
|
||||||
|
# replace line break at the end of line
|
||||||
|
if line.endswith('\n'):
|
||||||
|
line = line.replace('\n', '')
|
||||||
|
|
||||||
# one line comments
|
if line == '\n' or line == '':
|
||||||
if line != '"""' and line.startswith('"""') and line.endswith('"""') or line.startswith('#'):
|
if is_function:
|
||||||
continue
|
is_function = False
|
||||||
|
continue
|
||||||
|
|
||||||
# start multi line comment
|
# one line comments
|
||||||
if line.startswith('"""') or line.count('"""') == 1 and not is_comment:
|
if line != '"""' and line.startswith('"""') and line.endswith('"""') or line.startswith('#'):
|
||||||
is_comment = True
|
continue
|
||||||
continue
|
|
||||||
|
|
||||||
# end multi line comment
|
# start multi line comment
|
||||||
if line.startswith('"""') or line.endswith('"""') or line.count('"""') == 1 and is_comment:
|
if line.startswith('"""') or line.count('"""') == 1 and not is_comment:
|
||||||
is_comment = False
|
is_comment = True
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if is_comment:
|
# end multi line comment
|
||||||
continue
|
if line.startswith('"""') or line.endswith('"""') or line.count('"""') == 1 and is_comment:
|
||||||
|
is_comment = False
|
||||||
|
continue
|
||||||
|
|
||||||
if cls is None:
|
if is_comment:
|
||||||
cls = self._class_scanner.scan_line_for_classes(line)
|
continue
|
||||||
if cls is not None:
|
|
||||||
classes.append(cls)
|
|
||||||
continue
|
|
||||||
|
|
||||||
func = self._function_scanner.scan_line_for_function(line)
|
if cls is None:
|
||||||
if func is not None:
|
cls = self._class_scanner.scan_line_for_classes(line)
|
||||||
cls.add_function(func)
|
if cls is not None:
|
||||||
is_function = True if func.name != '__init__' else False
|
classes.append(cls)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if len(line_with_tabs.split(' ')) > 3 or is_function:
|
func = self._function_scanner.scan_line_for_function(line)
|
||||||
continue
|
if func is not None:
|
||||||
|
cls.add_function(func)
|
||||||
|
is_function = True if func.name != '__init__' else False
|
||||||
|
continue
|
||||||
|
|
||||||
attribute = self._attribute_scanner.scan_line_for_attribute(line)
|
if len(line_with_tabs.split(' ')) > 3 or is_function:
|
||||||
if attribute is not None:
|
continue
|
||||||
cls.add_attribute(attribute)
|
|
||||||
|
attribute = self._attribute_scanner.scan_line_for_attribute(line)
|
||||||
|
if attribute is not None:
|
||||||
|
cls.add_attribute(attribute)
|
||||||
|
except Exception as e:
|
||||||
|
Console.error(f'Parsing {file}@{i}', f'{e} -> {traceback.format_exc()}')
|
||||||
|
exit()
|
||||||
|
|
||||||
return classes
|
return classes
|
||||||
|
@ -16,14 +16,15 @@ class UmletCreatorService(UmletCreatorABC):
|
|||||||
|
|
||||||
def generate_xml(self, classes: list[PythonClass]) -> str:
|
def generate_xml(self, classes: list[PythonClass]) -> str:
|
||||||
xml_cls = ''
|
xml_cls = ''
|
||||||
width = 400
|
default_width = 80
|
||||||
height = 300
|
default_height = 80
|
||||||
next_x = 10
|
next_x = 10
|
||||||
|
|
||||||
for cls in classes:
|
for cls in classes:
|
||||||
uml_cls = UMLClass(cls, Position(next_x, 10), Dimension(width, height))
|
uml_cls = UMLClass(cls, Position(next_x, 10), Dimension(default_width, default_height))
|
||||||
|
# save class xml
|
||||||
xml_cls += uml_cls.as_xml()
|
xml_cls += uml_cls.as_xml()
|
||||||
next_x += width + 10
|
next_x += round(uml_cls.dimension.width, -1) + 10
|
||||||
|
|
||||||
return f"""\
|
return f"""\
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
Loading…
Reference in New Issue
Block a user