def __drawEllipseForDiagonalInheritanceLines(self, diagram: ImageDiagram): # imgDraw: ImageDraw = diagram._imgDraw eDef: EllipseDefinition = EllipseDefinition() pos: Position = Position(ELLIPSE_X, ELLIPSE_Y) size: Size = Size(width=ELLIPSE_WIDTH, height=ELLIPSE_HEIGHT) eDef.position = pos eDef.size = size diagram.drawEllipse(eDef) diagram.drawRectangle(eDef)
def testBasicMethod(self): baseName: str = f'{TestConstants.TEST_FILE_NAME}-BasicMethod' fileName: str = f'{baseName}.{ImageFormat.PNG.value}' diagram: ImageDiagram = ImageDiagram(fileName=f'{fileName}') position: Position = Position(107, 30) size: Size = Size(width=266, height=100) car: ClassDefinition = ClassDefinition(name='Car', position=position, size=size) initMethodDef: MethodDefinition = MethodDefinition( name='__init__', visibility=DefinitionType.Public) initParam: ParameterDefinition = ParameterDefinition( name='make', parameterType='str', defaultValue='') initMethodDef.parameters = [initParam] car.methods = [initMethodDef] diagram.drawClass(car) diagram.write() self._assertIdenticalFiles( baseName=baseName, generatedFileName=fileName, failMessage='Basic Method image file should be identical')
def testMethodParametersDisplay(self): toClassDefinition: ToClassDefinition = self._buildDisplayMethodParametersTest( ) baseName: str = f'{TestConstants.TEST_FILE_NAME}-MethodParametersDisplay' fileName: str = f'{baseName}.{ImageFormat.PNG.value}' diagram: ImageDiagram = ImageDiagram(fileName=fileName) classDefinitions: ClassDefinitions = toClassDefinition.classDefinitions for testClass in classDefinitions: diagram.drawClass(classDefinition=testClass) testLineDefinitions: UmlLineDefinitions = toClassDefinition.umlLineDefinitions for testLine in testLineDefinitions: diagram.drawUmlLine(testLine) diagram.write() self._assertIdenticalFiles( baseName=baseName, generatedFileName=fileName, failMessage='MethodParametersDisplay image file should be identical' )
def testBasicFields(self): baseName: str = f'{TestConstants.TEST_FILE_NAME}-BasicFields' fileName: str = f'{baseName}.{ImageFormat.PNG.value}' diagram: ImageDiagram = ImageDiagram(fileName=fileName) fieldsTestClass: ClassDefinition = ClassDefinition( name='FieldsTestClass', position=Position(226, 102), size=Size(height=156, width=230)) fieldsTestClass.fields = self._buildFields() initMethodDef: MethodDefinition = MethodDefinition( name='__init__', visibility=DefinitionType.Public) fieldsTestClass.methods = [initMethodDef] diagram.drawClass(classDefinition=fieldsTestClass) diagram.write() self._assertIdenticalFiles( baseName=baseName, generatedFileName=fileName, failMessage='Basic Fields image file should be identical')
def __init__(self, imageOptions: ImageOptions, dpi: int = 0, pyutVersion: str = '', pluginVersion: str = ''): """ Args: imageOptions: Lots of information on how to draw the diagram dpi: Dots per inch; Only used in PDF generation; Image generation is in pixels pyutVersion: Information for header pluginVersion: Information for header """ self.logger: Logger = getLogger(__name__) self._classDefinitions: ClassDefinitions = [] self._umlLineDefinitions: UmlLineDefinitions = [] today: str = strftime("%d %b %Y %H:%M:%S", localtime()) headerText: str = f'Pyut Version {pyutVersion} Plugin Version {pluginVersion} - {today}' fqFileName: str = imageOptions.outputFileName imageFormat: ImageFormat = imageOptions.imageFormat if imageFormat == ImageFormat.PDF: self._diagram: PdfDiagram = PdfDiagram(fileName=fqFileName, dpi=dpi, headerText=headerText) else: self._diagram: ImageDiagram = ImageDiagram(fileName=fqFileName, headerText=headerText # TODO use image size from new method signature )
def testSophisticatedLayout(self): baseName: str = f'{TestConstants.TEST_FILE_NAME}-SophisticatedLayout' fileName: str = f'{baseName}.{ImageFormat.PNG.value}' diagram: ImageDiagram = ImageDiagram(fileName=f'{fileName}') classDefinitions: ClassDefinitions = [ self._buildCar(), self._buildCat(), self._buildOpie(), self._buildNameTestCase(), self._buildElectricCar() ] for classDefinition in classDefinitions: classDefinition = cast(ClassDefinition, classDefinition) diagram.drawClass(classDefinition=classDefinition) lineDefinitions: UmlLineDefinitions = self._buildSophisticatedLineDefinitions( ) for lineDefinition in lineDefinitions: diagram.drawUmlLine(lineDefinition=lineDefinition) diagram.write() self._assertIdenticalFiles( baseName=baseName, generatedFileName=fileName, failMessage='Sophisticated Layout image file should be identical')
def testFillPage(self): baseName: str = f'{TestConstants.TEST_FILE_NAME}-FillPage' fileName: str = f'{baseName}.{ImageFormat.PNG.value}' diagram: ImageDiagram = ImageDiagram(fileName=f'{fileName}') widthInterval: int = TestImageDiagram.CELL_WIDTH // 10 heightInterval: int = TestImageDiagram.CELL_HEIGHT // 10 for x in range(0, TestImageDiagram.TEST_LAST_X_POSITION): scrX: int = (x * TestImageDiagram.CELL_WIDTH) + (widthInterval * x) for y in range(0, TestImageDiagram.TEST_LAST_Y_POSITION): scrY: int = (y * TestImageDiagram.CELL_HEIGHT) + ( y * heightInterval) classDef: ClassDefinition = ClassDefinition( name=f'{TestImageDiagram.BASE_TEST_CLASS_NAME}{x}{y}', position=Position(scrX, scrY), size=Size(width=TestImageDiagram.CELL_WIDTH, height=TestImageDiagram.CELL_HEIGHT)) diagram.drawClass(classDef) diagram.write() self._assertIdenticalFiles( baseName=baseName, generatedFileName=fileName, failMessage='Fill Page image file should be identical')
def testMinimalInheritance(self): baseName: str = f'{TestConstants.TEST_FILE_NAME}-MinimalInheritance' fileName: str = f'{baseName}.{ImageFormat.PNG.value}' diagram: ImageDiagram = ImageDiagram(fileName=f'{fileName}') cat: ClassDefinition = ClassDefinition(name='Gato', position=Position(536, 19), size=Size(height=74, width=113)) opie: ClassDefinition = ClassDefinition(name='Opie', position=Position(495, 208), size=Size(width=216, height=87)) diagram.drawClass(classDefinition=cat) diagram.drawClass(classDefinition=opie) startPosition: Position = Position(600, 208) endPosition: Position = Position(600, 93) linePositions: LinePositions = [startPosition, endPosition] opieToCat: UmlLineDefinition = UmlLineDefinition( lineType=LineType.Inheritance, linePositions=linePositions) diagram.drawUmlLine(lineDefinition=opieToCat) diagram.write() self._assertIdenticalFiles( baseName=baseName, generatedFileName=fileName, failMessage='Minimal Inheritance image file should be identical')
def testBends(self): baseName: str = f'{TestConstants.TEST_FILE_NAME}-Bends' fileName: str = f'{baseName}.{ImageFormat.PNG.value}' diagram: ImageDiagram = ImageDiagram(fileName=fileName) top: ClassDefinition = self._buildTopClass() left: ClassDefinition = self._buildLeftClass() right: ClassDefinition = self._buildRightClass() bentClasses: List[ClassDefinition] = [top, left, right] for bentClass in bentClasses: diagram.drawClass(classDefinition=bentClass) bentLineDefinitions: UmlLineDefinitions = self._buildBendTest() for bentLine in bentLineDefinitions: diagram.drawUmlLine(bentLine) diagram.write() self._assertIdenticalFiles( baseName=baseName, generatedFileName=fileName, failMessage='Bends image file should be identical')
def testAddSuffixEmbeddedDotsNot(self): diagram: ImageDiagram = ImageDiagram( fileName=TestImageDiagram.DOTTED_EXPECTED_NAME) adjustedName: str = diagram._addSuffix( fileName=TestImageDiagram.DOTTED_EXPECTED_NAME, suffix=TestImageDiagram.EXPECTED_SUFFIX) self.assertEqual(TestImageDiagram.DOTTED_EXPECTED_NAME, adjustedName, 'Suffix incorrectly added for embedded periods')
def testAddSuffix(self): diagram: ImageDiagram = ImageDiagram(fileName='/user/hasii/bogus') adjustedName: str = diagram._addSuffix( fileName=TestImageDiagram.UNADJUSTED_NAME, suffix=TestImageDiagram.EXPECTED_SUFFIX) self.assertEqual(TestImageDiagram.EXPECTED_NAME, adjustedName, 'Suffix not added correctly')
def testAddSuffixEmbeddedDots(self): diagram: ImageDiagram = ImageDiagram( fileName=TestImageDiagram.DOTTED_UNADJUSTED_NAME) adjustedName: str = diagram._addSuffix( fileName=TestImageDiagram.DOTTED_UNADJUSTED_NAME, suffix=TestImageDiagram.EXPECTED_SUFFIX) self.assertEqual(TestImageDiagram.DOTTED_EXPECTED_NAME, adjustedName, 'Suffix with embedded periods not added correctly')
def testAddSuffixNot(self): diagram: ImageDiagram = ImageDiagram( fileName=TestImageDiagram.EXPECTED_NAME) adjustedName: str = diagram._addSuffix( fileName=TestImageDiagram.EXPECTED_NAME, suffix=TestImageDiagram.EXPECTED_SUFFIX) self.assertEqual(TestImageDiagram.EXPECTED_NAME, adjustedName, 'Suffix incorrectly added')
def testBasicMethods(self): baseName: str = f'{TestConstants.TEST_FILE_NAME}-BasicMethods' fileName: str = f'{baseName}.{ImageFormat.PNG.value}' diagram: ImageDiagram = ImageDiagram(fileName=f'{fileName}') classDef: ClassDefinition = self._buildCar() diagram.drawClass(classDef) diagram.write() self._assertIdenticalFiles( baseName=baseName, generatedFileName=fileName, failMessage='Basic Methods image file should be identical')
def testBasicHeader(self): baseName: str = f'{TestConstants.TEST_FILE_NAME}-BasicHeader' fileName: str = f'{baseName}.{ImageFormat.PNG.value}' diagram: ImageDiagram = ImageDiagram( fileName=f'{fileName}', headerText=TestDiagramParent.UNIT_TEST_HEADER) classDef: ClassDefinition = self._buildCar() diagram.drawClass(classDef) diagram.write() self._assertIdenticalFiles( baseName=baseName, generatedFileName=fileName, failMessage='Basic Header image file should be identical')
def testBasic(self): baseName: str = f'{TestConstants.TEST_FILE_NAME}-Basic' fileName: str = f'{baseName}.{ImageFormat.PNG.value}' diagram: ImageDiagram = ImageDiagram(fileName=f'{fileName}') classDef: ClassDefinition = ClassDefinition( name=TestDiagramParent.BASE_TEST_CLASS_NAME, size=Size(width=266, height=100), position=Position(x=107, y=30)) diagram.drawClass(classDef) diagram.write() self._assertIdenticalFiles( baseName=baseName, generatedFileName=fileName, failMessage='Basic image file should be identical')
def testBigClass(self): toClassDefinition: ToClassDefinition = self._buildBigClassFromXml() baseName: str = f'{TestConstants.TEST_FILE_NAME}-BigClass' fileName: str = f'{baseName}.{ImageFormat.PNG.value}' diagram: ImageDiagram = ImageDiagram(fileName=fileName) classDefinitions: ClassDefinitions = toClassDefinition.classDefinitions for bigClass in classDefinitions: diagram.drawClass(classDefinition=bigClass) diagram.write() self._assertIdenticalFiles( baseName=baseName, generatedFileName=fileName, failMessage='Big Class image file should be identical')
def testOrthogonalInheritanceLines(self): diagram: ImageDiagram = ImageDiagram( fileName= f'{TestConstants.TEST_FILE_NAME}-OrthogonalInheritanceLines.{ImageFormat.PNG.value}' ) self._drawHorizontalBoundaries(diagram) self._drawVerticalBoundaries(diagram) lineDrawer: ImageLine = ImageLine( docWriter=diagram._imgDraw, diagramPadding=diagram._diagramPadding) north, south, east, west = self._createOrthogonalLines( LineType.Inheritance) lineDefinitions: UmlLineDefinitions = [north, south, east, west] for lineDefinition in lineDefinitions: lineDrawer.draw(lineDefinition) diagram.write()
def testDiagonalAggregationLines(self): diagram: ImageDiagram = ImageDiagram( fileName= f'{TestConstants.TEST_FILE_NAME}-DiagonalAggregationLines.{ImageFormat.PNG.value}' ) self.__drawEllipseForDiagonalInheritanceLines(diagram) lineDrawer: ImageLine = ImageLine( docWriter=diagram._imgDraw, diagramPadding=diagram._diagramPadding) northEast, northWest, southEast, southWest = self.__createDiagonalLines( LineType.Aggregation) definitions: UmlLineDefinitions = [ northEast, northWest, southEast, southWest ] for definition in definitions: lineDrawer.draw(definition) diagram.write()
def testSophisticatedHeader(self): today: str = strftime("%d %b %Y %H:%M:%S", self.unitTestTimeStamp.timetuple()) headerText: str = f'{TestDiagramParent.UNIT_TEST_SOPHISTICATED_HEADER} - {today}' baseName: str = f'{TestConstants.TEST_FILE_NAME}-SophisticatedHeader' fileName: str = f'{baseName}.{ImageFormat.PNG.value}' diagram: ImageDiagram = ImageDiagram(fileName=f'{fileName}', headerText=headerText) classDef: ClassDefinition = self._buildCar() diagram.drawClass(classDef) diagram.write() self._assertIdenticalFiles( baseName=baseName, generatedFileName=fileName, failMessage='Sophisticated Header image file should be identical')
def testBendsFromXmlInput(self): toClassDefinition: ToClassDefinition = self._buildBendTestFromXml() baseName: str = f'{TestConstants.TEST_FILE_NAME}-BendsFromXmlInput' fileName: str = f'{baseName}.{ImageFormat.PNG.value}' diagram: ImageDiagram = ImageDiagram(fileName=fileName) classDefinitions: ClassDefinitions = toClassDefinition.classDefinitions for bentClass in classDefinitions: diagram.drawClass(classDefinition=bentClass) bentLineDefinitions: UmlLineDefinitions = toClassDefinition.umlLineDefinitions for bentLine in bentLineDefinitions: diagram.drawUmlLine(bentLine) diagram.write() self._assertIdenticalFiles( baseName=baseName, generatedFileName=fileName, failMessage='BendsFromXmlInput image file should be identical')
class OglToPyUmlDefinition: INHERITANCE_DESTINATION_POSITION_NUDGE_FACTOR: int = 1 def __init__(self, imageOptions: ImageOptions, dpi: int = 0, pyutVersion: str = '', pluginVersion: str = ''): """ Args: imageOptions: Lots of information on how to draw the diagram dpi: Dots per inch; Only used in PDF generation; Image generation is in pixels pyutVersion: Information for header pluginVersion: Information for header """ self.logger: Logger = getLogger(__name__) self._classDefinitions: ClassDefinitions = [] self._umlLineDefinitions: UmlLineDefinitions = [] self._prefs: PyutPreferences = PyutPreferences() today: str = strftime("%d %b %Y %H:%M:%S", localtime()) headerText: str = f'Pyut Version {pyutVersion} Plugin Version {pluginVersion} - {today}' fqFileName: str = imageOptions.outputFileName imageFormat: ImageFormat = imageOptions.imageFormat imageLibShowParameters: DisplayMethodParameters = self.__toImageLibraryEnum( self._prefs.showParameters) if imageFormat == ImageFormat.PDF: self._diagram: BaseDiagram = PdfDiagram( fileName=fqFileName, dpi=dpi, headerText=headerText, docDisplayMethodParameters=imageLibShowParameters) else: self._diagram = ImageDiagram( fileName=fqFileName, headerText=headerText ) # TODO use image size from new method signature) def toClassDefinitions(self, oglObjects: List[OglClass]): classDefinitions: ClassDefinitions = [] for oglObject in oglObjects: umlObject: OglClass = cast(OglClass, oglObject) if not isinstance(umlObject, OglClass): continue pyutClass: PyutClass = cast(PyutClass, umlObject.pyutObject) x, y = umlObject.GetPosition() w, h = umlObject.GetSize() position: Position = Position(x=x, y=y) size: Size = Size(width=int(w), height=int(h)) classDefinition: ClassDefinition = ClassDefinition( name=pyutClass.name, position=position, size=size) if pyutClass.displayParameters is True: classDefinition.displayMethodParameters = DisplayMethodParameters.DISPLAY else: classDefinition.displayMethodParameters = DisplayMethodParameters.DO_NOT_DISPLAY classDefinition = self.__addClassDiagramDisplayPreferences( pyutClass=pyutClass, classDefinition=classDefinition) self._addMethods(classDefinition=classDefinition, pyutClass=pyutClass) self._diagram.drawClass(classDefinition=classDefinition) classDefinitions.append(classDefinition) self._classDefinitions = classDefinitions def layoutLines(self, oglObjects: List[OglClass]): umlLineDefinitions: UmlLineDefinitions = [] for umlObject in oglObjects: if not isinstance(umlObject, OglLink): continue oglLink: OglLink = cast(OglLink, umlObject) pyutLink: PyutLink = oglLink.getPyutObject() umlLinkType: LinkType = pyutLink.linkType lineType: LineType = self._toPyUmlLineType(umlLinkType) linePositions: LinePositions = self._toPyUmlPositions( oglLink, umlLinkType) self.logger.debug(f'{lineType=} {linePositions=}') line: UmlLineDefinition = UmlLineDefinition( lineType=lineType, linePositions=linePositions) self._diagram.drawUmlLine(lineDefinition=line) umlLineDefinitions.append(line) self._umlLineDefinitions = umlLineDefinitions def write(self): self._diagram.write() def _toPyUmlLineType(self, umlLinkType) -> LineType: if umlLinkType == LinkType.INHERITANCE: lineType: LineType = LineType.Inheritance elif umlLinkType == LinkType.COMPOSITION: lineType = LineType.Composition elif umlLinkType == LinkType.AGGREGATION: lineType = LineType.Aggregation else: lineType = LineType.Association # This won't happen yet return lineType def _toPyUmlPositions(self, oglLink, pyutLinkType: LinkType) -> LinePositions: if pyutLinkType == LinkType.INHERITANCE: srcAnchor: AnchorPoint = oglLink.sourceAnchor destAnchor: AnchorPoint = oglLink.destinationAnchor else: srcAnchor = oglLink.destinationAnchor destAnchor = oglLink.sourceAnchor srcX, srcY = srcAnchor.GetPosition() destX, destY = destAnchor.GetPosition() sourcePosition: Position = Position(x=srcX, y=srcY) destinationPosition: Position = Position(x=destX, y=destY) bends: List[ControlPoint] = oglLink.GetControlPoints() if bends is None or len(bends) == 0: linePositions: LinePositions = [ sourcePosition, destinationPosition ] else: linePositions = [sourcePosition] for cp in bends: bend: ControlPoint = cast(ControlPoint, cp) self.logger.debug(f'{bend:}') bendX, bendY = bend.GetPosition() bendPosition: Position = Position(x=bendX, y=bendY) linePositions.append(bendPosition) linePositions.append(destinationPosition) return linePositions def _addMethods(self, classDefinition: ClassDefinition, pyutClass: PyutClass) -> ClassDefinition: methods: Methods = [] for method in pyutClass.methods: pyutMethod: PyutMethod = cast(PyutMethod, method) methodDef: MethodDefinition = MethodDefinition( name=pyutMethod.name) methodDef.visibility = self.__toDefinitionType( pyutMethod.visibility) methodDef.returnType = pyutMethod.returnType.value self.__addParameters(methodDefinition=methodDef, pyutMethod=pyutMethod) methods.append(methodDef) classDefinition.methods = methods return classDefinition def __addParameters(self, methodDefinition: MethodDefinition, pyutMethod: PyutMethod) -> MethodDefinition: parameters: Parameters = [] for parameter in pyutMethod.parameters: paramDef: ParameterDefinition = ParameterDefinition( name=parameter.name) paramDef.parameterType = parameter.type.value paramDef.defaultValue = parameter.defaultValue parameters.append(paramDef) methodDefinition.parameters = parameters self.logger.debug(f'{methodDefinition.name=} {parameters=}') return methodDefinition def __toDefinitionType(self, visibility: PyutVisibilityEnum) -> DefinitionType: if visibility == PyutVisibilityEnum.PUBLIC: return DefinitionType.Public def __addClassDiagramDisplayPreferences( self, pyutClass: PyutClass, classDefinition: ClassDefinition) -> ClassDefinition: classDefinition.displayMethods = pyutClass.showMethods classDefinition.displayFields = pyutClass.showFields return classDefinition def __toImageLibraryEnum(self, showParameters: bool) -> DisplayMethodParameters: if showParameters is True: return DisplayMethodParameters.DISPLAY else: return DisplayMethodParameters.DO_NOT_DISPLAY