diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 860399e..22e40d1 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,50 +1,33 @@
repos:
-- repo: https://github.com/psf/black
- rev: 23.12.1
- hooks:
- - id: black
- args: [--safe, --quiet]
-- repo: https://github.com/asottile/blacken-docs
- rev: 1.16.0
- hooks:
- - id: blacken-docs
- additional_dependencies: [black==23.1.0]
+- repo: https://github.com/PyCQA/autoflake
+ rev: v2.3.0
+ hooks:
+ - id: autoflake
+ name: autoflake
+ entry: autoflake --in-place --remove-all-unused-imports
+ language: python
+ files: \.py$
+- repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: "v0.2.2"
+ hooks:
+ - id: ruff-format
- repo: https://github.com/pre-commit/mirrors-prettier
rev: "v4.0.0-alpha.8"
hooks:
- - id: prettier
- types_or: [css, javascript]
-- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.5.0
- hooks:
- - id: trailing-whitespace
- - id: end-of-file-fixer
- - id: debug-statements
-- repo: https://github.com/PyCQA/autoflake
- rev: v2.2.1
- hooks:
- - id: autoflake
- name: autoflake
- entry: autoflake --in-place --remove-all-unused-imports
- language: python
- files: \.py$
-- repo: https://github.com/asottile/reorder-python-imports
- rev: v3.12.0
- hooks:
- - id: reorder-python-imports
- args: ['--application-directories=.:src', --py36-plus]
-- repo: local
- hooks:
- - id: rst
- name: rst
- entry: rst-lint --encoding utf-8
- files: ^(HISTORY.rst|README.rst)$
- language: python
- additional_dependencies: [pygments, restructuredtext_lint]
-- repo: https://github.com/pre-commit/mirrors-mypy
- rev: v1.8.0
- hooks:
- - id: mypy
- files: ^(src/|tests/)
- args: []
- additional_dependencies: [types-attrs]
+ - id: prettier
+ types_or: [css, javascript]
+- repo: local
+ hooks:
+ - id: rst
+ name: rst
+ entry: rst-lint --encoding utf-8
+ files: ^(HISTORY.rst|README.rst)$
+ language: python
+ additional_dependencies: [pygments, restructuredtext_lint]
+- repo: https://github.com/pre-commit/mirrors-mypy
+ rev: v1.8.0
+ hooks:
+ - id: mypy
+ files: ^(src/|tests/)
+ args: []
+ additional_dependencies: [types-attrs]
diff --git a/docs/conf.py b/docs/conf.py
index e225b25..6e470a0 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -16,5 +16,5 @@
"sphinx.ext.autosummary",
]
-autodoc_default_flags = ['members']
+autodoc_default_flags = ["members"]
autosummary_generate = True
diff --git a/examples/drag_and_drop/main.py b/examples/drag_and_drop/main.py
index 1ab7955..f85f0b4 100644
--- a/examples/drag_and_drop/main.py
+++ b/examples/drag_and_drop/main.py
@@ -22,7 +22,7 @@ def create_drag_button(text, qmx_style, parent=None):
button.setText(text)
# # You can set an icon to the button with:
# button.setIcon(...)
- button.setProperty('qmx_style', qmx_style)
+ button.setProperty("qmx_style", qmx_style)
button.setToolTip("Drag me into the graph widget")
return button
@@ -35,14 +35,14 @@ class DragButton(QPushButton):
def mousePressEvent(self, event):
mime_data = qmxgraph.mime.create_qt_mime_data(
{
- 'vertices': [
+ "vertices": [
{
- 'dx': 0,
- 'dy': 0,
- 'width': 120,
- 'height': 40,
- 'label': self.text(),
- 'style': self.property('qmx_style'),
+ "dx": 0,
+ "dy": 0,
+ "width": 120,
+ "height": 40,
+ "label": self.text(),
+ "style": self.property("qmx_style"),
}
]
}
@@ -63,7 +63,7 @@ class DragAndDropWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
- self.setProperty('name', 'adas')
+ self.setProperty("name", "adas")
self.setMinimumSize(QSize(640, 480))
self.setWindowTitle("Drag&Drop Styles")
@@ -72,9 +72,9 @@ def __init__(self):
self.button_pane = QWidget(self)
self.button_pane.setEnabled(False)
- red_button = create_drag_button('RED', 'fillColor=#D88', self.button_pane)
- green_button = create_drag_button('GREEN', 'fillColor=#8D8', self.button_pane)
- blue_button = create_drag_button('BLUE', 'fillColor=#88D', self.button_pane)
+ red_button = create_drag_button("RED", "fillColor=#D88", self.button_pane)
+ green_button = create_drag_button("GREEN", "fillColor=#8D8", self.button_pane)
+ blue_button = create_drag_button("BLUE", "fillColor=#88D", self.button_pane)
self.graph_widget = QmxGraph(parent=central_widget)
self.events_bridge = self.create_events_bridge()
@@ -96,23 +96,23 @@ def create_events_bridge(self):
# Based in `EventsBridge` docstring.
def on_cells_added_handler(cell_ids):
- print(f'added {cell_ids}')
+ print(f"added {cell_ids}")
qmx = widget.api
for cid in cell_ids:
label = qmx.get_label(cid)
- qmx.set_label(cid, f'{label} ({cid})')
+ qmx.set_label(cid, f"{label} ({cid})")
def on_terminal_changed_handler(cell_id, terminal_type, new_terminal_id, old_terminal_id):
print(
- f'{terminal_type} of {cell_id} changed from'
- f' {old_terminal_id} to {new_terminal_id}'
+ f"{terminal_type} of {cell_id} changed from"
+ f" {old_terminal_id} to {new_terminal_id}"
)
def on_cells_removed_handler(cell_ids):
- print(f'removed {cell_ids}')
+ print(f"removed {cell_ids}")
def on_cells_bounds_changed_handler(changed_cell_bounds):
- print(f'cells bounds changed {changed_cell_bounds}')
+ print(f"cells bounds changed {changed_cell_bounds}")
widget = self.graph_widget
events_bridge = widget.events_bridge
diff --git a/examples/styles/main.py b/examples/styles/main.py
index a8861f4..c7e7a6b 100644
--- a/examples/styles/main.py
+++ b/examples/styles/main.py
@@ -19,16 +19,16 @@ def __init__(self):
self.setWindowTitle("Qmx Styles")
styles_cfg = {
- 'round_node': {
- 'shape': 'ellipse',
- 'fill_color': '#D88',
- 'vertical_label_position': 'bottom',
- 'vertical_align': 'top',
+ "round_node": {
+ "shape": "ellipse",
+ "fill_color": "#D88",
+ "vertical_label_position": "bottom",
+ "vertical_align": "top",
},
- 'bold_edge': {
- 'end_arrow': 'classic',
- 'shape': 'connector',
- 'stroke_width': 5.0,
+ "bold_edge": {
+ "end_arrow": "classic",
+ "shape": "connector",
+ "stroke_width": 5.0,
},
}
@@ -48,7 +48,7 @@ def graph_load_handler(self, is_loaded):
width=100,
height=50,
label="BBB",
- style='round_node',
+ style="round_node",
)
# Style by explicit values.
v2_id = qmx.insert_vertex(
@@ -57,11 +57,11 @@ def graph_load_handler(self, is_loaded):
width=50,
height=100,
label="CCC",
- style='fillColor=#8D8',
+ style="fillColor=#8D8",
)
- qmx.insert_edge(source_id=v0_id, target_id=v1_id, label='normal')
- qmx.insert_edge(source_id=v1_id, target_id=v2_id, label='bold', style='bold_edge')
+ qmx.insert_edge(source_id=v0_id, target_id=v1_id, label="normal")
+ qmx.insert_edge(source_id=v1_id, target_id=v2_id, label="bold", style="bold_edge")
if __name__ == "__main__":
diff --git a/pyproject.toml b/pyproject.toml
index 10572da..8efe2d9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,3 +1,17 @@
-[tool.black]
+[build-system]
+build-backend = "setuptools.build_meta"
+requires = [
+ "setuptools",
+ "setuptools-scm",
+]
+
+
+[tool.ruff]
+src = ["src"]
line-length = 100
-skip-string-normalization = true
+
+[tool.ruff.format]
+docstring-code-format = true
+
+[tool.ruff.lint.isort]
+force-single-line = true
diff --git a/scripts/svg_to_stencil.py b/scripts/svg_to_stencil.py
index 49aef10..226f66b 100644
--- a/scripts/svg_to_stencil.py
+++ b/scripts/svg_to_stencil.py
@@ -50,36 +50,36 @@ def __init__(self, svg_path):
self.svg_path = svg_path
def read(self):
- ident = ' ' * 4
+ ident = " " * 4
tree = xml.etree.ElementTree.parse(self.svg_path)
root = tree.getroot()
ns = {
- 'default': "http://www.w3.org/2000/svg",
- 'sodipodi': "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd",
- 'inkscape': "http://www.inkscape.org/namespaces/inkscape",
+ "default": "http://www.w3.org/2000/svg",
+ "sodipodi": "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd",
+ "inkscape": "http://www.inkscape.org/namespaces/inkscape",
}
- sodipodi_docname = '{{{}}}docname'.format(ns['sodipodi'])
+ sodipodi_docname = "{{{}}}docname".format(ns["sodipodi"])
if sodipodi_docname in root.attrib:
- name = root.attrib[sodipodi_docname].replace('.svg', '')
+ name = root.attrib[sodipodi_docname].replace(".svg", "")
else:
- name = os.path.basename(self.svg_path).replace('.svg', '')
- width = root.attrib['width'].replace('px', '')
- height = root.attrib['height'].replace('px', '')
+ name = os.path.basename(self.svg_path).replace(".svg", "")
+ width = root.attrib["width"].replace("px", "")
+ height = root.attrib["height"].replace("px", "")
- default_ns = '{{{}}}'.format(ns['default'])
+ default_ns = "{{{}}}".format(ns["default"])
svg_elements = (c for c in root if c.tag.startswith(default_ns))
drawing_cmds = []
for svg_element in svg_elements:
- tag = svg_element.tag.replace(default_ns, '')
+ tag = svg_element.tag.replace(default_ns, "")
parser = None
- if tag == 'path':
+ if tag == "path":
parser = PathParser(ident)
- elif tag == 'polygon':
+ elif tag == "polygon":
parser = PolygonParser(ident)
- elif tag == 'rect':
+ elif tag == "rect":
parser = RectParser(ident)
if parser is not None:
@@ -93,19 +93,19 @@ def read(self):
name=name,
width=width,
height=height,
- drawing='\n'.join(
- '{}{}'.format(ident * 2, c) for c in itertools.chain.from_iterable(drawing_cmds)
+ drawing="\n".join(
+ "{}{}".format(ident * 2, c) for c in itertools.chain.from_iterable(drawing_cmds)
),
)
def _parse_size(self, value, unit):
- return value.replace(unit, '')
+ return value.replace(unit, "")
class DrawingParser:
__metaclass__ = abc.ABCMeta
- def __init__(self, ident=''):
+ def __init__(self, ident=""):
self.ident = ident
self.cmds = []
self.styles = {}
@@ -124,16 +124,16 @@ def _add_style_commands(self, value):
added = self.styles
tag_map = {
- 'fill': ('fillcolor', 'color'),
- 'stroke': ('strokecolor', 'color'),
- 'stroke-width': ('strokewidth', 'width'),
- 'stroke-miterlimit': ('miterlimit', 'limit'),
+ "fill": ("fillcolor", "color"),
+ "stroke": ("strokecolor", "color"),
+ "stroke-width": ("strokewidth", "width"),
+ "stroke-miterlimit": ("miterlimit", "limit"),
}
- if 'style' in value.attrib:
- style = value.attrib['style']
- for style_attr in style.split(';'):
- style_tag, style_value = style_attr.split(':')
+ if "style" in value.attrib:
+ style = value.attrib["style"]
+ for style_attr in style.split(";"):
+ style_tag, style_value = style_attr.split(":")
if style_tag in tag_map:
el_name, attr = tag_map[style_tag]
@@ -147,18 +147,18 @@ def _add_style_commands(self, value):
added[style_tag] = self._add_if_not_none(el_name, attr, value.attrib[style_tag])
def _add_fill_stroke_command(self):
- has_stroke = self.styles.get('stroke')
- has_fill = self.styles.get('fill')
+ has_stroke = self.styles.get("stroke")
+ has_fill = self.styles.get("fill")
if has_fill and has_stroke:
- self.cmds.append('')
+ self.cmds.append("")
elif has_fill:
- self.cmds.append('')
+ self.cmds.append("")
elif has_stroke:
- self.cmds.append('')
+ self.cmds.append("")
def _add_if_not_none(self, el_name, attr, value):
added = False
- if value != 'none':
+ if value != "none":
self.cmds.append('<{} {}="{}"/>'.format(el_name, attr, value))
added = True
return added
@@ -174,18 +174,18 @@ def _add_drawing_commands(self, value):
# * for each subsequent coordinate pair, perform an absolute `lineto`
# operation to that coordinate pair
# * perform a `closepath` command
- points = value.attrib['points']
+ points = value.attrib["points"]
pos = 0
- self.cmds.append('')
- m = re.match(r'(\d+(?:\.\d+)?),(\d+(?:\.\d+)?) +', points[pos:])
+ self.cmds.append("")
+ m = re.match(r"(\d+(?:\.\d+)?),(\d+(?:\.\d+)?) +", points[pos:])
x0 = m.group(1)
y0 = m.group(2)
self.cmds.append('{}'.format(self.ident, x0, y0))
pos += len(m.group(0))
while True:
- m = re.match(r'(\d+(?:\.\d+)?),(\d+(?:\.\d+)?) +', points[pos:])
+ m = re.match(r"(\d+(?:\.\d+)?),(\d+(?:\.\d+)?) +", points[pos:])
if m is None:
break
@@ -194,12 +194,12 @@ def _add_drawing_commands(self, value):
# Close polygon
self.cmds.append('{}'.format(self.ident, x0, y0))
- self.cmds.append('')
+ self.cmds.append("")
class PathParser(DrawingParser):
def _add_drawing_commands(self, value):
- drawing = value.attrib['d']
+ drawing = value.attrib["d"]
state = self.wait_command_state
pos = 0
@@ -207,23 +207,23 @@ def _add_drawing_commands(self, value):
while state is not None:
state, pos = state(drawing, pos)
- self.cmds.insert(cmds_offset, '')
- self.cmds.append('')
+ self.cmds.insert(cmds_offset, "")
+ self.cmds.append("")
def wait_command_state(self, value, pos):
if pos >= len(value):
return None, pos
- elif value[pos] == 'M':
+ elif value[pos] == "M":
return self.move_state, pos + 1
- elif value[pos] == 'C':
+ elif value[pos] == "C":
return self.curve_state, pos + 1
- elif value[pos] == ' ':
+ elif value[pos] == " ":
return self.wait_command_state, pos + 1
raise ValueError("Could not parse {}".format(value[pos]))
def move_state(self, value, pos):
- m = re.match(r' +(\d+(\.\d+)?),(\d+(\.\d+)?) +', value[pos:])
+ m = re.match(r" +(\d+(\.\d+)?),(\d+(\.\d+)?) +", value[pos:])
if m is None:
raise ValueError("Could not parse {}".format(value[pos]))
@@ -233,22 +233,22 @@ def move_state(self, value, pos):
def curve_state(self, svg, pos):
index = 1
- cmd = ''
+ cmd = ""
while True:
- m = re.match(r' *(\d+(\.\d+)?),(\d+(\.\d+)?) *(Z)?', svg[pos:])
+ m = re.match(r" *(\d+(\.\d+)?),(\d+(\.\d+)?) *(Z)?", svg[pos:])
if m is None:
raise ValueError("Could not parse {}".format(svg[pos]))
pos += len(m.group(0))
if index == 1:
- cmd = '{} 3:
index = 1
- cmd += '/>'
+ cmd += "/>"
self.cmds.append(cmd)
if m.group(5) is not None:
@@ -262,20 +262,20 @@ def curve_state(self, svg, pos):
class RectParser(DrawingParser):
def _add_drawing_commands(self, value):
svg_to_stencil_attr_map = {
- 'x': 'x',
- 'y': 'y',
- 'width': 'w',
- 'height': 'h',
+ "x": "x",
+ "y": "y",
+ "width": "w",
+ "height": "h",
}
- rect_stencil_tag = ''
+ rect_stencil_tag += "/>"
self.cmds.append(rect_stencil_tag)
-_SHAPE_TEMPLATE = '''\
+_SHAPE_TEMPLATE = """\
@@ -293,20 +293,20 @@ def _add_drawing_commands(self, value):
-'''
+"""
-if __name__ == '__main__':
+if __name__ == "__main__":
import argparse
arg_parser = argparse.ArgumentParser(
- description='Converts a SVG file to a stencil file ' 'compatible with mxGraph.'
+ description="Converts a SVG file to a stencil file " "compatible with mxGraph."
)
arg_parser.add_argument(
- 'svg',
- metavar='SVG_FILE',
+ "svg",
+ metavar="SVG_FILE",
nargs=1,
- help='A SVG file',
+ help="A SVG file",
)
args = sys.argv[1:]
args = arg_parser.parse_args(args=args)
diff --git a/setup.py b/setup.py
index bd511b0..f84dc7e 100644
--- a/setup.py
+++ b/setup.py
@@ -3,41 +3,41 @@
from setuptools import find_packages
from setuptools import setup
-with open('README.rst') as readme_file:
+with open("README.rst") as readme_file:
readme = readme_file.read()
-with open('HISTORY.rst') as history_file:
+with open("HISTORY.rst") as history_file:
history = history_file.read()
requirements = []
setup(
- name='qmxgraph',
+ name="qmxgraph",
use_scm_version=True,
setup_requires=["setuptools_scm"],
description="A Qt graph drawing widget using JavaScript's mxGraph " "library.",
- long_description=readme + '\n\n' + history,
+ long_description=readme + "\n\n" + history,
author="Rafael Bertoldi",
- author_email='tochaman@gmail.com',
- url='https://github.com/ESSS/qmxgraph',
+ author_email="tochaman@gmail.com",
+ url="https://github.com/ESSS/qmxgraph",
packages=find_packages(where="src"),
package_dir={"": "src"},
install_requires=requirements,
license="MIT license",
zip_safe=False,
- keywords='qmxgraph',
+ keywords="qmxgraph",
classifiers=[
- 'Development Status :: 4 - Beta',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: MIT License',
- 'Natural Language :: English',
- 'Operating System :: OS Independent',
- 'Programming Language :: Python :: 3.8',
- 'Programming Language :: Python :: 3.9',
- 'Programming Language :: Python :: 3.10',
- 'Topic :: Scientific/Engineering :: Visualization',
- 'Topic :: Software Development :: User Interfaces',
+ "Development Status :: 4 - Beta",
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: MIT License",
+ "Natural Language :: English",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Topic :: Scientific/Engineering :: Visualization",
+ "Topic :: Software Development :: User Interfaces",
],
- test_suite='tests',
+ test_suite="tests",
tests_require=[],
)
diff --git a/src/qmxgraph/_cherrypy_server.py b/src/qmxgraph/_cherrypy_server.py
index eaf4599..49febee 100644
--- a/src/qmxgraph/_cherrypy_server.py
+++ b/src/qmxgraph/_cherrypy_server.py
@@ -38,7 +38,7 @@ def start(self, page, config):
cherrypy_server = Process(target=_do_start_server, args=(q, page, config))
cherrypy_server.start()
- if sys.platform.startswith('win'): # pragma: no cover
+ if sys.platform.startswith("win"): # pragma: no cover
timeout = 0.1
fail_on_timeout = False
else:
@@ -48,9 +48,9 @@ def start(self, page, config):
try:
error_msg = q.get(timeout=timeout)
except queue.Empty: # pragma: no cover
- address = '{}:{}'.format(
- config['global']['server.socket_host'],
- config['global']['server.socket_port'],
+ address = "{}:{}".format(
+ config["global"]["server.socket_host"],
+ config["global"]["server.socket_port"],
)
msg = "Server unable to start at {} after a timeout of {} seconds"
assert not fail_on_timeout, msg.format(address, timeout)
@@ -79,7 +79,7 @@ def stop(self):
# If already dead for any reason, just let it go
if e.winerror != 5:
raise
- if not sys.platform.startswith('win'):
+ if not sys.platform.startswith("win"):
os.waitpid(self.server_pid, 0)
self.server_pid = None
@@ -106,12 +106,12 @@ def single_shot(self, page, config):
def _do_start_server(queue, page, config):
import cherrypy
- if not sys.platform.startswith('win'):
+ if not sys.platform.startswith("win"):
# 'main' event is more reliable than 'start' event, as 'start' is
# fired just BEFORE server started, so it may not be necessarily be
# ready for access yet. 'main' though is only fired during server
# loop so it is already set up when reaches that point.
- channel = 'main'
+ channel = "main"
def callback():
cherrypy.engine.unsubscribe(channel, callback)
diff --git a/src/qmxgraph/_web_view.py b/src/qmxgraph/_web_view.py
index 936dc03..6aa779b 100644
--- a/src/qmxgraph/_web_view.py
+++ b/src/qmxgraph/_web_view.py
@@ -86,11 +86,11 @@ def load_graph(self, options: GraphOptions, styles: GraphStyles, stencils):
options=options,
styles=styles,
stencils=stencils,
- mxgraph_path=':/mxgraph',
- own_path=':/qmxgraph',
+ mxgraph_path=":/mxgraph",
+ own_path=":/qmxgraph",
)
self._view_state = ViewState.LoadingGraph
- self.setHtml(html, baseUrl=QUrl('qrc:/'))
+ self.setHtml(html, baseUrl=QUrl("qrc:/"))
def blank(self):
"""
@@ -98,7 +98,7 @@ def blank(self):
content.
"""
self._view_state = ViewState.LoadingBlank
- self.setHtml('')
+ self.setHtml("")
def closeEvent(self, event: QCloseEvent) -> None:
self.stop()
diff --git a/src/qmxgraph/api.py b/src/qmxgraph/api.py
index a03d3bf..0362300 100644
--- a/src/qmxgraph/api.py
+++ b/src/qmxgraph/api.py
@@ -17,18 +17,18 @@ class QmxGraphApi(object):
graph drawing library.
"""
- SOURCE_TERMINAL_CELL = 'source'
- TARGET_TERMINAL_CELL = 'target'
-
- LAYOUT_ORGANIC = 'organic'
- LAYOUT_COMPACT = 'compact'
- LAYOUT_CIRCLE = 'circle'
- LAYOUT_COMPACT_TREE = 'compact_tree'
- LAYOUT_EDGE_LABEL = 'edge_label'
- LAYOUT_PARALLEL_EDGE = 'parallel_edge'
- LAYOUT_PARTITION = 'partition'
- LAYOUT_RADIAL_TREE = 'radial_tree'
- LAYOUT_STACK = 'stack'
+ SOURCE_TERMINAL_CELL = "source"
+ TARGET_TERMINAL_CELL = "target"
+
+ LAYOUT_ORGANIC = "organic"
+ LAYOUT_COMPACT = "compact"
+ LAYOUT_CIRCLE = "circle"
+ LAYOUT_COMPACT_TREE = "compact_tree"
+ LAYOUT_EDGE_LABEL = "edge_label"
+ LAYOUT_PARALLEL_EDGE = "parallel_edge"
+ LAYOUT_PARTITION = "partition"
+ LAYOUT_RADIAL_TREE = "radial_tree"
+ LAYOUT_STACK = "stack"
def __init__(self, graph, call_context_manager_factory):
"""
@@ -77,7 +77,7 @@ def insert_vertex(
:return: Id of new vertex.
"""
return self.call_api(
- 'insertVertex', x, y, width, height, label, style, tags, id, adjust_xy_coordinates
+ "insertVertex", x, y, width, height, label, style, tags, id, adjust_xy_coordinates
)
def insert_port(
@@ -104,7 +104,7 @@ def insert_port(
interaction with cells in a graph.
"""
return self.call_api(
- 'insertPort', vertex_id, port_name, x, y, width, height, label, style, tags
+ "insertPort", vertex_id, port_name, x, y, width, height, label, style, tags
)
def insert_edge(
@@ -141,7 +141,7 @@ def insert_edge(
:return: Id of new edge.
"""
return self.call_api(
- 'insertEdge',
+ "insertEdge",
source_id,
target_id,
label,
@@ -178,7 +178,7 @@ def insert_decoration(self, x, y, width, height, label, style=None, tags=None, i
:rtype: str
:return: Id of new decoration.
"""
- return self.call_api('insertDecoration', x, y, width, height, label, style, tags, id)
+ return self.call_api("insertDecoration", x, y, width, height, label, style, tags, id)
def insert_decoration_on_edge(
self, edge_id, position, width, height, label, style=None, tags=None, id=None
@@ -209,7 +209,7 @@ def insert_decoration_on_edge(
:return: Id of new decoration.
"""
return self.call_api(
- 'insertDecorationOnEdge', edge_id, position, width, height, label, style, tags, id
+ "insertDecorationOnEdge", edge_id, position, width, height, label, style, tags, id
)
def insert_table(
@@ -247,7 +247,7 @@ def insert_table(
contents = decoration_contents.asdict(contents)
return self.call_api(
- 'insertTable', x, y, width, contents, title, tags, style, parent_id, id
+ "insertTable", x, y, width, contents, title, tags, style, parent_id, id
)
def update_table(self, table_id, contents, title):
@@ -262,7 +262,7 @@ def update_table(self, table_id, contents, title):
from . import decoration_contents
contents = decoration_contents.asdict(contents)
- self.call_api_async('updateTable', table_id, contents, title)
+ self.call_api_async("updateTable", table_id, contents, title)
def update_port(
self,
@@ -277,38 +277,38 @@ def update_port(
tags=None,
):
self.call_api_async(
- 'updatePort', vertex_id, port_name, x, y, width, height, label, style, tags
+ "updatePort", vertex_id, port_name, x, y, width, height, label, style, tags
)
def get_port_names(self, vertex_id):
- return self.call_api('getPortNames', vertex_id)
+ return self.call_api("getPortNames", vertex_id)
def group(self):
"""
Create a group with currently selected cells in graph. Edges connected
between selected vertices are automatically also included in group.
"""
- return self.call_api('group')
+ return self.call_api("group")
def ungroup(self):
"""
Ungroup currently selected group.
"""
- return self.call_api('ungroup')
+ return self.call_api("ungroup")
def toggle_outline(self):
"""
Outline is a small window that shows an overview of graph. It usually
starts disabled and can be shown on demand.
"""
- self.call_api_async('toggleOutline')
+ self.call_api_async("toggleOutline")
def toggle_grid(self):
"""
The grid in background of graph helps aligning cells inside graph. It
usually starts enabled and can be hidden on demand.
"""
- self.call_api_async('toggleGrid')
+ self.call_api_async("toggleGrid")
def toggle_snap(self):
"""
@@ -317,7 +317,7 @@ def toggle_snap(self):
Note that if grid is hidden this feature is also disabled.
"""
- self.call_api_async('toggleSnap')
+ self.call_api_async("toggleSnap")
def get_cell_id_at(self, x, y):
"""
@@ -328,7 +328,7 @@ def get_cell_id_at(self, x, y):
:rtype: str|None
:return: Id of cell if any given position, otherwise returns None.
"""
- return self.call_api('getCellIdAt', x, y)
+ return self.call_api("getCellIdAt", x, y)
def get_decoration_parent_cell_id(self, cell_id):
"""
@@ -339,7 +339,7 @@ def get_decoration_parent_cell_id(self, cell_id):
:rtype: str
:return: Id of the edge containg the given decoration.
"""
- return self.call_api('getDecorationParentCellId', cell_id)
+ return self.call_api("getDecorationParentCellId", cell_id)
def has_cell(self, cell_id):
"""
@@ -349,7 +349,7 @@ def has_cell(self, cell_id):
:rtype: bool
:return: True if cell exists.
"""
- return self.call_api('hasCell', cell_id)
+ return self.call_api("hasCell", cell_id)
def has_port(self, cell_id, port_name):
"""
@@ -360,7 +360,7 @@ def has_port(self, cell_id, port_name):
:rtype: bool
:return: True if the port exists.
"""
- return self.call_api('hasPort', cell_id, port_name)
+ return self.call_api("hasPort", cell_id, port_name)
def get_cell_type(self, cell_id):
"""
@@ -375,7 +375,7 @@ def get_cell_type(self, cell_id):
It raises if none of these types are a match.
"""
- return self.call_api('getCellType', cell_id)
+ return self.call_api("getCellType", cell_id)
def get_geometry(self, cell_id):
"""
@@ -391,7 +391,7 @@ def get_geometry(self, cell_id):
- height;
"""
- return self.call_api('getGeometry', cell_id)
+ return self.call_api("getGeometry", cell_id)
def get_terminal_points(self, cell_id):
"""
@@ -408,7 +408,7 @@ def get_terminal_points(self, cell_id):
- the target y coordinate;
"""
- return self.call_api('getEdgeTerminalPoints', cell_id)
+ return self.call_api("getEdgeTerminalPoints", cell_id)
def get_decoration_position(self, cell_id):
"""
@@ -419,7 +419,7 @@ def get_decoration_position(self, cell_id):
:return: Returns an a normalized number between [0, 1] representing
the position of the decoration along the parent edge.
"""
- return self.call_api('getDecorationPosition', cell_id)
+ return self.call_api("getDecorationPosition", cell_id)
def set_decoration_position(self, cell_id, position):
"""
@@ -429,7 +429,7 @@ def set_decoration_position(self, cell_id, position):
:param float position: A normalized number between [0, 1] representing
the position of the decoration along the parent edge.
"""
- return self.call_api('setDecorationPosition', cell_id, position)
+ return self.call_api("setDecorationPosition", cell_id, position)
def set_visible(self, cell_id, visible):
"""
@@ -438,7 +438,7 @@ def set_visible(self, cell_id, visible):
:param str cell_id: Id of a cell in graph.
:param bool visible: If visible or not.
"""
- return self.call_api('setVisible', cell_id, visible)
+ return self.call_api("setVisible", cell_id, visible)
def is_visible(self, cell_id):
"""
@@ -446,7 +446,7 @@ def is_visible(self, cell_id):
:param str cell_id: Id of a cell in graph.
"""
- return self.call_api('isVisible', cell_id)
+ return self.call_api("isVisible", cell_id)
def set_port_visible(self, cell_id, port_name, visible):
"""
@@ -456,7 +456,7 @@ def set_port_visible(self, cell_id, port_name, visible):
:param str port_name: Name of a port in the cell.
:param bool visible: If visible or not.
"""
- return self.call_api('setPortVisible', cell_id, port_name, visible)
+ return self.call_api("setPortVisible", cell_id, port_name, visible)
def is_port_visible(self, cell_id, port_name):
"""
@@ -465,7 +465,7 @@ def is_port_visible(self, cell_id, port_name):
:param str cell_id: Id of a cell in graph.
:param bool port_name: Name of a port in the cell.
"""
- return self.call_api('isPortVisible', cell_id, port_name)
+ return self.call_api("isPortVisible", cell_id, port_name)
def set_connectable(self, cell_id, connectable):
"""
@@ -474,7 +474,7 @@ def set_connectable(self, cell_id, connectable):
:param str cell_id: Id of a cell in graph.
:param bool connectable: If connectable or not.
"""
- self.call_api('setConnectable', cell_id, connectable)
+ self.call_api("setConnectable", cell_id, connectable)
def is_connectable(self, cell_id):
"""
@@ -482,31 +482,31 @@ def is_connectable(self, cell_id):
:param str cell_id: Id of a cell in graph.
"""
- return self.call_api('isConnectable', cell_id)
+ return self.call_api("isConnectable", cell_id)
def zoom_in(self):
"""
Zoom in the graph.
"""
- self.call_api_async('zoomIn')
+ self.call_api_async("zoomIn")
def zoom_out(self):
"""
Zoom out the graph.
"""
- self.call_api_async('zoomOut')
+ self.call_api_async("zoomOut")
def reset_zoom(self):
"""
Reset graph's zoom.
"""
- self.call_api_async('resetZoom')
+ self.call_api_async("resetZoom")
def fit(self):
"""
Rescale the graph to fit in the container.
"""
- self.call_api_async('fit')
+ self.call_api_async("fit")
def get_zoom_scale(self):
"""
@@ -514,7 +514,7 @@ def get_zoom_scale(self):
:rtype: float
"""
- return self.call_api('getZoomScale')
+ return self.call_api("getZoomScale")
def get_scale_and_translation(self):
"""
@@ -531,7 +531,7 @@ def get_scale_and_translation(self):
supplied to :func:`QmxGraphApi.set_scale_and_translation` to
set the scale and translation to a previous value.
"""
- return tuple(self.call_api('getScaleAndTranslation'))
+ return tuple(self.call_api("getScaleAndTranslation"))
def set_scale_and_translation(self, scale, x, y):
"""
@@ -542,7 +542,7 @@ def set_scale_and_translation(self, scale, x, y):
(0 = origin).
:param float y: The new graph's scale along the Y axis (0 = origin}.
"""
- return self.call_api('setScaleAndTranslation', scale, x, y)
+ return self.call_api("setScaleAndTranslation", scale, x, y)
def set_selected_cells(self, cell_ids):
"""
@@ -550,7 +550,7 @@ def set_selected_cells(self, cell_ids):
:param list[str] cell_ids:
"""
- return self.call_api('setSelectedCells', cell_ids)
+ return self.call_api("setSelectedCells", cell_ids)
def get_selected_cells(self):
"""
@@ -558,7 +558,7 @@ def get_selected_cells(self):
:rtype: list[str]
"""
- return self.call_api('getSelectedCells')
+ return self.call_api("getSelectedCells")
def remove_cells(self, cell_ids, ignore_missing_cells=False):
"""
@@ -568,7 +568,7 @@ def remove_cells(self, cell_ids, ignore_missing_cells=False):
:param bool ignore_missing_cells: Ids of non existent cells are
ignored instead raising an error.
"""
- return self.call_api('removeCells', cell_ids, ignore_missing_cells)
+ return self.call_api("removeCells", cell_ids, ignore_missing_cells)
def remove_port(self, vertex_id, port_name):
"""
@@ -578,7 +578,7 @@ def remove_port(self, vertex_id, port_name):
:param str vertex_id: The id of the parent vertex.
:param str port_name: The port's name to remove.
"""
- return self.call_api('removePort', vertex_id, port_name)
+ return self.call_api("removePort", vertex_id, port_name)
def register_double_click_handler(self, handler):
"""
@@ -595,7 +595,7 @@ def register_double_click_handler(self, handler):
object that is going to be used as callback to event. Receives a
str with double clicked cell id as only argument.
"""
- return self.call_api('registerDoubleClickHandler', qmxgraph.js.Variable(handler))
+ return self.call_api("registerDoubleClickHandler", qmxgraph.js.Variable(handler))
def register_popup_menu_handler(self, handler):
"""
@@ -615,7 +615,7 @@ def register_popup_menu_handler(self, handler):
screen coordinates and Y coordinate in screen coordinates as its
three arguments.
"""
- return self.call_api('registerPopupMenuHandler', qmxgraph.js.Variable(handler))
+ return self.call_api("registerPopupMenuHandler", qmxgraph.js.Variable(handler))
def register_label_changed_handler(self, handler):
"""
@@ -627,7 +627,7 @@ def register_label_changed_handler(self, handler):
object that is going to be used as callback to event. Receives,
respectively, cell id, new label and old label as arguments.
"""
- return self.call_api('registerLabelChangedHandler', qmxgraph.js.Variable(handler))
+ return self.call_api("registerLabelChangedHandler", qmxgraph.js.Variable(handler))
def register_cells_added_handler(self, handler):
"""
@@ -639,7 +639,7 @@ def register_cells_added_handler(self, handler):
object that is going to be used as callback to event. Receives a
`QVariantList` of added cell ids as only argument.
"""
- return self.call_api('registerCellsAddedHandler', qmxgraph.js.Variable(handler))
+ return self.call_api("registerCellsAddedHandler", qmxgraph.js.Variable(handler))
def register_cells_removed_handler(self, handler):
"""
@@ -651,7 +651,7 @@ def register_cells_removed_handler(self, handler):
object that is going to be used as callback to event. Receives a
`QVariantList` of removed cell ids as only argument.
"""
- return self.call_api('registerCellsRemovedHandler', qmxgraph.js.Variable(handler))
+ return self.call_api("registerCellsRemovedHandler", qmxgraph.js.Variable(handler))
def register_selection_changed_handler(self, handler):
"""
@@ -661,7 +661,7 @@ def register_selection_changed_handler(self, handler):
that is going to be used as callback to event. Receives an list of
str with selected cells ids as only argument.
"""
- return self.call_api('registerSelectionChangedHandler', qmxgraph.js.Variable(handler))
+ return self.call_api("registerSelectionChangedHandler", qmxgraph.js.Variable(handler))
def register_terminal_changed_handler(self, handler):
"""
@@ -673,7 +673,7 @@ def register_terminal_changed_handler(self, handler):
is the source (or target), id of the net terminal, id of the old
terminal.
"""
- return self.call_api('registerTerminalChangedHandler', qmxgraph.js.Variable(handler))
+ return self.call_api("registerTerminalChangedHandler", qmxgraph.js.Variable(handler))
def register_terminal_with_port_changed_handler(self, handler):
"""
@@ -687,7 +687,7 @@ def register_terminal_with_port_changed_handler(self, handler):
id of the old terminal.
"""
return self.call_api(
- 'registerTerminalWithPortChangedHandler',
+ "registerTerminalWithPortChangedHandler",
qmxgraph.js.Variable(handler),
)
@@ -698,7 +698,7 @@ def register_view_update_handler(self, handler):
that is going to be used as callback to event. Receives,
respectively, graph dump and graph scale and translation.
"""
- return self.call_api('registerViewUpdateHandler', qmxgraph.js.Variable(handler))
+ return self.call_api("registerViewUpdateHandler", qmxgraph.js.Variable(handler))
def register_cells_bounds_changed_handler(self, handler):
"""
@@ -708,7 +708,7 @@ def register_cells_bounds_changed_handler(self, handler):
a map of cell id to a map describing the cell bounds.
"""
- return self.call_api('registerBoundsChangedHandler', qmxgraph.js.Variable(handler))
+ return self.call_api("registerBoundsChangedHandler", qmxgraph.js.Variable(handler))
def resize_container(self, width, height):
"""
@@ -722,7 +722,7 @@ def resize_container(self, width, height):
:param int width: New width.
:param int height: New height.
"""
- self.call_api_async('resizeContainer', width, height)
+ self.call_api_async("resizeContainer", width, height)
def get_label(self, cell_id):
"""
@@ -732,7 +732,7 @@ def get_label(self, cell_id):
:rtype: str
:return: Label of cell.
"""
- return self.call_api('getLabel', cell_id)
+ return self.call_api("getLabel", cell_id)
def set_label(self, cell_id, label):
"""
@@ -741,7 +741,7 @@ def set_label(self, cell_id, label):
:param str cell_id: Id of a cell in graph.
:param str label: New label.
"""
- return self.call_api('setLabel', cell_id, label)
+ return self.call_api("setLabel", cell_id, label)
def set_style(self, cell_id, style):
"""
@@ -750,7 +750,7 @@ def set_style(self, cell_id, style):
:param str cell_id: Id of a cell in graph.
:param str style: Name of a style or an inline style.
"""
- return self.call_api('setStyle', cell_id, style)
+ return self.call_api("setStyle", cell_id, style)
def get_style(self, cell_id):
"""
@@ -760,7 +760,7 @@ def get_style(self, cell_id):
:rtype: str
:return: Name of a style or an inline style.
"""
- return self.call_api('getStyle', cell_id)
+ return self.call_api("getStyle", cell_id)
def set_tag(self, cell_id, tag_name, tag_value):
"""
@@ -770,7 +770,7 @@ def set_tag(self, cell_id, tag_name, tag_value):
:param str tag_name: Name of tag.
:param str tag_value: Value of tag.
"""
- return self.call_api('setTag', cell_id, tag_name, tag_value)
+ return self.call_api("setTag", cell_id, tag_name, tag_value)
def get_tag(self, cell_id, tag_name):
"""
@@ -781,7 +781,7 @@ def get_tag(self, cell_id, tag_name):
:rtype: str
:return: Value of tag.
"""
- return self.call_api('getTag', cell_id, tag_name)
+ return self.call_api("getTag", cell_id, tag_name)
def has_tag(self, cell_id, tag_name):
"""
@@ -792,7 +792,7 @@ def has_tag(self, cell_id, tag_name):
:rtype: bool
:return: True if tag exists in cell.
"""
- return self.call_api('hasTag', cell_id, tag_name)
+ return self.call_api("hasTag", cell_id, tag_name)
def get_edge_terminals(self, edge_id):
"""
@@ -803,7 +803,7 @@ def get_edge_terminals(self, edge_id):
:return: A list with 2 items, first the source vertex id and second
the target vertex id.
"""
- return self.call_api('getEdgeTerminals', edge_id)
+ return self.call_api("getEdgeTerminals", edge_id)
def get_edge_terminals_with_ports(self, edge_id):
"""
@@ -821,7 +821,7 @@ def get_edge_terminals_with_ports(self, edge_id):
- the port's name used on the target (can be `None`);
"""
- return self.call_api('getEdgeTerminalsWithPorts', edge_id)
+ return self.call_api("getEdgeTerminalsWithPorts", edge_id)
def set_edge_terminal(self, edge_id, terminal_type, new_terminal_cell_id, port_name=None):
"""
@@ -840,11 +840,11 @@ def set_edge_terminal(self, edge_id, terminal_type, new_terminal_cell_id, port_n
self.TARGET_TERMINAL_CELL,
}
if terminal_type not in valid_terminal_types:
- err_msg = '%s is not a valid value for `terminal_type`'
+ err_msg = "%s is not a valid value for `terminal_type`"
raise ValueError(err_msg % (terminal_type,))
return self.call_api(
- 'setEdgeTerminal', edge_id, terminal_type, new_terminal_cell_id, port_name
+ "setEdgeTerminal", edge_id, terminal_type, new_terminal_cell_id, port_name
)
def get_cell_bounds(self, cell_id):
@@ -857,7 +857,7 @@ def get_cell_bounds(self, cell_id):
"""
from qmxgraph.cell_bounds import CellBounds
- cell_bounds = self.call_api('getCellBounds', cell_id)
+ cell_bounds = self.call_api("getCellBounds", cell_id)
return CellBounds(**cell_bounds)
def set_cell_bounds(self, cell_id, cell_bounds):
@@ -870,7 +870,7 @@ def set_cell_bounds(self, cell_id, cell_bounds):
"""
from qmxgraph.cell_bounds import asdict
- return self.call_api('setCellBounds', cell_id, asdict(cell_bounds))
+ return self.call_api("setCellBounds", cell_id, asdict(cell_bounds))
def dump(self):
"""
@@ -880,7 +880,7 @@ def dump(self):
:rtype: str
:return: A xml string.
"""
- return self.call_api('dump')
+ return self.call_api("dump")
def restore(self, state):
"""
@@ -888,43 +888,43 @@ def restore(self, state):
:param str state: A xml string previously obtained with `dump`.
"""
- return self.call_api('restore', state)
+ return self.call_api("restore", state)
def set_interaction_enabled(self, enabled):
- self.call_api('setInteractionEnabled', enabled)
+ self.call_api("setInteractionEnabled", enabled)
def set_cells_deletable(self, enabled):
- self.call_api('setCellsDeletable', enabled)
+ self.call_api("setCellsDeletable", enabled)
def is_cells_deletable(self):
- return self.call_api('isCellsDeletable')
+ return self.call_api("isCellsDeletable")
def set_cells_disconnectable(self, enabled):
- self.call_api('setCellsDisconnectable', enabled)
+ self.call_api("setCellsDisconnectable", enabled)
def is_cells_disconnectable(self):
- return self.call_api('isCellsDisconnectable')
+ return self.call_api("isCellsDisconnectable")
def set_cells_editable(self, enabled):
- self.call_api('setCellsEditable', enabled)
+ self.call_api("setCellsEditable", enabled)
def is_cells_editable(self):
- return self.call_api('isCellsEditable')
+ return self.call_api("isCellsEditable")
def set_cells_movable(self, enabled):
- self.call_api('setCellsMovable', enabled)
+ self.call_api("setCellsMovable", enabled)
def is_cells_movable(self):
- return self.call_api('isCellsMovable')
+ return self.call_api("isCellsMovable")
def set_cells_connectable(self, enabled):
- self.call_api('setCellsConnectable', enabled)
+ self.call_api("setCellsConnectable", enabled)
def is_cells_connectable(self):
- return self.call_api('isCellsConnectable')
+ return self.call_api("isCellsConnectable")
def run_layout(self, layout_name):
- return self.call_api('runLayout', layout_name)
+ return self.call_api("runLayout", layout_name)
def call_api(self, fn: str, *args) -> Any:
"""
@@ -957,11 +957,11 @@ def call_api_async(self, fn: str, *args) -> None:
def _call_api(self, fn: str, *args, sync):
graph = self._graph()
eval_func = graph.inner_web_view().eval_js if sync else graph.inner_web_view().eval_js_async
- call = f'api.{qmxgraph.js.prepare_js_call(fn, *args)}'
+ call = f"api.{qmxgraph.js.prepare_js_call(fn, *args)}"
if qmxgraph.debug.is_qmxgraph_debug_enabled():
call = textwrap.dedent(
- f'''
+ f"""
if (
(typeof graphs === "undefined")
|| !graphs.isRunning()
@@ -980,7 +980,7 @@ def _call_api(self, fn: str, *args, sync):
);
}}
{call};
- '''
+ """
)
# Capture all warning messages from Qt.
capture_context = _capture_critical_log_messages()
diff --git a/src/qmxgraph/common_testing.py b/src/qmxgraph/common_testing.py
index 944551c..85a5ecc 100644
--- a/src/qmxgraph/common_testing.py
+++ b/src/qmxgraph/common_testing.py
@@ -7,7 +7,7 @@
from qmxgraph.widget import QmxGraph
-RETURN_ALL_CELLS_FILTER = 'function(cell) { return true }'
+RETURN_ALL_CELLS_FILTER = "function(cell) { return true }"
def get_cell_count(widget: QmxGraph, filter_function: str = RETURN_ALL_CELLS_FILTER) -> int:
@@ -30,7 +30,7 @@ def get_cell_ids(widget: QmxGraph, filter_function: str = RETURN_ALL_CELLS_FILTE
:return: A list with the id's of the selected cells.
"""
cells_ids = widget.inner_web_view().eval_js(
- f'''
+ f"""
(function(){{
var all_cells = api._graphEditor.graph.model.cells;
var cells = Object.keys(all_cells).map(
@@ -39,6 +39,6 @@ def get_cell_ids(widget: QmxGraph, filter_function: str = RETURN_ALL_CELLS_FILTE
cells = cells.filter({filter_function});
return cells.map(function(aCell){{ return aCell.getId(); }});
- }})()'''
+ }})()"""
)
return cast(List[str], cells_ids)
diff --git a/src/qmxgraph/configuration.py b/src/qmxgraph/configuration.py
index 941d576..34b38b0 100644
--- a/src/qmxgraph/configuration.py
+++ b/src/qmxgraph/configuration.py
@@ -22,7 +22,7 @@ def _is_image_configuration(inst, attr, value):
and isinstance(value[1], int)
and isinstance(value[2], int)
):
- msg = '{} must be a tuple of `(str, int, int)` but got {}'
+ msg = "{} must be a tuple of `(str, int, int)` but got {}"
raise TypeError(msg.format(attr.name, repr(value)))
@@ -155,27 +155,27 @@ def __init__(self, styles=None):
def validate(self):
known_keys = {
- 'dashed',
- 'decoration_base_rotation',
- 'deletable',
- 'end_arrow',
- 'fill_color',
- 'fill_opacity',
- 'foldable',
- 'image',
- 'label_position',
- 'label_rotatable',
- 'no_label',
- 'resizable',
- 'rotatable',
- 'selectable',
- 'shape',
- 'start_arrow',
- 'stroke_color',
- 'stroke_width',
- 'stroke_opacity',
- 'vertical_align',
- 'vertical_label_position',
+ "dashed",
+ "decoration_base_rotation",
+ "deletable",
+ "end_arrow",
+ "fill_color",
+ "fill_opacity",
+ "foldable",
+ "image",
+ "label_position",
+ "label_rotatable",
+ "no_label",
+ "resizable",
+ "rotatable",
+ "selectable",
+ "shape",
+ "start_arrow",
+ "stroke_color",
+ "stroke_width",
+ "stroke_opacity",
+ "vertical_align",
+ "vertical_label_position",
}
invalid = {}
diff --git a/src/qmxgraph/decoration_contents.py b/src/qmxgraph/decoration_contents.py
index c664421..71fde18 100644
--- a/src/qmxgraph/decoration_contents.py
+++ b/src/qmxgraph/decoration_contents.py
@@ -36,7 +36,7 @@ def _register_decoration_class(class_):
"tag" `attr.ib`.
"""
for attr_name in class_.__attrs_attrs__:
- if attr_name.name == 'tag':
+ if attr_name.name == "tag":
if not isinstance(attr_name.default, str):
raise ValueError(f"{class_}'s `tag` default must be a `str`")
if attr_name.init:
@@ -64,14 +64,14 @@ def _convert_decoration_content_item(raw_data):
return raw_data
else:
if not isinstance(raw_data, dict):
- raise TypeError(f'`raw_data` must be `str` or `dict` but got {type(raw_data)}')
+ raise TypeError(f"`raw_data` must be `str` or `dict` but got {type(raw_data)}")
raw_data = raw_data.copy()
- tag = raw_data.pop('tag', None)
+ tag = raw_data.pop("tag", None)
if tag is None:
raise ValueError('`raw_data` must have a `"tag"ยด item')
class_ = _tag_to_class.get(tag)
if class_ is None:
- raise ValueError(f"Can't locate a class for tag \"{tag}\"")
+ raise ValueError(f'Can\'t locate a class for tag "{tag}"')
return class_(**raw_data)
@@ -109,7 +109,7 @@ class Image:
:ivar int height: The desired height for the image.
"""
- tag = attr.ib(default='img', init=False)
+ tag = attr.ib(default="img", init=False)
src = attr.ib(validator=_is_str)
width = attr.ib(validator=_is_int)
height = attr.ib(validator=_is_int)
@@ -131,7 +131,7 @@ class TableData:
:ivar optional[str] style: A inline style for the element.
"""
- tag: str = attr.ib(default='td', init=False)
+ tag: str = attr.ib(default="td", init=False)
contents: List[Union[str, Image]] = attrib_table_contents(str, Image)
colspan: int = attr.ib(default=1, validator=_is_int)
rowspan: int = attr.ib(default=1, validator=_is_int)
@@ -154,7 +154,7 @@ class TableRow:
`str` used).
"""
- tag: str = attr.ib(default='tr', init=False)
+ tag: str = attr.ib(default="tr", init=False)
contents: Sequence[Union[str, TableData]] = attrib_table_contents(str, TableData)
@@ -171,7 +171,7 @@ class Table:
:ivar tuple[TableRow] contents: The table rows.
"""
- tag: str = attr.ib(default='table', init=False)
+ tag: str = attr.ib(default="table", init=False)
contents: Sequence[TableRow] = attrib_table_contents(TableRow)
def contents_after(self, caption):
diff --git a/src/qmxgraph/deploy.py b/src/qmxgraph/deploy.py
index cce0d37..1e48982 100644
--- a/src/qmxgraph/deploy.py
+++ b/src/qmxgraph/deploy.py
@@ -9,12 +9,12 @@ def get_conda_env_path():
"""
import sys
- conda_prefix = os.environ.get('CONDA_PREFIX', None)
+ conda_prefix = os.environ.get("CONDA_PREFIX", None)
env_path = None
if conda_prefix is not None:
- if sys.platform.startswith('win'):
+ if sys.platform.startswith("win"):
env_path = conda_prefix
else:
- env_path = os.path.join(conda_prefix, 'usr', 'local')
+ env_path = os.path.join(conda_prefix, "usr", "local")
return env_path
diff --git a/src/qmxgraph/js.py b/src/qmxgraph/js.py
index bd11406..de71901 100644
--- a/src/qmxgraph/js.py
+++ b/src/qmxgraph/js.py
@@ -16,9 +16,9 @@ def prepare_js_call(fn, *args):
:rtype: object
:return: A JavaScript statement ready to be evaluated.
"""
- return '{fn}({args})'.format(
+ return "{fn}({args})".format(
fn=fn,
- args=', '.join(_js_dump(v) for v in args),
+ args=", ".join(_js_dump(v) for v in args),
)
diff --git a/src/qmxgraph/mime.py b/src/qmxgraph/mime.py
index addfa8a..517a08c 100644
--- a/src/qmxgraph/mime.py
+++ b/src/qmxgraph/mime.py
@@ -61,10 +61,10 @@ def create_qt_mime_data(data):
data_stream = QDataStream(item_data, QIODevice.WriteOnly)
qgraph_mime = {
- 'version': qmxgraph.constants.QGRAPH_DD_MIME_VERSION,
+ "version": qmxgraph.constants.QGRAPH_DD_MIME_VERSION,
}
qgraph_mime.update(data)
- data_stream.writeString(json.dumps(qgraph_mime).encode('utf8'))
+ data_stream.writeString(json.dumps(qgraph_mime).encode("utf8"))
mime_data = QMimeData()
mime_data.setData(qmxgraph.constants.QGRAPH_DD_MIME_TYPE, item_data)
diff --git a/src/qmxgraph/render.py b/src/qmxgraph/render.py
index 799edaf..bad7cfc 100644
--- a/src/qmxgraph/render.py
+++ b/src/qmxgraph/render.py
@@ -19,7 +19,7 @@ def render_embedded_html(options, styles, stencils, mxgraph_path, own_path):
"""
from PyQt5.QtCore import QFile
- html_file = QFile(own_path + '/graph.html')
+ html_file = QFile(own_path + "/graph.html")
from PyQt5.QtCore import QIODevice
@@ -30,12 +30,12 @@ def render_embedded_html(options, styles, stencils, mxgraph_path, own_path):
from jinja2 import Template
html_data = html_file.readAll().data()
- template = Template(html_data.decode('utf8'))
+ template = Template(html_data.decode("utf8"))
finally:
html_file.close()
def qrc_prefixed(path):
- return 'qrc{}'.format(path)
+ return "qrc{}".format(path)
mxgraph_path = qrc_prefixed(mxgraph_path)
own_path = qrc_prefixed(own_path)
@@ -67,7 +67,7 @@ def render_hosted_html(options, styles, stencils, mxgraph_path, own_path, templa
env = Environment()
env.loader = FileSystemLoader(template_path)
- template = env.get_template('graph.html')
+ template = env.get_template("graph.html")
return _render(template, options, styles, stencils, mxgraph_path, own_path, embedded=False)
diff --git a/src/qmxgraph/server.py b/src/qmxgraph/server.py
index 335de67..2d97d6b 100644
--- a/src/qmxgraph/server.py
+++ b/src/qmxgraph/server.py
@@ -63,7 +63,7 @@ def gen_config(port, mxgraph_path, own_path, stencils_path=None, debug=False):
config["global"].update(
{
# http://docs.cherrypy.org/en/latest/basics.html#disable-logging
- 'log.screen': False,
+ "log.screen": False,
}
)
@@ -72,14 +72,14 @@ def gen_config(port, mxgraph_path, own_path, stencils_path=None, debug=False):
# any reason server is unable to be started, for instance.
log_path = os.path.dirname(__file__)
- server_logs_dir = '{}/.server_logs'.format(log_path)
+ server_logs_dir = "{}/.server_logs".format(log_path)
if not os.path.isdir(server_logs_dir):
os.makedirs(server_logs_dir)
config["global"].update(
{
- 'log.access_file': '{}/cherrypy_port{}_access.log'.format(server_logs_dir, port),
- 'log.error_file': '{}/cherrypy_port{}_error.log'.format(server_logs_dir, port),
+ "log.access_file": "{}/cherrypy_port{}_access.log".format(server_logs_dir, port),
+ "log.error_file": "{}/cherrypy_port{}_error.log".format(server_logs_dir, port),
}
)
@@ -132,8 +132,8 @@ def index(self, *args, **kwargs):
stencils=self.stencils,
# Environment of mxGraph static files is served together with
# page (see config generation in this module)
- mxgraph_path='mxgraph',
- own_path='own',
+ mxgraph_path="mxgraph",
+ own_path="own",
template_path=self.template_path,
)
return html
@@ -151,7 +151,7 @@ def host(port, options=None, styles=None, stencils=tuple()):
:param iterable[str] stencils: Sequence of paths in file system
referring to stencil files.
"""
- mxgraph_path = os.environ.get('MXGRAPHPATH', None)
+ mxgraph_path = os.environ.get("MXGRAPHPATH", None)
if mxgraph_path is None:
conda_env_path = deploy.get_conda_env_path()
if conda_env_path is None:
@@ -160,9 +160,9 @@ def host(port, options=None, styles=None, stencils=tuple()):
"server. Set MXGRAPHPATH environment variable or "
"use a conda environment."
)
- mxgraph_path = os.path.join(conda_env_path, 'mxgraph')
- mxgraph_path = os.path.join(mxgraph_path, 'javascript', 'src')
- own_path = os.path.join(os.path.dirname(__file__), 'page')
+ mxgraph_path = os.path.join(conda_env_path, "mxgraph")
+ mxgraph_path = os.path.join(mxgraph_path, "javascript", "src")
+ own_path = os.path.join(os.path.dirname(__file__), "page")
stencils_path = None
stencils_ = []
@@ -172,7 +172,7 @@ def host(port, options=None, styles=None, stencils=tuple()):
"Due to simplification, expects " "all stencils in same folder"
)
stencils_path = candidate
- stencils_.append('stencils/{}'.format(os.path.basename(stencil)))
+ stencils_.append("stencils/{}".format(os.path.basename(stencil)))
config = gen_config(
port=port,
@@ -189,7 +189,7 @@ def host(port, options=None, styles=None, stencils=tuple()):
cherrypy_server = CherryPyServer()
with cherrypy_server.single_shot(page=page, config=config):
yield Host(
- address='http://localhost:{}'.format(config['global']['server.socket_port']),
+ address="http://localhost:{}".format(config["global"]["server.socket_port"]),
options=page.options,
styles=page.styles,
stencils=stencils_,
@@ -233,14 +233,14 @@ def portable_path(path):
"""
import sys
- if sys.platform.startswith('win'):
- path = path.replace('\\', '/')
+ if sys.platform.startswith("win"):
+ path = path.replace("\\", "/")
return path
-if __name__ == '__main__':
- mxgraph_path = os.path.join(deploy.get_conda_env_path(), 'mxgraph', 'javascript', 'src')
- own_path = os.path.join(os.path.dirname(__file__), 'page')
+if __name__ == "__main__":
+ mxgraph_path = os.path.join(deploy.get_conda_env_path(), "mxgraph", "javascript", "src")
+ own_path = os.path.join(os.path.dirname(__file__), "page")
config = gen_config(
port=60066,
diff --git a/src/qmxgraph/widget.py b/src/qmxgraph/widget.py
index 507c86e..4589a37 100644
--- a/src/qmxgraph/widget.py
+++ b/src/qmxgraph/widget.py
@@ -39,7 +39,7 @@
from qmxgraph.waiting import wait_until
# Some ugliness to successfully build the doc on ReadTheDocs...
-on_rtd = os.environ.get('READTHEDOCS') == 'True'
+on_rtd = os.environ.get("READTHEDOCS") == "True"
if not on_rtd:
from qmxgraph import resource_mxgraph, resource_qmxgraph # type:ignore[attr-defined]
@@ -130,10 +130,10 @@ def __init__(
self._double_click_bridge = _DoubleClickBridge()
self._popup_menu_bridge = _PopupMenuBridge()
self._channel = QWebChannel()
- self._channel.registerObject('bridge_error_handler', self._error_bridge)
- self._channel.registerObject('bridge_events_handler', self._events_bridge)
- self._channel.registerObject('bridge_double_click_handler', self._double_click_bridge)
- self._channel.registerObject('bridge_popup_menu_handler', self._popup_menu_bridge)
+ self._channel.registerObject("bridge_error_handler", self._error_bridge)
+ self._channel.registerObject("bridge_events_handler", self._events_bridge)
+ self._channel.registerObject("bridge_double_click_handler", self._double_click_bridge)
+ self._channel.registerObject("bridge_popup_menu_handler", self._popup_menu_bridge)
self._web_view.setWebChannel(self._channel)
self._layout.addWidget(self._web_view, 0, 0, 1, 1)
@@ -311,24 +311,24 @@ def is_enabled(self) -> bool:
return self._enabled
def _connect_events_bridge(self):
- self.api.register_cells_added_handler('bridge_events_handler.cells_added_slot')
- self.api.register_cells_removed_handler('bridge_events_handler.cells_removed_slot')
- self.api.register_label_changed_handler('bridge_events_handler.label_changed_slot')
- self.api.register_selection_changed_handler('bridge_events_handler.selection_changed_slot')
- self.api.register_terminal_changed_handler('bridge_events_handler.terminal_changed_slot')
+ self.api.register_cells_added_handler("bridge_events_handler.cells_added_slot")
+ self.api.register_cells_removed_handler("bridge_events_handler.cells_removed_slot")
+ self.api.register_label_changed_handler("bridge_events_handler.label_changed_slot")
+ self.api.register_selection_changed_handler("bridge_events_handler.selection_changed_slot")
+ self.api.register_terminal_changed_handler("bridge_events_handler.terminal_changed_slot")
self.api.register_terminal_with_port_changed_handler(
- 'bridge_events_handler.terminal_with_port_changed_slot'
+ "bridge_events_handler.terminal_with_port_changed_slot"
)
self.api.register_cells_bounds_changed_handler(
- 'bridge_events_handler.cells_bounds_changed_slot'
+ "bridge_events_handler.cells_bounds_changed_slot"
)
- self.api.register_view_update_handler('bridge_events_handler.view_update_slot')
+ self.api.register_view_update_handler("bridge_events_handler.view_update_slot")
def _connect_double_click_handler(self):
- self.api.register_double_click_handler('bridge_double_click_handler.double_click_slot')
+ self.api.register_double_click_handler("bridge_double_click_handler.double_click_slot")
def _connect_popup_menu_handler(self):
- self.api.register_popup_menu_handler('bridge_popup_menu_handler.popup_menu_slot')
+ self.api.register_popup_menu_handler("bridge_popup_menu_handler.popup_menu_slot")
@property
def api(self):
@@ -465,10 +465,10 @@ def _on_drop(self, event):
data = event.mimeData().data(constants.QGRAPH_DD_MIME_TYPE)
if not data.isNull():
data_stream = QDataStream(data, QIODevice.ReadOnly)
- parsed = json.loads(data_stream.readString().decode('utf8'))
+ parsed = json.loads(data_stream.readString().decode("utf8"))
# Refer to `mime.py` for docs about format
- version = parsed['version']
+ version = parsed["version"]
if version not in (1, 2):
raise ValueError("Unsupported version of QmxGraph MIME data: {}".format(version))
@@ -476,34 +476,34 @@ def _on_drop(self, event):
y = event.pos().y()
if version in (1, 2):
- vertices = parsed.get('vertices', [])
+ vertices = parsed.get("vertices", [])
scale = self.api.get_zoom_scale()
for v in vertices:
# place vertices with an offset so their center falls
# in the event point.
- vertex_x = x + (v['dx'] - v['width'] * 0.5) * scale
- vertex_y = y + (v['dy'] - v['height'] * 0.5) * scale
+ vertex_x = x + (v["dx"] - v["width"] * 0.5) * scale
+ vertex_y = y + (v["dy"] - v["height"] * 0.5) * scale
self.api.insert_vertex(
x=vertex_x,
y=vertex_y,
- width=v['width'],
- height=v['height'],
- label=v['label'],
- style=v.get('style', None),
- tags=v.get('tags', {}),
+ width=v["width"],
+ height=v["height"],
+ label=v["label"],
+ style=v.get("style", None),
+ tags=v.get("tags", {}),
)
if version in (2,):
- decorations = parsed.get('decorations', [])
+ decorations = parsed.get("decorations", [])
for v in decorations:
self.api.insert_decoration(
x=x,
y=y,
- width=v['width'],
- height=v['height'],
- label=v['label'],
- style=v.get('style', None),
- tags=v.get('tags', {}),
+ width=v["width"],
+ height=v["height"],
+ label=v["label"],
+ style=v.get("style", None),
+ tags=v.get("tags", {}),
)
event.acceptProposedAction()
@@ -537,14 +537,14 @@ def __init_subclass__(cls, **kwargs):
for k, v in list(cls.__dict__.items()):
if isinstance(v, pyqtSignal):
(signature,) = v.signatures
- m = re.match(r'^([^(]+)\(([^)]*)\)$', signature)
+ m = re.match(r"^([^(]+)\(([^)]*)\)$", signature)
assert m is not None
signal_name = m.group(1)
- assert signal_name.startswith('on_')
- slot_name = signal_name[len('on_') :] + '_slot'
+ assert signal_name.startswith("on_")
+ slot_name = signal_name[len("on_") :] + "_slot"
parameters = m.group(2)
- parameters = parameters.split(',') if parameters else []
+ parameters = parameters.split(",") if parameters else []
slot_method = _make_async_pyqt_slot(slot_name, signal_name, parameters)
setattr(cls, slot_name, slot_method)
@@ -603,7 +603,7 @@ class ErrorHandlingBridge(DelayedSignalsBridge):
# url: str
# line: int
# column: int
- on_error = pyqtSignal(str, str, int, int, name='on_error')
+ on_error = pyqtSignal(str, str, int, int, name="on_error")
class EventsBridge(DelayedSignalsBridge):
@@ -693,16 +693,16 @@ def on_cells_removed_handler(cell_ids):
"""
- on_cells_removed = pyqtSignal('QVariantList', name='on_cells_removed')
- on_cells_added = pyqtSignal('QVariantList', name='on_cells_added')
- on_label_changed = pyqtSignal(str, str, str, name='on_label_changed')
- on_selection_changed = pyqtSignal('QVariantList', name='on_selection_changed')
- on_terminal_changed = pyqtSignal(str, str, str, str, name='on_terminal_changed')
+ on_cells_removed = pyqtSignal("QVariantList", name="on_cells_removed")
+ on_cells_added = pyqtSignal("QVariantList", name="on_cells_added")
+ on_label_changed = pyqtSignal(str, str, str, name="on_label_changed")
+ on_selection_changed = pyqtSignal("QVariantList", name="on_selection_changed")
+ on_terminal_changed = pyqtSignal(str, str, str, str, name="on_terminal_changed")
on_terminal_with_port_changed = pyqtSignal(
- str, str, str, str, str, str, name='on_terminal_with_port_changed'
+ str, str, str, str, str, str, name="on_terminal_with_port_changed"
)
- on_view_update = pyqtSignal(str, 'QVariantList', name='on_view_update')
- on_cells_bounds_changed = pyqtSignal('QVariant', name='on_cells_bounds_changed')
+ on_view_update = pyqtSignal(str, "QVariantList", name="on_view_update")
+ on_cells_bounds_changed = pyqtSignal("QVariant", name="on_cells_bounds_changed")
class _DoubleClickBridge(DelayedSignalsBridge):
@@ -716,7 +716,7 @@ class _DoubleClickBridge(DelayedSignalsBridge):
# Arguments:
# cell_id: str
- on_double_click = pyqtSignal(str, name='on_double_click')
+ on_double_click = pyqtSignal(str, name="on_double_click")
class _PopupMenuBridge(DelayedSignalsBridge):
@@ -732,7 +732,7 @@ class _PopupMenuBridge(DelayedSignalsBridge):
# cell_id: str
# x: int
# y: int
- on_popup_menu = pyqtSignal(str, int, int, name='on_popup_menu')
+ on_popup_menu = pyqtSignal(str, int, int, name="on_popup_menu")
@contextmanager
diff --git a/tasks.py b/tasks.py
index 58d1e7a..5a15342 100644
--- a/tasks.py
+++ b/tasks.py
@@ -31,35 +31,35 @@ def qrc(
from qmxgraph import deploy
WEB_EXTENSIONS = (
- '.js',
- '.gif',
- '.png',
- '.html',
- '.css',
- '.txt', # used by mxGraph resources
- '.xml', # used by mxGraph resources
+ ".js",
+ ".gif",
+ ".png",
+ ".html",
+ ".css",
+ ".txt", # used by mxGraph resources
+ ".xml", # used by mxGraph resources
)
- indent = ' '
- print_message('qrc', color=Fore.BLUE, bright=True)
+ indent = " "
+ print_message("qrc", color=Fore.BLUE, bright=True)
def create_web_resource(resource_name, src_dir):
print_message(
- '{}- resource: {}'.format(indent, resource_name), color=Fore.BLUE, bright=True
+ "{}- resource: {}".format(indent, resource_name), color=Fore.BLUE, bright=True
)
target_dir = os.path.dirname(qmxgraph.__file__)
qrc_file, py_file = generate_qrc_from_folder(
- basename='resource_{}'.format(resource_name),
+ basename="resource_{}".format(resource_name),
alias=resource_name,
source_dir=src_dir,
target_dir=target_dir,
include=WEB_EXTENSIONS,
)
- print_message('{}* generated {}'.format(indent * 2, qrc_file))
- print_message('{}* generated {}'.format(indent * 2, py_file))
+ print_message("{}* generated {}".format(indent * 2, qrc_file))
+ print_message("{}* generated {}".format(indent * 2, py_file))
- mxgraph = os.environ.get('MXGRAPHPATH', None)
+ mxgraph = os.environ.get("MXGRAPHPATH", None)
if mxgraph is not None:
if not os.path.isdir(mxgraph):
raise IOError(
@@ -76,7 +76,7 @@ def create_web_resource(resource_name, src_dir):
" and no conda environment active"
)
- mxgraph = '{env_dir}/mxgraph'.format(env_dir=env_dir)
+ mxgraph = "{env_dir}/mxgraph".format(env_dir=env_dir)
if not os.path.isdir(mxgraph):
raise IOError(
"Unable to determine MxGraph to use:"
@@ -85,20 +85,20 @@ def create_web_resource(resource_name, src_dir):
)
create_web_resource(
- resource_name='mxgraph', src_dir='{folder}/javascript/src'.format(folder=mxgraph)
+ resource_name="mxgraph", src_dir="{folder}/javascript/src".format(folder=mxgraph)
)
qgraph_root = os.path.dirname(qmxgraph.__file__)
create_web_resource(
- resource_name='qmxgraph',
- src_dir=os.path.join(qgraph_root, 'page'),
+ resource_name="qmxgraph",
+ src_dir=os.path.join(qgraph_root, "page"),
)
@invoke.task(
help={
- 'python-version': (
- 'Can be used to define the python version used when creating the' ' work environment'
+ "python-version": (
+ "Can be used to define the python version used when creating the" " work environment"
),
}
)
@@ -111,34 +111,34 @@ def docs(ctx, python_version=None):
import tempfile
from pathlib import Path
- conda_info_json = subprocess.check_output(['conda', 'info', '--json'])
+ conda_info_json = subprocess.check_output(["conda", "info", "--json"])
conda_info = json.loads(conda_info_json)
current_env_name = conda_info["active_prefix_name"]
- if current_env_name in (None, 'base'):
+ if current_env_name in (None, "base"):
raise invoke.Exit("Activate the project's conda environment first")
else:
- docs_env_name = f'{current_env_name}-docs'
+ docs_env_name = f"{current_env_name}-docs"
new_environ = os.environ.copy()
- new_environ['TEST_QMXGRAPH'] = '0'
+ new_environ["TEST_QMXGRAPH"] = "0"
if python_version is not None:
- new_environ['PYTHON_VERSION'] = python_version
+ new_environ["PYTHON_VERSION"] = python_version
script = [
- '', # To have a new line at the start (see windows new line).
- f'conda devenv --name {docs_env_name} --file docs_environment.devenv.yml',
- f'conda activate {docs_env_name}',
- 'cd docs',
- 'sphinx-build . _build -W',
+ "", # To have a new line at the start (see windows new line).
+ f"conda devenv --name {docs_env_name} --file docs_environment.devenv.yml",
+ f"conda activate {docs_env_name}",
+ "cd docs",
+ "sphinx-build . _build -W",
]
- if sys.platform == 'win32':
- suffix = '.bat'
- new_line = '\n@echo on\ncall '
- command = ['cmd', '/C']
+ if sys.platform == "win32":
+ suffix = ".bat"
+ new_line = "\n@echo on\ncall "
+ command = ["cmd", "/C"]
else:
- suffix = '.bash'
- new_line = '\n'
- command = ['bash', '-x']
+ suffix = ".bash"
+ new_line = "\n"
+ command = ["bash", "-x"]
script_file = tempfile.NamedTemporaryFile(suffix=suffix, delete=False)
try:
@@ -154,8 +154,8 @@ def docs(ctx, python_version=None):
@invoke.task
def test(ctx):
- print_message('test'.format(), color=Fore.BLUE, bright=True)
- cmd = 'pytest --cov=qmxgraph --timeout=30 -v --durations=10 --color=yes'
+ print_message("test".format(), color=Fore.BLUE, bright=True)
+ cmd = "pytest --cov=qmxgraph --timeout=30 -v --durations=10 --color=yes"
import subprocess
@@ -164,8 +164,8 @@ def test(ctx):
@invoke.task
def linting(ctx):
- print_message('lint'.format(), color=Fore.BLUE, bright=True)
- cmd = 'flake8 -v qmxgraph'
+ print_message("lint".format(), color=Fore.BLUE, bright=True)
+ cmd = "flake8 -v qmxgraph"
import subprocess
@@ -174,7 +174,7 @@ def linting(ctx):
@invoke.task(
help={
- 'svg_path': 'A SVG file',
+ "svg_path": "A SVG file",
}
)
def svgtostencil(ctx, svg_path):
@@ -182,12 +182,12 @@ def svgtostencil(ctx, svg_path):
Converts a SVG file to a stencil file compatible with mxGraph, output is printed in standard
output.
"""
- qmxgraph_scripts = os.path.join(os.getcwd(), 'scripts')
+ qmxgraph_scripts = os.path.join(os.getcwd(), "scripts")
import subprocess
- svg_to_stencil_script = os.path.join(qmxgraph_scripts, 'svg_to_stencil.py')
- raise invoke.Exit(subprocess.call(['python', svg_to_stencil_script, svg_path]))
+ svg_to_stencil_script = os.path.join(qmxgraph_scripts, "svg_to_stencil.py")
+ raise invoke.Exit(subprocess.call(["python", svg_to_stencil_script, svg_path]))
def generate_qrc(target_filename, file_map):
@@ -242,7 +242,7 @@ def generate_qrc(target_filename, file_map):
# https://forum.qt.io/topic/42641/the-qt-resource-system-compile-error/4).
import io
- with io.open(target_filename, 'w', encoding='utf8') as f:
+ with io.open(target_filename, "w", encoding="utf8") as f:
f.write(contents)
@@ -265,9 +265,9 @@ def generate_qrc_contents(file_map, target_dir):
def create_entry(alias_, path_):
path_ = follow_subst(path_)
rel_path = os.path.relpath(path_, target_dir)
- return ' ' + QRC_ENTRY_TEMPLATE.format(alias=alias_, path=rel_path)
+ return " " + QRC_ENTRY_TEMPLATE.format(alias=alias_, path=rel_path)
- entries = '\n'.join([create_entry(alias, path) for (alias, path) in file_map])
+ entries = "\n".join([create_entry(alias, path) for (alias, path) in file_map])
return QRC_FILE_TEMPLATE.format(entries=entries)
@@ -294,10 +294,10 @@ def generate_qrc_py(qrc_filename, target_filename):
subprocess.check_call(
[
sys.executable,
- '-m',
- 'PyQt5.pyrcc_main',
+ "-m",
+ "PyQt5.pyrcc_main",
local_filename,
- '-o',
+ "-o",
target_filename,
],
cwd=cwd,
@@ -325,9 +325,7 @@ def generate_qrc_from_folder(basename, alias, source_dir, target_dir, include=No
With a call like:
```python
- generate_qrc_from_folder(
- "resource_foo", "rsc_foo", "/home/dent/foo/", "/home/dent/foo/"
- )
+ generate_qrc_from_folder("resource_foo", "rsc_foo", "/home/dent/foo/", "/home/dent/foo/")
```
It would result in a .qrc like:
@@ -361,10 +359,10 @@ def generate_qrc_from_folder(basename, alias, source_dir, target_dir, include=No
if not os.path.isdir(target_dir):
raise IOError("Invalid target directory: {}".format(target_dir))
- if sys.platform.startswith('win'):
+ if sys.platform.startswith("win"):
def fix_alias(a):
- return a.replace('\\', '/')
+ return a.replace("\\", "/")
else:
@@ -374,7 +372,7 @@ def fix_alias(a):
files = [
(
fix_alias(
- '{alias}/{rel_file}'.format(alias=alias, rel_file=os.path.relpath(f, source_dir))
+ "{alias}/{rel_file}".format(alias=alias, rel_file=os.path.relpath(f, source_dir))
),
f,
)
@@ -385,10 +383,10 @@ def fix_alias(a):
"Unable to collect anything for " ".qrc file in folder {}".format(source_dir)
)
- qrc_filename = os.path.join(target_dir, '{basename}{ext}'.format(basename=basename, ext='.qrc'))
+ qrc_filename = os.path.join(target_dir, "{basename}{ext}".format(basename=basename, ext=".qrc"))
generate_qrc(qrc_filename, files)
- py_filename = os.path.join(target_dir, '{basename}{ext}'.format(basename=basename, ext='.py'))
+ py_filename = os.path.join(target_dir, "{basename}{ext}".format(basename=basename, ext=".py"))
generate_qrc_py(qrc_filename, py_filename)
return qrc_filename, py_filename
@@ -404,7 +402,7 @@ def collect_files_in_folder(folder, include=None):
return collected
-def print_message(message, color=None, bright=True, endline='\n'):
+def print_message(message, color=None, bright=True, endline="\n"):
"""
Print a message to the standard output.
@@ -421,7 +419,7 @@ def print_message(message, color=None, bright=True, endline='\n'):
if color is not None:
style = Style.BRIGHT if bright else Style.DIM
- message = '{color}{style}{msg}{reset}'.format(
+ message = "{color}{style}{msg}{reset}".format(
color=color,
style=style,
reset=Style.RESET_ALL,
@@ -437,7 +435,7 @@ def print_message(message, color=None, bright=True, endline='\n'):
sys.stderr.flush()
-if sys.platform.startswith('win'):
+if sys.platform.startswith("win"):
def follow_subst(path, deep=True):
"""
@@ -462,7 +460,7 @@ def follow_subst(path, deep=True):
path = os.path.abspath(path)
while True:
- drive = path[0] + ':'
+ drive = path[0] + ":"
universal_drive = drive.lower()
subst = parse_subst()
if universal_drive in subst:
@@ -479,7 +477,7 @@ def parse_subst():
import re
import subprocess
- output = subprocess.check_output('subst')
+ output = subprocess.check_output("subst")
def parse_subst_line(line):
import locale
@@ -487,7 +485,7 @@ def parse_subst_line(line):
if not isinstance(line, str):
line = line.decode(locale.getpreferredencoding(False))
- match = re.match(r'^(\w:)\\: => (.+)$', line)
+ match = re.match(r"^(\w:)\\: => (.+)$", line)
drive = match.group(1)
replace = match.group(2)
return drive.lower(), replace
@@ -510,7 +508,7 @@ def follow_subst(path, deep=True):
QRC_ENTRY_TEMPLATE = '{path}'
-QRC_FILE_TEMPLATE = '''\
+QRC_FILE_TEMPLATE = """\
@@ -518,7 +516,7 @@ def follow_subst(path, deep=True):
{entries}
-'''
+"""
# Only task registered in this global collection will be detected by invoke.
diff --git a/tests/conftest.py b/tests/conftest.py
index 29a77cb..c1ff37a 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -7,7 +7,7 @@ def pytest_configure(config):
# During warm up, clean up the temporary files/objects used by ports
# fixture from previous runs. Note these files are shared among ALL slaves
# of pytest so they can't reliably be removed by a fixture.
- config.cache.set('qmxgraph/ports', [])
+ config.cache.set("qmxgraph/ports", [])
import os
@@ -54,7 +54,7 @@ def enable_qgraph_debug():
qmxgraph.debug.set_qmxgraph_debug(False)
-@pytest.fixture(scope='session')
+@pytest.fixture(scope="session")
def port(request):
"""
Each process hosting a graph page must use an unique port. This fixture
@@ -106,7 +106,7 @@ def get(self):
# On Windows it seems to sometimes to fail because of lack of
# privileges, for some reason.
if e.errno == errno.EEXIST or (
- sys.platform.startswith('win') and e.errno == errno.EACCES
+ sys.platform.startswith("win") and e.errno == errno.EACCES
):
time.sleep(0.1)
continue
@@ -117,15 +117,15 @@ def get(self):
import socket
s = socket.socket()
- s.bind(('', 0))
+ s.bind(("", 0))
port_ = s.getsockname()[1]
s.close()
- ports_ = self.cache.get('qmxgraph/ports', [])
+ ports_ = self.cache.get("qmxgraph/ports", [])
unique = port_ not in ports_
if unique:
- self.cache.set('qmxgraph/ports', ports_ + [port_])
+ self.cache.set("qmxgraph/ports", ports_ + [port_])
break
else:
attempts -= 1
@@ -138,7 +138,7 @@ def get(self):
return port_
-@pytest.fixture(scope='session')
+@pytest.fixture(scope="session")
def host(port):
"""
Hosts a graph page, with a series of simple default options and styles.
@@ -151,21 +151,21 @@ def host(port):
styles = GraphStyles(
{
- 'group': {
- 'shape': 'rectangle',
- 'fill_color': '#ff93ba',
- 'dashed': True,
+ "group": {
+ "shape": "rectangle",
+ "fill_color": "#ff93ba",
+ "dashed": True,
},
- 'table': {
- 'fill_color': '#ffffff',
- 'stroke_opacity': 0,
- 'fill_opacity': 0,
+ "table": {
+ "fill_color": "#ffffff",
+ "stroke_opacity": 0,
+ "fill_opacity": 0,
},
- 'yellow': {
- 'fill_color': '#ffff00',
+ "yellow": {
+ "fill_color": "#ffff00",
},
- 'purple': {
- 'fill_color': '#ff00ff',
+ "purple": {
+ "fill_color": "#ff00ff",
},
}
)
@@ -256,10 +256,10 @@ def pytest_collection_modifyitems(items):
"""
import os
- if os.environ.get('CI', 'false') != 'true':
+ if os.environ.get("CI", "false") != "true":
return
for item in items:
- if 'graph_cases' in getattr(item, 'fixturenames', []):
+ if "graph_cases" in getattr(item, "fixturenames", []):
item.add_marker(pytest.mark.flaky(reruns=3))
@@ -306,31 +306,31 @@ def __init__(self, selenium, host):
_wait_graph_page_ready(host=host, selenium=selenium)
selenium.execute_script(
- 'callback = function(cellIds) {'
- ' if (!window.__added__) {'
- ' window.__added__ = [];'
- ' }'
- ' window.__added__.push.apply(window.__added__, cellIds);'
- '}'
+ "callback = function(cellIds) {"
+ " if (!window.__added__) {"
+ " window.__added__ = [];"
+ " }"
+ " window.__added__.push.apply(window.__added__, cellIds);"
+ "}"
)
- self.eval_js_function('api.registerCellsAddedHandler', qmxgraph.js.Variable('callback'))
+ self.eval_js_function("api.registerCellsAddedHandler", qmxgraph.js.Variable("callback"))
selenium.execute_script(
- 'callback = function(cellId, newLabel, oldLabel) {'
- ' if (!window.__labels__) {'
- ' window.__labels__ = [];'
- ' }'
- ' window.__labels__.push({cellId: cellId, newLabel: newLabel, oldLabel: oldLabel});' # noqa
- '}'
+ "callback = function(cellId, newLabel, oldLabel) {"
+ " if (!window.__labels__) {"
+ " window.__labels__ = [];"
+ " }"
+ " window.__labels__.push({cellId: cellId, newLabel: newLabel, oldLabel: oldLabel});" # noqa
+ "}"
)
- self.eval_js_function('api.registerLabelChangedHandler', qmxgraph.js.Variable('callback'))
+ self.eval_js_function("api.registerLabelChangedHandler", qmxgraph.js.Variable("callback"))
def get_container(self):
"""
:rtype: selenium.webdriver.remote.webelement.WebElement
:return: DIV element containing graph drawing widget.
"""
- return self.selenium.find_element(By.ID, 'graphContainer')
+ return self.selenium.find_element(By.ID, "graphContainer")
def get_container_size(self):
"""
@@ -339,7 +339,7 @@ def get_container_size(self):
element, respectively.
"""
container = self.get_container()
- return container.size['width'], container.size['height']
+ return container.size["width"], container.size["height"]
def get_vertex_position(self, vertex):
"""
@@ -348,7 +348,7 @@ def get_vertex_position(self, vertex):
:rtype: tuple[float, float]
:return: Left/X and top/Y screen coordinates of vertex, respectively.
"""
- return float(vertex.get_attribute('x')), float(vertex.get_attribute('y'))
+ return float(vertex.get_attribute("x")), float(vertex.get_attribute("y"))
def get_vertex_size(self, vertex):
"""
@@ -357,7 +357,7 @@ def get_vertex_size(self, vertex):
:rtype: tuple[int, int]
:return: Width and height in pixels of vertex, respectively.
"""
- return int(vertex.get_attribute('width')), int(vertex.get_attribute('height'))
+ return int(vertex.get_attribute("width")), int(vertex.get_attribute("height"))
def get_edge(self, source, target):
"""
@@ -378,12 +378,12 @@ def get(v, attr):
from selenium.common.exceptions import StaleElementReferenceException
try:
- if get(source, 'x') < get(target, 'x'):
- h_right = get(source, 'x') + get(source, 'width')
- v_center = get(source, 'y') + get(source, 'height') // 2
+ if get(source, "x") < get(target, "x"):
+ h_right = get(source, "x") + get(source, "width")
+ v_center = get(source, "y") + get(source, "height") // 2
else:
- h_right = get(target, 'x') + get(target, 'width')
- v_center = get(target, 'y') + get(target, 'height') // 2
+ h_right = get(target, "x") + get(target, "width")
+ v_center = get(target, "y") + get(target, "height") // 2
except StaleElementReferenceException:
# If any of vertices is not longer in page, edge is also removed
return None
@@ -410,14 +410,14 @@ def get_label_element(self, cell):
# vertices aren't child to cell drawing node in SVG of mxGraph, they
# actually share a same parent node which contains both cell drawing
# and text at a same level.
- common = cell.find_element(By.XPATH, '../..')
- if self.selenium.execute_script('return graphEditor.graph.isHtmlLabel()'):
+ common = cell.find_element(By.XPATH, "../..")
+ if self.selenium.execute_script("return graphEditor.graph.isHtmlLabel()"):
# If HTML labels are enabled, label is a bit more complicated...
- g = common.find_element(By.CSS_SELECTOR, 'g[style]>g[transform]')
- label = g.find_element(By.TAG_NAME, 'div')
- label = label.find_element(By.TAG_NAME, 'div')
+ g = common.find_element(By.CSS_SELECTOR, "g[style]>g[transform]")
+ label = g.find_element(By.TAG_NAME, "div")
+ label = label.find_element(By.TAG_NAME, "div")
else:
- label = common.find_element(By.CSS_SELECTOR, 'g>g>text')
+ label = common.find_element(By.CSS_SELECTOR, "g>g>text")
return label
def get_edge_position(self, edge):
@@ -430,7 +430,7 @@ def get_edge_position(self, edge):
"""
import re
- edge_coords = re.search(r'M (\d+) (\d+)', edge.get_attribute('d'))
+ edge_coords = re.search(r"M (\d+) (\d+)", edge.get_attribute("d"))
return int(edge_coords.group(1)), int(edge_coords.group(2))
def get_id(self, cell):
@@ -452,7 +452,7 @@ def get_id(self, cell):
tolerance = self.selenium.execute_script("return graphEditor.graph.tolerance") / 2.0
id_ = self.eval_js_function(
- 'api.getCellIdAt', cell.location['x'] + tolerance, cell.location['y'] + tolerance
+ "api.getCellIdAt", cell.location["x"] + tolerance, cell.location["y"] + tolerance
)
return id_
@@ -464,7 +464,7 @@ def get_type_at(self, x, y):
:return: Cell type at position. See `QmxGraphApi.getCellTypeAt` for
details about possible types.
"""
- return self.eval_js_function('api.getCellTypeAt', x, y)
+ return self.eval_js_function("api.getCellTypeAt", x, y)
def get_geometry(self, cell):
"""
@@ -473,7 +473,7 @@ def get_geometry(self, cell):
:rtype: list[int, int, int, int]
:return: List composed, respectively, by x, y, width and height.
"""
- return self.eval_js_function('api.getGeometry', self._as_cell_id(cell))
+ return self.eval_js_function("api.getGeometry", self._as_cell_id(cell))
def get_label(self, cell):
"""
@@ -482,7 +482,7 @@ def get_label(self, cell):
:rtype: str
:return: Label of cell.
"""
- return self.eval_js_function('api.getLabel', self._as_cell_id(cell))
+ return self.eval_js_function("api.getLabel", self._as_cell_id(cell))
def set_visible(self, cell, visible):
"""
@@ -490,14 +490,14 @@ def set_visible(self, cell, visible):
Graphical element of a cell or its id.
:param bool visible: New visibility state.
"""
- self.eval_js_function('api.setVisible', self._as_cell_id(cell), visible)
+ self.eval_js_function("api.setVisible", self._as_cell_id(cell), visible)
def is_visible(self, cell):
"""
:param selenium.webdriver.remote.webelement.WebElement|str cell:
Graphical element of a cell or its id.
"""
- return self.eval_js_function('api.isVisible', self._as_cell_id(cell))
+ return self.eval_js_function("api.isVisible", self._as_cell_id(cell))
def get_table_title(self, table):
"""
@@ -506,8 +506,8 @@ def get_table_title(self, table):
:rtype: str
:return: Table title.
"""
- title = table.find_element(By.CSS_SELECTOR, 'table.table-cell-title')
- return title.find_element(By.TAG_NAME, 'tr').text
+ title = table.find_element(By.CSS_SELECTOR, "table.table-cell-title")
+ return title.find_element(By.TAG_NAME, "tr").text
def get_table_contents(self, table):
"""
@@ -516,8 +516,8 @@ def get_table_contents(self, table):
:rtype: str
:return: Table contents.
"""
- contents = table.find_element(By.CSS_SELECTOR, 'table.table-cell-contents')
- return [i.text for i in contents.find_elements(By.TAG_NAME, 'td')]
+ contents = table.find_element(By.CSS_SELECTOR, "table.table-cell-contents")
+ return [i.text for i in contents.find_elements(By.TAG_NAME, "td")]
def select_vertex(self, vertex):
"""
@@ -532,8 +532,8 @@ def select_vertex(self, vertex):
# because of element mismatch. This is an attempt to click in the
# bottom right part of vertex that *usually* doesn't seem to have
# anything over it.
- x_offset = int(vertex.get_attribute('width')) // 2
- y_offset = int(vertex.get_attribute('height')) // 2
+ x_offset = int(vertex.get_attribute("width")) // 2
+ y_offset = int(vertex.get_attribute("height")) // 2
assert (x_offset > 0) and (y_offset > 0)
actions.move_to_element_with_offset(vertex, x_offset, y_offset)
actions.click()
@@ -556,7 +556,7 @@ def get_added_cell_ids(self):
:return: Id of every cell added to graph, captured by using
`registerCellsAddedHandler` event.
"""
- return self.selenium.execute_script('return window.__added__')
+ return self.selenium.execute_script("return window.__added__")
def get_label_changes(self):
"""
@@ -564,9 +564,9 @@ def get_label_changes(self):
:return: Event object of every time a cell was renamed in graph,
captured by using `onLabelChanged` event.
"""
- return self.selenium.execute_script('return window.__labels__')
+ return self.selenium.execute_script("return window.__labels__")
- def insert_vertex(self, x=10, y=10, width=25, height=25, label='label', style=None, tags=None):
+ def insert_vertex(self, x=10, y=10, width=25, height=25, label="label", style=None, tags=None):
"""
Inserts a vertex with sensible, empirical defaults.
@@ -576,7 +576,7 @@ def insert_vertex(self, x=10, y=10, width=25, height=25, label='label', style=No
"""
return self.eval_js_function("api.insertVertex", x, y, width, height, label, style, tags)
- def insert_table(self, x=20, y=60, width=100, contents=None, title='Hitchhikers', tags=None):
+ def insert_table(self, x=20, y=60, width=100, contents=None, title="Hitchhikers", tags=None):
"""
Inserts a table with sensible, empirical defaults.
@@ -587,17 +587,17 @@ def insert_table(self, x=20, y=60, width=100, contents=None, title='Hitchhikers'
if contents is None:
contents = { # graphs.utils.TableRowDescription
- 'contents': [
+ "contents": [
# graphs.utils.TableDataDescription
- {'contents': ['arthur', 'dent']},
+ {"contents": ["arthur", "dent"]},
# graphs.utils.TableDataDescription
- {'contents': ['ford', 'prefect']},
+ {"contents": ["ford", "prefect"]},
]
}
- return self.eval_js_function('api.insertTable', x, y, width, contents, title, tags)
+ return self.eval_js_function("api.insertTable", x, y, width, contents, title, tags)
def insert_decoration(
- self, x, y, width=10, height=10, style=None, label='decoration', tags=None
+ self, x, y, width=10, height=10, style=None, label="decoration", tags=None
):
"""
Inserts a decoration with sensible, empirical defaults for most
@@ -609,7 +609,7 @@ def insert_decoration(
:return: New decoration id.
"""
return self.eval_js_function(
- 'api.insertDecoration', x, y, width, height, label, style, tags
+ "api.insertDecoration", x, y, width, height, label, style, tags
)
def insert_edge_by_drag_drop(self, source, target):
@@ -627,7 +627,7 @@ def insert_edge_by_drag_drop(self, source, target):
actions.drag_and_drop(source, target)
actions.perform()
- def insert_edge(self, source, target, label='', style=None, tags=None):
+ def insert_edge(self, source, target, label="", style=None, tags=None):
"""
Inserts an edge programatically.
@@ -661,7 +661,7 @@ def remove_cells(self, *cell_ids):
"""
:param iterable[str] cell_ids: Id of cells to be removed.
"""
- return self.eval_js_function('api.removeCells', list(cell_ids))
+ return self.eval_js_function("api.removeCells", list(cell_ids))
def eval_js_function(self, fn, *args):
"""
@@ -675,7 +675,7 @@ def eval_js_function(self, fn, *args):
# Unlike Qt JS evaluation, Selenium doesn't include return by default,
# it is necessary to include it in statement.
return self.selenium.execute_script(
- 'return {}'.format(qmxgraph.js.prepare_js_call(fn, *args))
+ "return {}".format(qmxgraph.js.prepare_js_call(fn, *args))
)
def _as_cell_id(self, cell):
@@ -712,11 +712,11 @@ def __init__(self, selenium, host):
selenium.execute_script("api.insertVertex(10, 10, 25, 25, 'label', null)")
vertex = self.get_vertex()
- assert vertex.get_attribute('x') == '10'
- assert vertex.get_attribute('y') == '10'
- assert vertex.get_attribute('width') == '25'
- assert vertex.get_attribute('height') == '25'
- assert self.get_label_element(vertex).text == 'label'
+ assert vertex.get_attribute("x") == "10"
+ assert vertex.get_attribute("y") == "10"
+ assert vertex.get_attribute("width") == "25"
+ assert vertex.get_attribute("height") == "25"
+ assert self.get_label_element(vertex).text == "label"
def get_vertex(self):
color = self.selenium.execute_script(
@@ -738,7 +738,7 @@ class Graph1Vertex1Port(Graph1Vertex):
def __init__(self, selenium, host):
Graph1Vertex.__init__(self, selenium, host)
vertex_id = self.get_id(self.get_vertex())
- self.port_color = '#987654'
+ self.port_color = "#987654"
selenium.execute_script(
f"api.insertPort("
f" {vertex_id}, 'foo',"
@@ -762,14 +762,14 @@ def __init__(self, selenium, host):
selenium.execute_script("api.insertVertex(10, 10, 25, 25, 'yellow', 'yellow')")
vertex = self.get_vertex()
- assert vertex.get_attribute('x') == '10'
- assert vertex.get_attribute('y') == '10'
- assert vertex.get_attribute('width') == '25'
- assert vertex.get_attribute('height') == '25'
- assert self.get_label_element(vertex).text == 'yellow'
+ assert vertex.get_attribute("x") == "10"
+ assert vertex.get_attribute("y") == "10"
+ assert vertex.get_attribute("width") == "25"
+ assert vertex.get_attribute("height") == "25"
+ assert self.get_label_element(vertex).text == "yellow"
def get_vertex(self):
- color = self.host.styles['yellow']['fill_color']
+ color = self.host.styles["yellow"]["fill_color"]
# The vertex basically is composed of two parts:
# * A tag drawn in SVG (which is a grandchild of two consecutive
@@ -785,8 +785,8 @@ class Graph2Vertices(BaseGraphCase):
def __init__(self, selenium, host):
BaseGraphCase.__init__(self, selenium, host)
- self.vertex1_id = self.insert_vertex(10, 10, 30, 30, 'foo', None)
- self.vertex2_id = self.insert_vertex(90, 10, 30, 30, 'bar', None)
+ self.vertex1_id = self.insert_vertex(10, 10, 30, 30, "foo", None)
+ self.vertex2_id = self.insert_vertex(90, 10, 30, 30, "bar", None)
class Graph2Vertices1EdgeByCode(Graph2Vertices):
@@ -795,27 +795,27 @@ def __init__(self, selenium, host):
self.source_id = self.vertex1_id
self.target_id = self.vertex2_id
- self.edge_id = self.insert_edge(self.source_id, self.target_id, 'edge')
+ self.edge_id = self.insert_edge(self.source_id, self.target_id, "edge")
class Graph3Vertices1EdgeByCode(Graph2Vertices1EdgeByCode):
def __init__(self, selenium, host):
Graph2Vertices1EdgeByCode.__init__(self, selenium, host)
- self.vertex3_id = self.insert_vertex(10, 90, 30, 30, 'fuz', None)
+ self.vertex3_id = self.insert_vertex(10, 90, 30, 30, "fuz", None)
class Graph3Vertices3EdgesByCode(BaseGraphCase):
def __init__(self, selenium, host):
BaseGraphCase.__init__(self, selenium, host)
- self.vertex1_id = self.insert_vertex(0, 0, 1, 1, label='foo')
- self.vertex2_id = self.insert_vertex(100, 0, 1, 1, label='bar')
- self.vertex3_id = self.insert_vertex(200, 0, 1, 1, label='fuz')
+ self.vertex1_id = self.insert_vertex(0, 0, 1, 1, label="foo")
+ self.vertex2_id = self.insert_vertex(100, 0, 1, 1, label="bar")
+ self.vertex3_id = self.insert_vertex(200, 0, 1, 1, label="fuz")
- self.edge1_id = self.insert_edge(self.vertex1_id, self.vertex2_id, 'edge1')
- self.edge2_id = self.insert_edge(self.vertex1_id, self.vertex3_id, 'edge2')
- self.edge3_id = self.insert_edge(self.vertex2_id, self.vertex3_id, 'edge3')
+ self.edge1_id = self.insert_edge(self.vertex1_id, self.vertex2_id, "edge1")
+ self.edge2_id = self.insert_edge(self.vertex1_id, self.vertex3_id, "edge2")
+ self.edge3_id = self.insert_edge(self.vertex2_id, self.vertex3_id, "edge3")
class Graph2Vertices1EdgeByDragDrop(Graph2Vertices):
@@ -843,9 +843,9 @@ def __init__(self, selenium, host):
y = vertices_top_border + vertices_width / 2 # edge's y coordinate.
w = 10
h = 10
- style = 'purple'
- label = 'decoration'
- self.eval_js_function('api.insertDecoration', x, y, w, h, label, style)
+ style = "purple"
+ label = "decoration"
+ self.eval_js_function("api.insertDecoration", x, y, w, h, label, style)
decoration = self.get_decorations()[0]
assert int(decoration.get_attribute("x")) == x - (w // 2)
@@ -854,8 +854,8 @@ def __init__(self, selenium, host):
assert int(decoration.get_attribute("height")) == h
def get_decorations(self):
- style = 'purple'
- selector = 'g>g>rect[fill="{}"]'.format(self.host.styles[style]['fill_color'])
+ style = "purple"
+ selector = 'g>g>rect[fill="{}"]'.format(self.host.styles[style]["fill_color"])
decoration = self.selenium.find_elements(By.CSS_SELECTOR, selector)
return decoration
@@ -868,27 +868,27 @@ def __init__(self, selenium, host):
y = 60
w = 100
contents = { # graphs.utils.TableDescription
- 'contents': [
+ "contents": [
# graphs.utils.TableDataDescription
- {'contents': ['arthur', 'dent']},
+ {"contents": ["arthur", "dent"]},
# graphs.utils.TableDataDescription
- {'contents': ['ford', 'prefect']},
+ {"contents": ["ford", "prefect"]},
]
}
- title = 'Hitchhikers'
- self.table_id = self.eval_js_function('api.insertTable', x, y, w, contents, title)
+ title = "Hitchhikers"
+ self.table_id = self.eval_js_function("api.insertTable", x, y, w, contents, title)
- assert self.get_table_title(self.get_tables()[0]) == 'Hitchhikers'
+ assert self.get_table_title(self.get_tables()[0]) == "Hitchhikers"
assert self.get_table_contents(self.get_tables()[0]) == [
- 'arthur',
- 'dent',
- 'ford',
- 'prefect',
+ "arthur",
+ "dent",
+ "ford",
+ "prefect",
]
def get_tables(self):
- titles = self.selenium.find_elements(By.CSS_SELECTOR, 'div>table.table-cell-title')
- return [web_el.find_element(By.XPATH, '../..') for web_el in titles]
+ titles = self.selenium.find_elements(By.CSS_SELECTOR, "div>table.table-cell-title")
+ return [web_el.find_element(By.XPATH, "../..") for web_el in titles]
class Graph1Table(BaseGraphCase):
@@ -899,27 +899,27 @@ def __init__(self, selenium, host):
y = 60
w = 100
contents = { # graphs.utils.TableDescription
- 'contents': [
+ "contents": [
# graphs.utils.TableDataDescription
- {'contents': ['arthur', 'dent']},
+ {"contents": ["arthur", "dent"]},
# graphs.utils.TableDataDescription
- {'contents': ['ford', 'prefect']},
+ {"contents": ["ford", "prefect"]},
]
}
- title = 'Hitchhikers'
- self.eval_js_function('api.insertTable', x, y, w, contents, title)
+ title = "Hitchhikers"
+ self.eval_js_function("api.insertTable", x, y, w, contents, title)
- assert self.get_table_title(self.get_tables()[0]) == 'Hitchhikers'
+ assert self.get_table_title(self.get_tables()[0]) == "Hitchhikers"
assert self.get_table_contents(self.get_tables()[0]) == [
- 'arthur',
- 'dent',
- 'ford',
- 'prefect',
+ "arthur",
+ "dent",
+ "ford",
+ "prefect",
]
def get_tables(self):
- titles = self.selenium.find_elements(By.CSS_SELECTOR, 'div>table.table-cell-title')
- return [web_el.find_element(By.XPATH, '../..') for web_el in titles]
+ titles = self.selenium.find_elements(By.CSS_SELECTOR, "div>table.table-cell-title")
+ return [web_el.find_element(By.XPATH, "../..") for web_el in titles]
def _wait_graph_page_ready(host, selenium):
@@ -962,12 +962,13 @@ def _wait_graph_page_ready(host, selenium):
)
except timeout_exceptions as e:
raise TimeoutException(
- "Graph page wasn't ready in address {} after a timeout of {}"
- " seconds".format(host.address, timeout)
+ "Graph page wasn't ready in address {} after a timeout of {}" " seconds".format(
+ host.address, timeout
+ )
) from e
for n in range(timeout):
- has_api = selenium.execute_script('return !!window.api')
+ has_api = selenium.execute_script("return !!window.api")
if has_api:
break
else:
@@ -980,4 +981,4 @@ def _wait_graph_page_ready(host, selenium):
def _get_port_lock_filename(rootdir):
- return '{}/.port.lock'.format(rootdir)
+ return "{}/.port.lock".format(rootdir)
diff --git a/tests/test_decoration_contents.py b/tests/test_decoration_contents.py
index 5c2b320..7b7f61b 100644
--- a/tests/test_decoration_contents.py
+++ b/tests/test_decoration_contents.py
@@ -20,15 +20,15 @@ class Household:
def test_tuple_of_validator() -> None:
- Household(silverware=(Cutlery(name='fork'),))
+ Household(silverware=(Cutlery(name="fork"),))
with pytest.raises(TypeError) as execinfo:
- Household(silverware=Cutlery(name='fork'))
+ Household(silverware=Cutlery(name="fork"))
msg = "'silverware' must be a tuple but got Cutlery(name='fork')"
assert msg in str(execinfo.value)
with pytest.raises(TypeError) as execinfo:
- Household(silverware=(Cutlery(name='fork'), Door()))
+ Household(silverware=(Cutlery(name="fork"), Door()))
assert "'silverware' must be a tuple of " in str(execinfo.value)
msg = (
"but got (Cutlery(name='fork'), Door()) and item in index 1 is not"
@@ -42,19 +42,19 @@ def test_contents_after() -> None:
table = Table(
[
- TableRow([TableData(['Cutlery'])]),
- TableRow(['Spoons', '2']),
- TableRow(['Knifes', '5']),
- TableRow([TableData(['Bathroom'])]),
- TableRow(['Soap', '2']),
- TableRow(['Toothpaste', '1']),
+ TableRow([TableData(["Cutlery"])]),
+ TableRow(["Spoons", "2"]),
+ TableRow(["Knifes", "5"]),
+ TableRow([TableData(["Bathroom"])]),
+ TableRow(["Soap", "2"]),
+ TableRow(["Toothpaste", "1"]),
]
)
- assert table.contents_after('Bathroom') == (
- TableRow(['Soap', '2']),
- TableRow(['Toothpaste', '1']),
+ assert table.contents_after("Bathroom") == (
+ TableRow(["Soap", "2"]),
+ TableRow(["Toothpaste", "1"]),
)
- assert table.contents_after('Soap') == (TableRow(['Toothpaste', '1']),)
+ assert table.contents_after("Soap") == (TableRow(["Toothpaste", "1"]),)
def test_content_converter() -> None:
@@ -62,17 +62,17 @@ def test_content_converter() -> None:
table = Table(
[
- dict(tag='tr', contents=['1', 'Cutlery']), # type:ignore[list-item]
+ dict(tag="tr", contents=["1", "Cutlery"]), # type:ignore[list-item]
TableRow(
[
- '',
- 'Spoon',
+ "",
+ "Spoon",
dict( # type:ignore[list-item]
- tag='td',
+ tag="td",
contents=[
dict(
- tag='img',
- src='spoon.gif',
+ tag="img",
+ src="spoon.gif",
height=5,
width=10,
)
@@ -84,7 +84,7 @@ def test_content_converter() -> None:
)
assert table == Table(
[
- TableRow(['1', 'Cutlery']),
- TableRow(['', 'Spoon', TableData([Image(src='spoon.gif', height=5, width=10)])]),
+ TableRow(["1", "Cutlery"]),
+ TableRow(["", "Spoon", TableData([Image(src="spoon.gif", height=5, width=10)])]),
]
)
diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py
index ddeea80..ed2b78f 100644
--- a/tests/test_fixtures.py
+++ b/tests/test_fixtures.py
@@ -1,6 +1,6 @@
import os
-pytest_plugins = 'pytester'
+pytest_plugins = "pytester"
def test_port_fixture(testdir) -> None:
@@ -10,10 +10,10 @@ def test_port_fixture(testdir) -> None:
"""
import shutil
- shutil.copy(os.path.join(os.path.dirname(__file__), 'conftest.py'), str(testdir.tmpdir))
+ shutil.copy(os.path.join(os.path.dirname(__file__), "conftest.py"), str(testdir.tmpdir))
testdir.makepyfile(
- test_port='''
+ test_port="""
import pytest
def test_port(port) -> None:
@@ -23,7 +23,7 @@ def test_port(port) -> None:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
with pytest.raises(socket.error):
s.connect(('localhost', port_))
- '''
+ """
)
result = testdir.runpytest()
- result.stdout.fnmatch_lines(['*1 passed*'])
+ result.stdout.fnmatch_lines(["*1 passed*"])
diff --git a/tests/test_js_graph.py b/tests/test_js_graph.py
index 961da67..9785ef5 100644
--- a/tests/test_js_graph.py
+++ b/tests/test_js_graph.py
@@ -22,7 +22,7 @@ def test_resize_container(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('empty')
+ graph = graph_cases("empty")
width, height = graph.get_container_size()
new_width = width + 20
@@ -38,7 +38,7 @@ def test_insert_vertex(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1v')
+ graph = graph_cases("1v")
assert graph.get_vertex() is not None
@@ -46,7 +46,7 @@ def test_insert_vertex_with_zoom_and_scale(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('empty')
+ graph = graph_cases("empty")
x = 10
y = 20
w = 30
@@ -54,25 +54,25 @@ def test_insert_vertex_with_zoom_and_scale(graph_cases) -> None:
scale = 2
trans_x = 8
trans_y = 7
- graph.eval_js_function('api.setScaleAndTranslation', scale, trans_x, trans_y)
+ graph.eval_js_function("api.setScaleAndTranslation", scale, trans_x, trans_y)
# `adjustXYCcoordinates` value `undefined` defaults to `true`.
- graph.eval_js_function('api.insertVertex', x, y, w, h, '', '', {}, 'adjusted-1')
- graph.eval_js_function('api.insertVertex', x, y, w, h, '', '', {}, 'adjusted-2', True)
- adjusted1_bounds = graph.eval_js_function('api.getCellBounds', 'adjusted-1')
- adjusted2_bounds = graph.eval_js_function('api.getCellBounds', 'adjusted-2')
+ graph.eval_js_function("api.insertVertex", x, y, w, h, "", "", {}, "adjusted-1")
+ graph.eval_js_function("api.insertVertex", x, y, w, h, "", "", {}, "adjusted-2", True)
+ adjusted1_bounds = graph.eval_js_function("api.getCellBounds", "adjusted-1")
+ adjusted2_bounds = graph.eval_js_function("api.getCellBounds", "adjusted-2")
assert adjusted2_bounds == adjusted1_bounds
- assert adjusted1_bounds['x'] == (x / scale) - trans_x == -3
- assert adjusted1_bounds['y'] == (y / scale) - trans_y == 3
+ assert adjusted1_bounds["x"] == (x / scale) - trans_x == -3
+ assert adjusted1_bounds["y"] == (y / scale) - trans_y == 3
# When `adjustXYCcoordinates` is `false` values are taken on face value.
- graph.eval_js_function('api.insertVertex', x, y, w, h, '', '', {}, 'absolute', False)
- absolute_bounds = graph.eval_js_function('api.getCellBounds', 'absolute')
- assert absolute_bounds['x'] == x
- assert absolute_bounds['y'] == y
+ graph.eval_js_function("api.insertVertex", x, y, w, h, "", "", {}, "absolute", False)
+ absolute_bounds = graph.eval_js_function("api.getCellBounds", "absolute")
+ assert absolute_bounds["x"] == x
+ assert absolute_bounds["y"] == y
-@pytest.mark.parametrize('dumped,restored', [('1v', '2v'), ('2v', '1v')])
+@pytest.mark.parametrize("dumped,restored", [("1v", "2v"), ("2v", "1v")])
def test_dump_restore(dumped, restored, graph_cases) -> None:
"""
:type dumped: str
@@ -81,11 +81,11 @@ def test_dump_restore(dumped, restored, graph_cases) -> None:
"""
graph = graph_cases(dumped)
dumped_vertices_count = len(graph.get_vertices())
- dump = graph.eval_js_function('api.dump')
+ dump = graph.eval_js_function("api.dump")
del graph
graph = graph_cases(restored)
assert dumped_vertices_count != len(graph.get_vertices())
- graph.eval_js_function('api.restore', dump)
+ graph.eval_js_function("api.restore", dump)
assert dumped_vertices_count == len(graph.get_vertices())
@@ -93,7 +93,7 @@ def test_insert_vertex_with_style(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1v_style')
+ graph = graph_cases("1v_style")
vertex = graph.get_vertex()
# Can't have same color as default vertex style
@@ -102,25 +102,25 @@ def test_insert_vertex_with_style(graph_cases) -> None:
)
default = default.lower()
- assert vertex.get_attribute('fill') != default
+ assert vertex.get_attribute("fill") != default
@pytest.mark.parametrize(
- 'mode',
+ "mode",
[
- 'by_code',
- 'by_drag_drop',
+ "by_code",
+ "by_drag_drop",
],
)
def test_insert_edge(graph_cases, mode) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- if mode == 'by_code':
- case = '2v_1e'
+ if mode == "by_code":
+ case = "2v_1e"
else:
- assert mode == 'by_drag_drop'
- case = '2v_1eDD'
+ assert mode == "by_drag_drop"
+ case = "2v_1eDD"
graph = graph_cases(case)
assert graph.get_edge(*graph.get_vertices()) is not None
@@ -129,7 +129,7 @@ def test_get_terminal_points(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v_1e')
+ graph = graph_cases("2v_1e")
edge_id = graph.get_id(graph.get_edge(*graph.get_vertices()))
terminal_points = graph.eval_js_function("api.getEdgeTerminalPoints", edge_id)
(source_x, source_y), (target_x, target_y) = terminal_points
@@ -145,7 +145,7 @@ def test_insert_edge_error_endpoint_not_found(graph_cases, selenium_extras) -> N
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type selenium_extras: qmxgraph.tests.conftest.SeleniumExtras
"""
- graph = graph_cases('1v')
+ graph = graph_cases("1v")
vertex = graph.get_vertices()[0]
invalid_source_id = invalid_target_id = "999"
@@ -171,11 +171,11 @@ def test_insert_decoration(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v_1e_1d')
+ graph = graph_cases("2v_1e_1d")
assert len(graph.get_decorations()) == 1
graph.eval_js_function(
- 'api.insertDecorationOnEdge', graph.edge_id, 0.75, 10, 10, 'another decoration', 'purple'
+ "api.insertDecorationOnEdge", graph.edge_id, 0.75, 10, 10, "another decoration", "purple"
)
assert len(graph.get_decorations()) == 2
@@ -184,14 +184,14 @@ def test_decoration_position(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v_1e_1d')
+ graph = graph_cases("2v_1e_1d")
cell_id = graph.get_id(graph.get_decorations()[0])
- position = graph.eval_js_function('api.getDecorationPosition', cell_id)
+ position = graph.eval_js_function("api.getDecorationPosition", cell_id)
assert position == pytest.approx(0.4)
- graph.eval_js_function('api.setDecorationPosition', cell_id, 0.8)
- position = graph.eval_js_function('api.getDecorationPosition', cell_id)
+ graph.eval_js_function("api.setDecorationPosition", cell_id, 0.8)
+ position = graph.eval_js_function("api.getDecorationPosition", cell_id)
assert position == pytest.approx(0.8)
@@ -199,17 +199,17 @@ def test_get_decoration_parent_cell_id(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v_1e_1d')
+ graph = graph_cases("2v_1e_1d")
cell_id = graph.get_id(graph.get_decorations()[0])
- parent_id = graph.eval_js_function('api.getDecorationParentCellId', cell_id)
- assert parent_id == '4'
+ parent_id = graph.eval_js_function("api.getDecorationParentCellId", cell_id)
+ assert parent_id == "4"
def test_delete_vertex(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1v')
+ graph = graph_cases("1v")
graph.select_vertex(graph.get_vertex())
actions = ActionChains(graph.selenium)
@@ -224,7 +224,7 @@ def test_delete_edge(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v_1e')
+ graph = graph_cases("2v_1e")
graph.select_edge(graph.get_edge(*graph.get_vertices()))
actions = ActionChains(graph.selenium)
@@ -239,7 +239,7 @@ def test_group(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v')
+ graph = graph_cases("2v")
actions = ActionChains(graph.selenium)
actions.key_down(Keys.CONTROL)
@@ -256,7 +256,7 @@ def test_group(graph_cases) -> None:
# Group selected vertices
graph.selenium.execute_script("api.group()")
- group_fill = graph.host.styles['group']['fill_color']
+ group_fill = graph.host.styles["group"]["fill_color"]
group_selector = 'g>g>rect[fill="{}"]'.format(group_fill)
group = graph.selenium.find_elements(By.CSS_SELECTOR, group_selector)
assert len(group) == 1
@@ -277,11 +277,11 @@ def test_toggle_outline(selenium, host, wait_graph_page_ready) -> None:
# By default, outline starts hidden. Basically this means mxGraph's window
# component used to shown outline doesn't exist yet.
with pytest.raises(NoSuchElementException):
- selenium.find_element(By.CSS_SELECTOR, 'div.mxWindow')
+ selenium.find_element(By.CSS_SELECTOR, "div.mxWindow")
# Once shown, outline is displayed in a mxGraph's window component
selenium.execute_script("api.toggleOutline()")
- outline = selenium.find_element(By.CSS_SELECTOR, 'div.mxWindow')
+ outline = selenium.find_element(By.CSS_SELECTOR, "div.mxWindow")
assert outline is not None
# However once toggled back to hidden, it is not destroyed but simply
@@ -290,7 +290,7 @@ def test_toggle_outline(selenium, host, wait_graph_page_ready) -> None:
assert not outline.is_displayed()
-@pytest.mark.parametrize('grid', [True, False])
+@pytest.mark.parametrize("grid", [True, False])
def test_toggle_grid(selenium, host, grid, wait_graph_page_ready) -> None:
"""
:type selenium: selenium.webdriver.remote.webdriver.WebDriver
@@ -303,17 +303,17 @@ def test_toggle_grid(selenium, host, grid, wait_graph_page_ready) -> None:
if not grid:
selenium.execute_script("api.toggleGrid()")
- container = selenium.find_element(By.CSS_SELECTOR, 'div.graph')
- assert container.get_attribute('id') == 'graphContainer'
- assert container.get_attribute('class') == ('graph' if grid else 'graph hide-bg')
+ container = selenium.find_element(By.CSS_SELECTOR, "div.graph")
+ assert container.get_attribute("id") == "graphContainer"
+ assert container.get_attribute("class") == ("graph" if grid else "graph hide-bg")
-@pytest.mark.parametrize('snap', [True, False])
+@pytest.mark.parametrize("snap", [True, False])
def test_toggle_snap(graph_cases, snap) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1v')
+ graph = graph_cases("1v")
selenium = graph.selenium
# If snap is enabled, it should move to closest grid block (which are
@@ -339,30 +339,30 @@ def expected(v):
result = math.ceil(result / 10.0) * 10
return result
- assert int(vertex.get_attribute('width')) == w
- assert int(vertex.get_attribute('height')) == h
- assert int(vertex.get_attribute('x')) == expected(x)
- assert int(vertex.get_attribute('y')) == expected(y)
+ assert int(vertex.get_attribute("width")) == w
+ assert int(vertex.get_attribute("height")) == h
+ assert int(vertex.get_attribute("x")) == expected(x)
+ assert int(vertex.get_attribute("y")) == expected(y)
def test_get_cell_id_at(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v_1e_1d_1t')
+ graph = graph_cases("2v_1e_1d_1t")
# mxGraph shares a global id counter for all cell types. The first
# non-reserved id is 2, as lower values are used by internal control
# structures.
- assert graph.get_id(graph.get_vertices()[0]) == '2'
- assert graph.get_id(graph.get_vertices()[1]) == '3'
- assert graph.get_id(graph.get_edge(*graph.get_vertices())) == '4'
- assert graph.get_id(graph.get_decorations()[0]) == '5'
- assert graph.get_id(graph.get_tables()[0]) == '6'
+ assert graph.get_id(graph.get_vertices()[0]) == "2"
+ assert graph.get_id(graph.get_vertices()[1]) == "3"
+ assert graph.get_id(graph.get_edge(*graph.get_vertices())) == "4"
+ assert graph.get_id(graph.get_decorations()[0]) == "5"
+ assert graph.get_id(graph.get_tables()[0]) == "6"
class Invalid:
def __init__(self):
- self.location = {'x': 999, 'y': 999}
+ self.location = {"x": 999, "y": 999}
assert graph.get_id(Invalid()) is None
@@ -371,7 +371,7 @@ def test_set_visible(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v_1e_1d_1t')
+ graph = graph_cases("2v_1e_1d_1t")
# Hide then show vertex again
vertices = graph.get_vertices()
@@ -409,18 +409,18 @@ def test_is_and_set_port_visible(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1v_1p')
+ graph = graph_cases("1v_1p")
vertex_id = graph.get_id(graph.get_vertex())
- assert graph.eval_js_function('api.isPortVisible', vertex_id, 'foo')
+ assert graph.eval_js_function("api.isPortVisible", vertex_id, "foo")
assert graph.get_port() is not None
- graph.eval_js_function('api.setPortVisible', vertex_id, 'foo', False)
- assert not graph.eval_js_function('api.isPortVisible', vertex_id, 'foo')
+ graph.eval_js_function("api.setPortVisible", vertex_id, "foo", False)
+ assert not graph.eval_js_function("api.isPortVisible", vertex_id, "foo")
assert graph.get_port() is None
- graph.eval_js_function('api.setPortVisible', vertex_id, 'foo', True)
- assert graph.eval_js_function('api.isPortVisible', vertex_id, 'foo')
+ graph.eval_js_function("api.setPortVisible", vertex_id, "foo", True)
+ assert graph.eval_js_function("api.isPortVisible", vertex_id, "foo")
assert graph.get_port() is not None
@@ -428,9 +428,9 @@ def test_parse_port_id(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('empty')
- port_data = graph.eval_js_function('mxCell.parsePortId', 'qmxgraph-port-PARENT-PORT-NAME')
- assert port_data == ['PARENT', 'PORT-NAME']
+ graph = graph_cases("empty")
+ port_data = graph.eval_js_function("mxCell.parsePortId", "qmxgraph-port-PARENT-PORT-NAME")
+ assert port_data == ["PARENT", "PORT-NAME"]
def test_set_visible_error_not_found(graph_cases, selenium_extras) -> None:
@@ -438,8 +438,8 @@ def test_set_visible_error_not_found(graph_cases, selenium_extras) -> None:
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type selenium_extras: qmxgraph.tests.conftest.SeleniumExtras
"""
- graph = graph_cases('2v_1e_1d_1t')
- cell_id = '999'
+ graph = graph_cases("2v_1e_1d_1t")
+ cell_id = "999"
with pytest.raises(WebDriverException) as e:
graph.set_visible(cell_id, False)
@@ -456,7 +456,7 @@ def test_get_geometry_plain(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v_1e_1d_1t')
+ graph = graph_cases("2v_1e_1d_1t")
assert graph.get_geometry(graph.get_vertices()[0]) == [10, 10, 30, 30]
assert graph.get_geometry(graph.get_edge(*graph.get_vertices())) == [40, 25, 50, 1]
@@ -472,7 +472,7 @@ def test_get_geometry_error_not_found(graph_cases, selenium_extras) -> None:
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type selenium_extras: qmxgraph.tests.conftest.SeleniumExtras
"""
- graph = graph_cases('2v_1e_1d_1t')
+ graph = graph_cases("2v_1e_1d_1t")
cell_id = "999"
with pytest.raises(WebDriverException) as e:
@@ -485,13 +485,13 @@ def test_insert_table(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1t')
+ graph = graph_cases("1t")
assert len(graph.get_tables()) == 1
@pytest.mark.parametrize(
- 'action, expected_scale',
- [(None, 1.0), ('zoomIn', 1.2), ('zoomOut', 0.83)],
+ "action, expected_scale",
+ [(None, 1.0), ("zoomIn", 1.2), ("zoomOut", 0.83)],
)
def test_insert_child_table(graph_cases, action, expected_scale) -> None:
"""
@@ -501,19 +501,19 @@ def test_insert_child_table(graph_cases, action, expected_scale) -> None:
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1t')
+ graph = graph_cases("1t")
# Applying zoom, so it changes the scale and transformation
- obtained_scale = graph.eval_js_function('api.getZoomScale')
+ obtained_scale = graph.eval_js_function("api.getZoomScale")
assert obtained_scale == 1.0
- ini_scale, ini_x, ini_y = graph.eval_js_function('api.getScaleAndTranslation')
+ ini_scale, ini_x, ini_y = graph.eval_js_function("api.getScaleAndTranslation")
assert (ini_scale, ini_x, ini_y) == (1, 0, 0)
if action is not None:
- graph.eval_js_function('api.{}'.format(action))
- obtained_scale = graph.eval_js_function('api.getZoomScale')
+ graph.eval_js_function("api.{}".format(action))
+ obtained_scale = graph.eval_js_function("api.getZoomScale")
assert obtained_scale == expected_scale
- ini_scale, ini_x, ini_y = graph.eval_js_function('api.getScaleAndTranslation')
+ ini_scale, ini_x, ini_y = graph.eval_js_function("api.getScaleAndTranslation")
assert ini_scale != 1
assert ini_x != 0
assert ini_y != 0
@@ -522,19 +522,19 @@ def test_insert_child_table(graph_cases, action, expected_scale) -> None:
assert len(tables) == 1
parent_id = graph.get_id(tables[0])
child_id = graph.eval_js_function(
- 'api.insertTable', 0.5, 1.5, 300, {'contents': []}, 'foobar', None, None, parent_id
+ "api.insertTable", 0.5, 1.5, 300, {"contents": []}, "foobar", None, None, parent_id
)
tables = graph.get_tables()
assert len(tables) == 2
# After resetting the zoom, bounds of the tables must respect the
# constraints being tested below between parent and child bounds
- graph.eval_js_function('api.resetZoom')
- obtained_scale = graph.eval_js_function('api.getZoomScale')
+ graph.eval_js_function("api.resetZoom")
+ obtained_scale = graph.eval_js_function("api.getZoomScale")
assert obtained_scale == 1.0
def get_bounds(cell_id):
- return graph.eval_js_function('api.getGeometry', cell_id)
+ return graph.eval_js_function("api.getGeometry", cell_id)
parent_bounds = get_bounds(parent_id)
child_bounds = get_bounds(child_id)
@@ -546,23 +546,23 @@ def test_table_with_image(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1t')
+ graph = graph_cases("1t")
tables = graph.get_tables()
assert len(tables) == 1
table_id = graph.get_id(tables[0])
contents = { # graphs.utils.TableRowDescription
- 'contents': [
+ "contents": [
{ # graphs.utils.TableDataDescription
- 'contents': [
+ "contents": [
{ # graphs.utils.TableDataDescription
- 'contents': [
- 'foo ',
+ "contents": [
+ "foo ",
{
- 'tag': 'img',
- 'src': 'some-image-path',
- 'width': 16,
- 'height': 16,
+ "tag": "img",
+ "src": "some-image-path",
+ "width": 16,
+ "height": 16,
},
]
}
@@ -570,34 +570,34 @@ def test_table_with_image(graph_cases) -> None:
}
]
}
- graph.eval_js_function('api.updateTable', table_id, contents, '')
+ graph.eval_js_function("api.updateTable", table_id, contents, "")
- image_elements = graph.selenium.find_elements(By.CSS_SELECTOR, '.table-cell-contents img')
+ image_elements = graph.selenium.find_elements(By.CSS_SELECTOR, ".table-cell-contents img")
assert len(image_elements) == 1
image = image_elements[0]
- assert image.get_attribute('src').endswith('some-image-path')
+ assert image.get_attribute("src").endswith("some-image-path")
def test_update_table(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1t')
+ graph = graph_cases("1t")
table_id = graph.get_id(graph.get_tables()[0])
contents = { # graphs.utils.TableDescription
- 'contents': [
+ "contents": [
# graphs.utils.TableRowDescription's
- {'contents': ['a', 1]},
- {'contents': ['b', 2]},
+ {"contents": ["a", 1]},
+ {"contents": ["b", 2]},
]
}
- title = 'updated'
- graph.selenium.execute_script(js.prepare_js_call('api.updateTable', table_id, contents, title))
+ title = "updated"
+ graph.selenium.execute_script(js.prepare_js_call("api.updateTable", table_id, contents, title))
table = graph.get_tables()[0]
- assert graph.get_table_title(table) == 'updated'
- assert graph.get_table_contents(table) == ['a', '1', 'b', '2']
+ assert graph.get_table_title(table) == "updated"
+ assert graph.get_table_contents(table) == ["a", "1", "b", "2"]
def test_update_table_error_not_found(graph_cases, selenium_extras) -> None:
@@ -605,15 +605,15 @@ def test_update_table_error_not_found(graph_cases, selenium_extras) -> None:
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type selenium_extras: qmxgraph.tests.conftest.SeleniumExtras
"""
- graph = graph_cases('1t')
+ graph = graph_cases("1t")
table_id = "999"
contents: List[Any] = []
- title = 'will not matter'
+ title = "will not matter"
with pytest.raises(WebDriverException) as e:
graph.selenium.execute_script(
- js.prepare_js_call('api.updateTable', table_id, contents, title)
+ js.prepare_js_call("api.updateTable", table_id, contents, title)
)
assert f"Unable to find cell with id {table_id}" in selenium_extras.get_exception_message(e)
@@ -624,15 +624,15 @@ def test_update_table_error_not_table(graph_cases, selenium_extras) -> None:
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type selenium_extras: qmxgraph.tests.conftest.SeleniumExtras
"""
- graph = graph_cases('2v_1e_1d_1t')
+ graph = graph_cases("2v_1e_1d_1t")
table_id = graph.get_id(graph.get_edge(*graph.get_vertices()))
contents: List[Any] = []
- title = 'will not matter'
+ title = "will not matter"
with pytest.raises(WebDriverException) as e:
graph.selenium.execute_script(
- js.prepare_js_call('api.updateTable', table_id, contents, title)
+ js.prepare_js_call("api.updateTable", table_id, contents, title)
)
assert "Cell is not a table" in selenium_extras.get_exception_message(e)
@@ -642,14 +642,14 @@ def test_remove_cells(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v_1e')
+ graph = graph_cases("2v_1e")
vertices = graph.get_vertices()
cell_ids = [
graph.get_id(vertices[0]),
graph.get_id(graph.get_edge(*vertices)),
]
- graph.eval_js_function('api.removeCells', cell_ids)
+ graph.eval_js_function("api.removeCells", cell_ids)
assert len(graph.get_vertices()) == 1
assert graph.get_edge(*vertices) is None
@@ -660,11 +660,11 @@ def test_remove_cells_error_not_found(graph_cases, selenium_extras) -> None:
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type selenium_extras: qmxgraph.tests.conftest.SeleniumExtras
"""
- graph = graph_cases('empty')
+ graph = graph_cases("empty")
cell_id = 999
with pytest.raises(WebDriverException) as e:
- graph.eval_js_function('api.removeCells', [cell_id])
+ graph.eval_js_function("api.removeCells", [cell_id])
assert f"Unable to find cell with id {cell_id}" in selenium_extras.get_exception_message(e)
@@ -673,18 +673,18 @@ def test_on_cells_removed(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v_1e')
+ graph = graph_cases("2v_1e")
- graph.selenium.execute_script('callback = function(cellIds) {window.cellIds = cellIds;}')
- graph.eval_js_function('api.registerCellsRemovedHandler', js.Variable('callback'))
+ graph.selenium.execute_script("callback = function(cellIds) {window.cellIds = cellIds;}")
+ graph.eval_js_function("api.registerCellsRemovedHandler", js.Variable("callback"))
cell_ids = [
graph.get_id(graph.get_vertices()[0]),
graph.get_id(graph.get_edge(*graph.get_vertices())),
]
- graph.eval_js_function('api.removeCells', cell_ids)
+ graph.eval_js_function("api.removeCells", cell_ids)
- assert graph.selenium.execute_script('return window.cellIds') == cell_ids
+ assert graph.selenium.execute_script("return window.cellIds") == cell_ids
def test_custom_shapes(selenium, port, tmpdir, wait_graph_page_ready) -> None:
@@ -693,7 +693,7 @@ def test_custom_shapes(selenium, port, tmpdir, wait_graph_page_ready) -> None:
:type port: qmxgraph.tests.conftest.Port
"""
# Shape found in by https://www.draw.io/stencils/basic.xml
- custom_stencil = '''\
+ custom_stencil = """\
@@ -712,7 +712,7 @@ def test_custom_shapes(selenium, port, tmpdir, wait_graph_page_ready) -> None:
-''' # noqa
+""" # noqa
stencil_file = tmpdir.mkdir("stencils").join("custom.xml")
stencil_file.write(custom_stencil)
@@ -720,9 +720,9 @@ def test_custom_shapes(selenium, port, tmpdir, wait_graph_page_ready) -> None:
styles = GraphStyles(
{
- 'moon': {
- 'shape': 'Moon',
- 'fill_color': '#ffff00',
+ "moon": {
+ "shape": "Moon",
+ "fill_color": "#ffff00",
},
}
)
@@ -738,10 +738,10 @@ def has_custom_shape():
@pytest.mark.parametrize(
- 'mode',
+ "mode",
[
- 'by_code',
- 'by_drag_drop',
+ "by_code",
+ "by_drag_drop",
],
)
def test_edge_with_style(port, mode, graph_cases_factory) -> None:
@@ -752,28 +752,28 @@ def test_edge_with_style(port, mode, graph_cases_factory) -> None:
"""
styles = GraphStyles(
{
- 'edge': {
- 'stroke_color': '#000000',
+ "edge": {
+ "stroke_color": "#000000",
},
}
)
with server.host(port=port.get(), styles=styles) as host:
cases = graph_cases_factory(host)
- graph = cases('2v_1e' if mode == 'by_code' else '2v_1eDD')
- assert graph.get_edge(*graph.get_vertices()).get_attribute('stroke') == '#000000'
+ graph = cases("2v_1e" if mode == "by_code" else "2v_1eDD")
+ assert graph.get_edge(*graph.get_vertices()).get_attribute("stroke") == "#000000"
def test_get_label(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v_1e_1d_1t')
+ graph = graph_cases("2v_1e_1d_1t")
- assert graph.get_label(graph.get_vertices()[0]) == 'foo'
- assert graph.get_label(graph.get_vertices()[1]) == 'bar'
- assert graph.get_label(graph.get_edge(*graph.get_vertices())) == 'edge'
- assert graph.get_label(graph.get_decorations()[0]) == 'decoration'
+ assert graph.get_label(graph.get_vertices()[0]) == "foo"
+ assert graph.get_label(graph.get_vertices()[1]) == "bar"
+ assert graph.get_label(graph.get_edge(*graph.get_vertices())) == "edge"
+ assert graph.get_label(graph.get_decorations()[0]) == "decoration"
# Tables use a complex label in HTML
table_label = graph.get_label(graph.get_tables()[0])
@@ -798,7 +798,7 @@ def handle_data(self, data):
parser = TableHTMLParser()
parser.feed(table_label)
- assert table_html_data == ['Hitchhikers', 'arthur', 'dent', 'ford', 'prefect']
+ assert table_html_data == ["Hitchhikers", "arthur", "dent", "ford", "prefect"]
def test_get_label_error_not_found(graph_cases, selenium_extras) -> None:
@@ -806,7 +806,7 @@ def test_get_label_error_not_found(graph_cases, selenium_extras) -> None:
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type selenium_extras: qmxgraph.tests.conftest.SeleniumExtras
"""
- graph = graph_cases('2v_1e_1d_1t')
+ graph = graph_cases("2v_1e_1d_1t")
cell_id = "999"
with pytest.raises(WebDriverException) as e:
@@ -819,7 +819,7 @@ def test_has_cell(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('empty')
+ graph = graph_cases("empty")
cell_id = graph.insert_vertex(x=10, y=10)
assert graph.eval_js_function("api.hasCell", cell_id)
@@ -831,11 +831,11 @@ def test_get_cell_type(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v_1e_1d_1t')
+ graph = graph_cases("2v_1e_1d_1t")
def get_cell_type(web_element):
cell_id = graph.get_id(web_element)
- return graph.eval_js_function('api.getCellType', cell_id)
+ return graph.eval_js_function("api.getCellType", cell_id)
assert get_cell_type(graph.get_vertices()[0]) == constants.CELL_TYPE_VERTEX
@@ -851,7 +851,7 @@ def test_get_cell_type_error_not_found(graph_cases, selenium_extras) -> None:
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type selenium_extras: qmxgraph.tests.conftest.SeleniumExtras
"""
- graph = graph_cases('empty')
+ graph = graph_cases("empty")
cell_id = "999"
@@ -862,7 +862,7 @@ def test_get_cell_type_error_not_found(graph_cases, selenium_extras) -> None:
@pytest.mark.parametrize(
- 'cell_type',
+ "cell_type",
[
qmxgraph.constants.CELL_TYPE_VERTEX,
qmxgraph.constants.CELL_TYPE_EDGE,
@@ -875,33 +875,33 @@ def test_insert_with_tags(graph_cases, cell_type) -> None:
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type cell_type: qmxgraph.constants.CELL_TYPE_*
"""
- graph = graph_cases('empty')
+ graph = graph_cases("empty")
# Listen to on cells added event to be sure tags are already configured
# as soon as cell is created
graph.selenium.execute_script(
- 'callback = function(cellIds) {'
- ' window.tags = cellIds.map('
- ' function(cellId) {'
+ "callback = function(cellIds) {"
+ " window.tags = cellIds.map("
+ " function(cellId) {"
' return api.hasTag(cellId, "tagTest")? api.getTag(cellId, "tagTest") : null;' # noqa
- ' }'
- ' );'
- '}'
+ " }"
+ " );"
+ "}"
)
- graph.eval_js_function('api.registerCellsAddedHandler', js.Variable('callback'))
- tags = {'tagTest': '1'}
+ graph.eval_js_function("api.registerCellsAddedHandler", js.Variable("callback"))
+ tags = {"tagTest": "1"}
cell_id = insert_by_parametrized_type(graph, cell_type, tags=tags)
assert (
graph.selenium.execute_script("return api.getTag({}, 'tagTest')".format(cell_id))
- == tags['tagTest']
+ == tags["tagTest"]
)
- assert graph.selenium.execute_script('return window.tags') == [tags['tagTest']]
+ assert graph.selenium.execute_script("return window.tags") == [tags["tagTest"]]
@pytest.mark.parametrize(
- 'cell_type',
+ "cell_type",
[
qmxgraph.constants.CELL_TYPE_VERTEX,
qmxgraph.constants.CELL_TYPE_EDGE,
@@ -915,7 +915,7 @@ def test_insert_with_tags_error_value_not_string(graph_cases, cell_type, seleniu
:type cell_type: qmxgraph.constants.CELL_TYPE_*
:type selenium_extras: qmxgraph.tests.conftest.SeleniumExtras
"""
- graph = graph_cases('empty')
+ graph = graph_cases("empty")
tag_name = "tagTest"
tags = {tag_name: 999}
@@ -927,7 +927,7 @@ def test_insert_with_tags_error_value_not_string(graph_cases, cell_type, seleniu
@pytest.mark.parametrize(
- 'cell_type',
+ "cell_type",
[
qmxgraph.constants.CELL_TYPE_VERTEX,
qmxgraph.constants.CELL_TYPE_EDGE,
@@ -940,7 +940,7 @@ def test_set_get_tag(graph_cases, cell_type) -> None:
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type cell_type: qmxgraph.constants.CELL_TYPE_*
"""
- graph = graph_cases('empty')
+ graph = graph_cases("empty")
cell_id = insert_by_parametrized_type(graph, cell_type)
@@ -951,7 +951,7 @@ def test_set_get_tag(graph_cases, cell_type) -> None:
@pytest.mark.parametrize(
- 'cell_type',
+ "cell_type",
[
qmxgraph.constants.CELL_TYPE_VERTEX,
qmxgraph.constants.CELL_TYPE_EDGE,
@@ -965,7 +965,7 @@ def test_set_get_tag_error_tag_not_found(graph_cases, cell_type, selenium_extras
:type cell_type: qmxgraph.constants.CELL_TYPE_*
:type selenium_extras: qmxgraph.tests.conftest.SeleniumExtras
"""
- graph = graph_cases('empty')
+ graph = graph_cases("empty")
cell_id = insert_by_parametrized_type(graph, cell_type)
tag_name = "test"
@@ -981,7 +981,7 @@ def test_set_get_tag_error_tag_not_found(graph_cases, cell_type, selenium_extras
@pytest.mark.parametrize(
- 'cell_type',
+ "cell_type",
[
qmxgraph.constants.CELL_TYPE_VERTEX,
qmxgraph.constants.CELL_TYPE_EDGE,
@@ -995,7 +995,7 @@ def test_set_get_tag_error_value_not_string(graph_cases, cell_type, selenium_ext
:type cell_type: qmxgraph.constants.CELL_TYPE_*
:type selenium_extras: qmxgraph.tests.conftest.SeleniumExtras
"""
- graph = graph_cases('empty')
+ graph = graph_cases("empty")
cell_id = insert_by_parametrized_type(graph, cell_type)
tag_name = "test"
@@ -1007,7 +1007,7 @@ def test_set_get_tag_error_value_not_string(graph_cases, cell_type, selenium_ext
@pytest.mark.parametrize(
- 'cell_type',
+ "cell_type",
[
qmxgraph.constants.CELL_TYPE_VERTEX,
qmxgraph.constants.CELL_TYPE_EDGE,
@@ -1020,7 +1020,7 @@ def test_set_get_tag_doesnt_overwrite_protected_tags(graph_cases, cell_type) ->
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type cell_type: qmxgraph.constants.CELL_TYPE_*
"""
- graph = graph_cases('empty')
+ graph = graph_cases("empty")
cell_id = insert_by_parametrized_type(graph, cell_type)
assert not graph.eval_js_function("api.hasTag", cell_id, "label")
@@ -1036,7 +1036,7 @@ def test_set_get_tag_error_cell_not_found(graph_cases, selenium_extras) -> None:
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type selenium_extras: qmxgraph.tests.conftest.SeleniumExtras
"""
- graph = graph_cases('empty')
+ graph = graph_cases("empty")
cell_id = "999"
@@ -1069,7 +1069,7 @@ def test_set_get_tag_without_initial_tag_support(graph_cases) -> None:
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v')
+ graph = graph_cases("2v")
graph.insert_edge_by_drag_drop(*graph.get_vertices())
edge = graph.get_edge(*graph.get_vertices())
@@ -1085,7 +1085,7 @@ def test_on_cells_added(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v_1e_1d_1t')
+ graph = graph_cases("2v_1e_1d_1t")
added = [
graph.get_id(graph.get_vertices()[0]),
@@ -1102,53 +1102,53 @@ def test_on_label_changed(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1v')
+ graph = graph_cases("1v")
vertex_id = graph.get_id(graph.get_vertex())
# Sanity check: custom tags are internally stored in same node element as
# label. This is to make sure tags aren't lost when label is changed by
# mistakenly overwriting whole node element instead of just label.
- graph.eval_js_function('api.setTag', vertex_id, 'test', 'test')
+ graph.eval_js_function("api.setTag", vertex_id, "test", "test")
label = graph.get_label(graph.get_vertex())
label_element = graph.get_label_element(graph.get_vertex())
actions = ActionChains(graph.selenium)
actions.double_click(label_element)
- actions.send_keys('foo')
+ actions.send_keys("foo")
actions.click(graph.get_container()) # to lose focus and confirm
actions.perform()
- assert graph.get_label(graph.get_vertex()) == 'foo'
+ assert graph.get_label(graph.get_vertex()) == "foo"
label_changes = graph.get_label_changes()
assert label_changes == [
{
- 'cellId': vertex_id,
- 'newLabel': 'foo',
- 'oldLabel': label,
+ "cellId": vertex_id,
+ "newLabel": "foo",
+ "oldLabel": label,
}
]
- assert graph.eval_js_function('api.getTag', vertex_id, 'test') == 'test'
+ assert graph.eval_js_function("api.getTag", vertex_id, "test") == "test"
def test_set_label(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1v')
+ graph = graph_cases("1v")
vertex_id = graph.get_id(graph.get_vertex())
label = graph.get_label(graph.get_vertex())
- graph.eval_js_function('api.setLabel', vertex_id, 'foo')
+ graph.eval_js_function("api.setLabel", vertex_id, "foo")
- assert graph.get_label(graph.get_vertex()) == 'foo'
+ assert graph.get_label(graph.get_vertex()) == "foo"
label_changes = graph.get_label_changes()
assert label_changes == [
{
- 'cellId': vertex_id,
- 'newLabel': 'foo',
- 'oldLabel': label,
+ "cellId": vertex_id,
+ "newLabel": "foo",
+ "oldLabel": label,
}
]
@@ -1162,7 +1162,7 @@ def test_set_label_error_not_found(graph_cases, selenium_extras) -> None:
cell_id = "999"
with pytest.raises(WebDriverException) as e:
- graph.eval_js_function('api.setLabel', cell_id, 'foo')
+ graph.eval_js_function("api.setLabel", cell_id, "foo")
assert f"Unable to find cell with id {cell_id}" in selenium_extras.get_exception_message(e)
@@ -1171,24 +1171,24 @@ def test_set_double_click_handler(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1v')
+ graph = graph_cases("1v")
vertex_id = graph.get_id(graph.get_vertex())
graph.selenium.execute_script(
- 'callback = function(cellId) {'
- ' if (!window.__dblClick__) {'
- ' window.__dblClick__ = [];'
- ' }'
- ' window.__dblClick__.push(cellId);'
- '}'
+ "callback = function(cellId) {"
+ " if (!window.__dblClick__) {"
+ " window.__dblClick__ = [];"
+ " }"
+ " window.__dblClick__.push(cellId);"
+ "}"
)
- graph.eval_js_function('api.registerDoubleClickHandler', qmxgraph.js.Variable('callback'))
+ graph.eval_js_function("api.registerDoubleClickHandler", qmxgraph.js.Variable("callback"))
actions = ActionChains(graph.selenium)
actions.double_click(graph.get_vertex())
actions.perform()
- assert graph.selenium.execute_script('return window.__dblClick__') == [vertex_id]
+ assert graph.selenium.execute_script("return window.__dblClick__") == [vertex_id]
def test_add_selection_change_handler(graph_cases) -> None:
@@ -1196,19 +1196,19 @@ def test_add_selection_change_handler(graph_cases) -> None:
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v_1e')
+ graph = graph_cases("2v_1e")
source, target = graph.get_vertices()
edge = graph.get_edge(source, target)
graph.selenium.execute_script(
- 'callback = function(cellIds) {'
- ' if (!window.__selectionChange__) {'
- ' window.__selectionChange__ = [];'
- ' }'
- ' window.__selectionChange__.push(cellIds);'
- '}'
+ "callback = function(cellIds) {"
+ " if (!window.__selectionChange__) {"
+ " window.__selectionChange__ = [];"
+ " }"
+ " window.__selectionChange__.push(cellIds);"
+ "}"
)
- graph.eval_js_function('api.registerSelectionChangedHandler', qmxgraph.js.Variable('callback'))
+ graph.eval_js_function("api.registerSelectionChangedHandler", qmxgraph.js.Variable("callback"))
# Select all cells.
actions = ActionChains(graph.selenium)
@@ -1219,26 +1219,26 @@ def test_add_selection_change_handler(graph_cases) -> None:
actions.key_up(Keys.CONTROL)
actions.perform()
- fired_selection_events = graph.selenium.execute_script('return window.__selectionChange__')
+ fired_selection_events = graph.selenium.execute_script("return window.__selectionChange__")
assert fired_selection_events == [
- ['2'],
- ['3', '2'],
- ['4', '3', '2'],
+ ["2"],
+ ["3", "2"],
+ ["4", "3", "2"],
]
- assert graph.eval_js_function('api.getSelectedCells') == ['4', '3', '2']
+ assert graph.eval_js_function("api.getSelectedCells") == ["4", "3", "2"]
# Programmatically select one cell.
- graph.eval_js_function('api.setSelectedCells', ['3'])
+ graph.eval_js_function("api.setSelectedCells", ["3"])
# Clear selection.
- graph.eval_js_function('api.setSelectedCells', [])
+ graph.eval_js_function("api.setSelectedCells", [])
- fired_selection_events = graph.selenium.execute_script('return window.__selectionChange__')
+ fired_selection_events = graph.selenium.execute_script("return window.__selectionChange__")
assert fired_selection_events == [
- ['2'],
- ['3', '2'],
- ['4', '3', '2'],
- ['3'],
+ ["2"],
+ ["3", "2"],
+ ["4", "3", "2"],
+ ["3"],
[],
]
@@ -1247,33 +1247,33 @@ def test_set_popup_menu_handler(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1v')
+ graph = graph_cases("1v")
vertex_id = graph.get_id(graph.get_vertex())
graph.selenium.execute_script(
- 'callback = function(cellId, x, y) {'
- ' if (!window.__popupMenu__) {'
- ' window.__popupMenu__ = [];'
- ' }'
- ' window.__popupMenu__.push([cellId, x, y]);'
- '}'
+ "callback = function(cellId, x, y) {"
+ " if (!window.__popupMenu__) {"
+ " window.__popupMenu__ = [];"
+ " }"
+ " window.__popupMenu__.push([cellId, x, y]);"
+ "}"
)
- graph.eval_js_function('api.registerPopupMenuHandler', qmxgraph.js.Variable('callback'))
+ graph.eval_js_function("api.registerPopupMenuHandler", qmxgraph.js.Variable("callback"))
vertex_label_el = graph.get_label_element(graph.get_vertex())
actions = ActionChains(graph.selenium)
actions.context_click(vertex_label_el)
actions.perform()
- x = vertex_label_el.location['x'] + vertex_label_el.size['width'] // 2
- y = vertex_label_el.location['y'] + vertex_label_el.size['height'] // 2
- assert graph.selenium.execute_script('return window.__popupMenu__') == [[vertex_id, x, y]]
+ x = vertex_label_el.location["x"] + vertex_label_el.size["width"] // 2
+ y = vertex_label_el.location["y"] + vertex_label_el.size["height"] // 2
+ assert graph.selenium.execute_script("return window.__popupMenu__") == [[vertex_id, x, y]]
@pytest.mark.parametrize(
- 'action, expected_scale',
- [('zoomIn', 1.2), ('zoomOut', 0.83)],
+ "action, expected_scale",
+ [("zoomIn", 1.2), ("zoomOut", 0.83)],
)
def test_zoom(graph_cases, action, expected_scale) -> None:
"""
@@ -1281,30 +1281,30 @@ def test_zoom(graph_cases, action, expected_scale) -> None:
:type action: str
:type expected_scale: float
"""
- graph = graph_cases('2v_1e')
- obtained_scale = graph.eval_js_function('api.getZoomScale')
+ graph = graph_cases("2v_1e")
+ obtained_scale = graph.eval_js_function("api.getZoomScale")
assert obtained_scale == 1.0
- graph.eval_js_function('api.{}'.format(action))
- obtained_scale = graph.eval_js_function('api.getZoomScale')
+ graph.eval_js_function("api.{}".format(action))
+ obtained_scale = graph.eval_js_function("api.getZoomScale")
assert obtained_scale == expected_scale
- graph.eval_js_function('api.resetZoom')
- obtained_scale = graph.eval_js_function('api.getZoomScale')
+ graph.eval_js_function("api.resetZoom")
+ obtained_scale = graph.eval_js_function("api.getZoomScale")
assert obtained_scale == 1.0
@pytest.mark.xfail(
'sys.platform != "win32"',
- reason='need investigate differences between linux and windows',
+ reason="need investigate differences between linux and windows",
)
def test_set_scale_and_translation(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1v')
+ graph = graph_cases("1v")
- ini_scale, ini_x, ini_y = graph.eval_js_function('api.getScaleAndTranslation')
+ ini_scale, ini_x, ini_y = graph.eval_js_function("api.getScaleAndTranslation")
assert (ini_scale, ini_x, ini_y) == (1, 0, 0)
from selenium.webdriver.common.actions.mouse_button import MouseButton
@@ -1323,7 +1323,7 @@ def click_and_hold_right(self, on_element=None):
if on_element:
self.move_to_element(on_element)
self._actions.append(
- lambda: self._driver.execute(Command.MOUSE_DOWN, {'button': 2})
+ lambda: self._driver.execute(Command.MOUSE_DOWN, {"button": 2})
)
return self
@@ -1334,14 +1334,14 @@ def release_right(self, on_element=None):
self.w3c_actions.pointer_action.pointer_up(MouseButton.RIGHT)
self.w3c_actions.key_action.pause()
else:
- self._actions.append(lambda: self._driver.execute(Command.MOUSE_UP, {'button': 2}))
+ self._actions.append(lambda: self._driver.execute(Command.MOUSE_UP, {"button": 2}))
return self
vertex = graph.get_vertex()
w, h = graph.get_vertex_size(vertex)
def ScaleAndTranslateGraph():
- graph.eval_js_function('api.zoomIn')
+ graph.eval_js_function("api.zoomIn")
actions = MyActionChains(graph.selenium)
actions.move_to_element_with_offset(vertex, w * 2, h * 2)
@@ -1350,39 +1350,39 @@ def ScaleAndTranslateGraph():
actions.release_right() # mxgraph does some extra work on release.
actions.perform()
- graph.eval_js_function('api.zoomIn')
+ graph.eval_js_function("api.zoomIn")
ScaleAndTranslateGraph()
- saved_scale, saved_x, saved_y = graph.eval_js_function('api.getScaleAndTranslation')
+ saved_scale, saved_x, saved_y = graph.eval_js_function("api.getScaleAndTranslation")
assert saved_scale == pytest.approx(1.44, abs=2)
assert saved_x == pytest.approx(-36.11, abs=2)
assert saved_y == pytest.approx(60.42, abs=2)
ScaleAndTranslateGraph()
- new_scale, new_x, new_y = graph.eval_js_function('api.getScaleAndTranslation')
+ new_scale, new_x, new_y = graph.eval_js_function("api.getScaleAndTranslation")
assert new_scale == pytest.approx(2.08, abs=2)
assert new_x == pytest.approx(-61.50, abs=2)
assert new_y == pytest.approx(97.28, abs=2)
- graph.eval_js_function('api.setScaleAndTranslation', saved_scale, saved_x, saved_y)
- scale, x, y = graph.eval_js_function('api.getScaleAndTranslation')
+ graph.eval_js_function("api.setScaleAndTranslation", saved_scale, saved_x, saved_y)
+ scale, x, y = graph.eval_js_function("api.getScaleAndTranslation")
assert (scale, x, y) == (saved_scale, saved_x, saved_y)
-@pytest.mark.parametrize('action', [None, 'zoomIn', 'zoomOut'])
+@pytest.mark.parametrize("action", [None, "zoomIn", "zoomOut"])
def test_fit(graph_cases, action) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type action: Optional[str]
"""
- graph = graph_cases('2v_1e')
- obtained_scale = graph.eval_js_function('api.getZoomScale')
+ graph = graph_cases("2v_1e")
+ obtained_scale = graph.eval_js_function("api.getZoomScale")
assert obtained_scale == 1.0
if action is not None:
- graph.eval_js_function('api.{}'.format(action))
+ graph.eval_js_function("api.{}".format(action))
- graph.eval_js_function('api.fit')
- obtained_scale = graph.eval_js_function('api.getZoomScale')
+ graph.eval_js_function("api.fit")
+ obtained_scale = graph.eval_js_function("api.getZoomScale")
assert obtained_scale == pytest.approx(3.14, abs=2)
@@ -1390,29 +1390,29 @@ def test_get_edge_terminals(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('2v_1e')
+ graph = graph_cases("2v_1e")
source, target = graph.get_vertices()
edge = graph.get_edge(source, target)
- source_id, target_id = graph.eval_js_function('api.getEdgeTerminals', graph.get_id(edge))
+ source_id, target_id = graph.eval_js_function("api.getEdgeTerminals", graph.get_id(edge))
assert source_id == graph.get_id(source)
assert target_id == graph.get_id(target)
-@pytest.mark.parametrize('terminal_type', ['source', 'target'])
+@pytest.mark.parametrize("terminal_type", ["source", "target"])
def test_set_edge_terminals(graph_cases, terminal_type) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type terminal_type: str
"""
- graph = graph_cases('3v_1e')
- graph.eval_js_function('api.setEdgeTerminal', graph.edge_id, terminal_type, graph.vertex3_id)
+ graph = graph_cases("3v_1e")
+ graph.eval_js_function("api.setEdgeTerminal", graph.edge_id, terminal_type, graph.vertex3_id)
- source_id, target_id = graph.eval_js_function('api.getEdgeTerminals', graph.edge_id)
- if terminal_type == 'source':
+ source_id, target_id = graph.eval_js_function("api.getEdgeTerminals", graph.edge_id)
+ if terminal_type == "source":
assert source_id == graph.vertex3_id
assert target_id == graph.target_id
- elif terminal_type == 'target':
+ elif terminal_type == "target":
assert source_id == graph.source_id
assert target_id == graph.vertex3_id
else:
@@ -1423,41 +1423,41 @@ def test_set_get_style(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1v')
+ graph = graph_cases("1v")
vertices = graph.get_vertices()
assert len(vertices) == 1
vertex_id = graph.get_id(vertices[0])
- style = graph.eval_js_function('api.getStyle', vertex_id)
+ style = graph.eval_js_function("api.getStyle", vertex_id)
assert style is None
- graph.eval_js_function('api.setStyle', vertex_id, 'foo')
- style = graph.eval_js_function('api.getStyle', vertex_id)
- assert style == 'foo'
+ graph.eval_js_function("api.setStyle", vertex_id, "foo")
+ style = graph.eval_js_function("api.getStyle", vertex_id)
+ assert style == "foo"
with pytest.raises(WebDriverException) as excinfo:
- graph.eval_js_function('api.getStyle', 'nonexistent')
- assert 'Unable to find cell with id nonexistent' in str(excinfo.value)
+ graph.eval_js_function("api.getStyle", "nonexistent")
+ assert "Unable to find cell with id nonexistent" in str(excinfo.value)
def test_set_get_connectable(graph_cases) -> None:
"""
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
"""
- graph = graph_cases('1v')
+ graph = graph_cases("1v")
vertices = graph.get_vertices()
assert len(vertices) == 1
vertex_id = graph.get_id(vertices[0])
- connectable = graph.eval_js_function('api.isConnectable', vertex_id)
+ connectable = graph.eval_js_function("api.isConnectable", vertex_id)
assert connectable
- graph.eval_js_function('api.setConnectable', vertex_id, False)
- connectable = graph.eval_js_function('api.isConnectable', vertex_id)
+ graph.eval_js_function("api.setConnectable", vertex_id, False)
+ connectable = graph.eval_js_function("api.isConnectable", vertex_id)
assert not connectable
- graph.eval_js_function('api.setConnectable', vertex_id, True)
- connectable = graph.eval_js_function('api.isConnectable', vertex_id)
+ graph.eval_js_function("api.setConnectable", vertex_id, True)
+ connectable = graph.eval_js_function("api.isConnectable", vertex_id)
assert connectable
@@ -1466,12 +1466,12 @@ def test_get_edge_terminals_error_edge_not_found(graph_cases, selenium_extras) -
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type selenium_extras: qmxgraph.tests.conftest.SeleniumExtras
"""
- graph = graph_cases('empty')
+ graph = graph_cases("empty")
edge_id = "999"
with pytest.raises(WebDriverException) as e:
- graph.eval_js_function('api.getEdgeTerminals', edge_id)
+ graph.eval_js_function("api.getEdgeTerminals", edge_id)
assert f"Unable to find edge with id {edge_id}" in selenium_extras.get_exception_message(e)
@@ -1481,11 +1481,11 @@ def test_get_edge_terminals_error_not_an_edge(graph_cases, selenium_extras) -> N
:type graph_cases: qmxgraph.tests.conftest.GraphCaseFactory
:type selenium_extras: qmxgraph.tests.conftest.SeleniumExtras
"""
- graph = graph_cases('1v')
+ graph = graph_cases("1v")
vertex = graph.get_vertices()[0]
with pytest.raises(WebDriverException) as e:
- graph.eval_js_function('api.getEdgeTerminals', graph.get_id(vertex))
+ graph.eval_js_function("api.getEdgeTerminals", graph.get_id(vertex))
assert (
f"Cell with id {graph.get_id(vertex)} is not an edge"
@@ -1499,7 +1499,7 @@ def test_custom_font_family(graph_cases_factory, port) -> None:
:type port: qmxgraph.tests.conftest.Port
"""
options = GraphOptions(
- font_family=('Helvetica',),
+ font_family=("Helvetica",),
)
with server.host(port=port.get(), options=options) as host:
@@ -1513,41 +1513,41 @@ def test_custom_font_family(graph_cases_factory, port) -> None:
def test_ports(graph_cases) -> None:
- graph = graph_cases('2v')
+ graph = graph_cases("2v")
vertex_a, vertex_b = graph.get_vertices()
- port_x_name, port_y_name = 'X', 'Y'
+ port_x_name, port_y_name = "X", "Y"
vertex_a_id = graph.get_id(vertex_a)
vertex_b_id = graph.get_id(vertex_b)
# Test insert port.
- graph.eval_js_function('api.insertPort', vertex_a_id, port_x_name, 0, 0, 9, 9)
+ graph.eval_js_function("api.insertPort", vertex_a_id, port_x_name, 0, 0, 9, 9)
with pytest.raises(WebDriverException) as e:
- graph.eval_js_function('api.insertPort', vertex_a_id, port_x_name, 1, 1, 9, 9)
- expected = 'The cell {} already have a port named {}'.format(vertex_a_id, port_x_name)
+ graph.eval_js_function("api.insertPort", vertex_a_id, port_x_name, 1, 1, 9, 9)
+ expected = "The cell {} already have a port named {}".format(vertex_a_id, port_x_name)
assert expected in str(e.value)
# Test remove port.
- graph.eval_js_function('api.removePort', vertex_a_id, port_x_name)
+ graph.eval_js_function("api.removePort", vertex_a_id, port_x_name)
with pytest.raises(WebDriverException) as e:
- graph.eval_js_function('api.removePort', vertex_a_id, port_x_name)
- expected = 'The cell {} does not have a port named {}'.format(vertex_a_id, port_x_name)
+ graph.eval_js_function("api.removePort", vertex_a_id, port_x_name)
+ expected = "The cell {} does not have a port named {}".format(vertex_a_id, port_x_name)
assert expected in str(e.value)
# Test insert edge.
- graph.eval_js_function('api.insertPort', vertex_a_id, port_x_name, 0, 0, 9, 9)
- graph.eval_js_function('api.insertPort', vertex_b_id, port_y_name, 0, 0, 9, 9)
+ graph.eval_js_function("api.insertPort", vertex_a_id, port_x_name, 0, 0, 9, 9)
+ graph.eval_js_function("api.insertPort", vertex_b_id, port_y_name, 0, 0, 9, 9)
edge_id = graph.eval_js_function(
- 'api.insertEdge', vertex_a_id, vertex_b_id, None, None, None, port_x_name, port_y_name
+ "api.insertEdge", vertex_a_id, vertex_b_id, None, None, None, port_x_name, port_y_name
)
# When removing a port remove edges connected through it.
- assert graph.eval_js_function('api.hasCell', edge_id)
- assert [vertex_a_id, vertex_b_id] == graph.eval_js_function('api.getEdgeTerminals', edge_id)
+ assert graph.eval_js_function("api.hasCell", edge_id)
+ assert [vertex_a_id, vertex_b_id] == graph.eval_js_function("api.getEdgeTerminals", edge_id)
assert [[vertex_a_id, port_x_name], [vertex_b_id, port_y_name]] == graph.eval_js_function(
- 'api.getEdgeTerminalsWithPorts', edge_id
+ "api.getEdgeTerminalsWithPorts", edge_id
)
- graph.eval_js_function('api.removePort', vertex_b_id, port_y_name)
- assert not graph.eval_js_function('api.hasCell', edge_id)
+ graph.eval_js_function("api.removePort", vertex_b_id, port_y_name)
+ assert not graph.eval_js_function("api.hasCell", edge_id)
def insert_by_parametrized_type(graph, cell_type, tags=None):
@@ -1568,7 +1568,7 @@ def insert_by_parametrized_type(graph, cell_type, tags=None):
@pytest.mark.parametrize(
- 'layout_name',
+ "layout_name",
[
QmxGraphApi.LAYOUT_ORGANIC,
QmxGraphApi.LAYOUT_COMPACT,
@@ -1582,39 +1582,40 @@ def insert_by_parametrized_type(graph, cell_type, tags=None):
],
)
def test_run_all_layouts(layout_name, graph_cases) -> None:
- graph = graph_cases('3v_1e')
- graph.eval_js_function('api.runLayout', layout_name)
+ graph = graph_cases("3v_1e")
+ graph.eval_js_function("api.runLayout", layout_name)
def test_run_organic_layout(graph_cases) -> None:
- graph = graph_cases('3v_3e')
+ graph = graph_cases("3v_3e")
label = lambda cell: graph.get_label(cell)
nodes_positions = {
label(v): {
- 'before': None,
- 'after': None,
+ "before": None,
+ "after": None,
}
for v in graph.get_vertices()
}
for v in graph.get_vertices():
- nodes_positions[label(v)]['before'] = graph.get_vertex_position(v)
- graph.eval_js_function('api.runLayout', QmxGraphApi.LAYOUT_ORGANIC)
+ nodes_positions[label(v)]["before"] = graph.get_vertex_position(v)
+ graph.eval_js_function("api.runLayout", QmxGraphApi.LAYOUT_ORGANIC)
for v in graph.get_vertices():
- nodes_positions[label(v)]['after'] = graph.get_vertex_position(v)
+ nodes_positions[label(v)]["after"] = graph.get_vertex_position(v)
for position_data in nodes_positions.values():
# We do not have the exact expected position to check - But we do know that the positions
# should at least change.
- assert (
- not pytest.approx(position_data['before']) == position_data['after']
- ), "Expected position different from %s, but got %s" % (
- {position_data['before']},
- {position_data['after']},
+ assert not pytest.approx(position_data["before"]) == position_data["after"], (
+ "Expected position different from %s, but got %s"
+ % (
+ {position_data["before"]},
+ {position_data["after"]},
+ )
)
def test_run_invalid_layout(graph_cases) -> None:
- graph = graph_cases('3v_1e')
+ graph = graph_cases("3v_1e")
with pytest.raises(WebDriverException):
- graph.eval_js_function('api.runLayout', 'invalid_layout_name')
+ graph.eval_js_function("api.runLayout", "invalid_layout_name")
diff --git a/tests/test_js_utils.py b/tests/test_js_utils.py
index 8fb4396..2d49882 100644
--- a/tests/test_js_utils.py
+++ b/tests/test_js_utils.py
@@ -5,41 +5,41 @@
@pytest.fixture
def graph(graph_cases: GraphCaseFactory) -> BaseGraphCase:
- return graph_cases('empty')
+ return graph_cases("empty")
def test_set_style_key(graph: BaseGraphCase) -> None:
- assert graph.eval_js_function('graphs.utils.setStyleKey', '', 'bar', 5) == 'bar=5'
- assert graph.eval_js_function('graphs.utils.setStyleKey', 'style', 'bar', 5) == 'style;bar=5'
+ assert graph.eval_js_function("graphs.utils.setStyleKey", "", "bar", 5) == "bar=5"
+ assert graph.eval_js_function("graphs.utils.setStyleKey", "style", "bar", 5) == "style;bar=5"
assert (
- graph.eval_js_function('graphs.utils.setStyleKey', 'style;bar=7', 'bar', 5) == 'style;bar=5'
+ graph.eval_js_function("graphs.utils.setStyleKey", "style;bar=7", "bar", 5) == "style;bar=5"
)
assert (
- graph.eval_js_function('graphs.utils.setStyleKey', 'foobar=3;bar=7', 'bar', 5)
- == 'foobar=3;bar=5'
+ graph.eval_js_function("graphs.utils.setStyleKey", "foobar=3;bar=7", "bar", 5)
+ == "foobar=3;bar=5"
)
assert (
- graph.eval_js_function('graphs.utils.setStyleKey', 'foobar=3', 'bar', 5) == 'foobar=3;bar=5'
+ graph.eval_js_function("graphs.utils.setStyleKey", "foobar=3", "bar", 5) == "foobar=3;bar=5"
)
assert (
- graph.eval_js_function('graphs.utils.setStyleKey', 'foobar=3;fizzbar=7', 'bar', 5)
- == 'foobar=3;fizzbar=7;bar=5'
+ graph.eval_js_function("graphs.utils.setStyleKey", "foobar=3;fizzbar=7", "bar", 5)
+ == "foobar=3;fizzbar=7;bar=5"
)
def test_remove_style_key(graph: BaseGraphCase) -> None:
- assert graph.eval_js_function('graphs.utils.removeStyleKey', '', 'bar') == ''
- assert graph.eval_js_function('graphs.utils.removeStyleKey', 'style;bar=7', 'bar') == 'style'
+ assert graph.eval_js_function("graphs.utils.removeStyleKey", "", "bar") == ""
+ assert graph.eval_js_function("graphs.utils.removeStyleKey", "style;bar=7", "bar") == "style"
assert (
- graph.eval_js_function('graphs.utils.removeStyleKey', 'style;bar=7', 'foo') == 'style;bar=7'
+ graph.eval_js_function("graphs.utils.removeStyleKey", "style;bar=7", "foo") == "style;bar=7"
)
assert (
- graph.eval_js_function('graphs.utils.removeStyleKey', 'style;bar=7', 'style')
- == 'style;bar=7'
+ graph.eval_js_function("graphs.utils.removeStyleKey", "style;bar=7", "style")
+ == "style;bar=7"
)
assert (
- graph.eval_js_function('graphs.utils.removeStyleKey', 'foo=3;bar=7', 'style')
- == 'foo=3;bar=7'
+ graph.eval_js_function("graphs.utils.removeStyleKey", "foo=3;bar=7", "style")
+ == "foo=3;bar=7"
)
- assert graph.eval_js_function('graphs.utils.removeStyleKey', 'foo=3;bar=7', 'foo') == 'bar=7'
- assert graph.eval_js_function('graphs.utils.removeStyleKey', 'foo=3;bar=7', 'bar') == 'foo=3'
+ assert graph.eval_js_function("graphs.utils.removeStyleKey", "foo=3;bar=7", "foo") == "bar=7"
+ assert graph.eval_js_function("graphs.utils.removeStyleKey", "foo=3;bar=7", "bar") == "foo=3"
diff --git a/tests/test_qt_js_integration.py b/tests/test_qt_js_integration.py
index b0e047a..64ffb4c 100644
--- a/tests/test_qt_js_integration.py
+++ b/tests/test_qt_js_integration.py
@@ -43,13 +43,13 @@ def test_error_redirection(loaded_graph) -> None:
assert cb.args is not None
msg, url, line, column = cb.args
expected = textwrap.dedent(
- '''\
+ """\
Uncaught Error: test
stack:
Error: test
- at :1:7'''
+ at :1:7"""
)
- assert (url, line, column) == ('qrc:/', 1, 1)
+ assert (url, line, column) == ("qrc:/", 1, 1)
def test_events_bridge_delayed_signals(graph, qtbot, mocker) -> None:
@@ -108,7 +108,7 @@ def test_events_bridge_plain(graph, mocker) -> None:
graph.load_and_wait()
# on_cells_added
with wait_signals_called(events.on_cells_added):
- vertex_id = graph.api.insert_vertex(40, 40, 20, 20, 'test')
+ vertex_id = graph.api.insert_vertex(40, 40, 20, 20, "test")
assert added_handler.call_args_list == [mocker.call([vertex_id])]
# on_selection_changed
assert selections_handler.call_args_list == []
@@ -117,13 +117,13 @@ def test_events_bridge_plain(graph, mocker) -> None:
assert selections_handler.call_args_list == [mocker.call([vertex_id])]
# on_label_changed
with wait_signals_called(events.on_label_changed):
- graph.api.set_label(vertex_id, 'TOTALLY NEW LABEL')
- assert labels_handler.call_args_list == [mocker.call(vertex_id, 'TOTALLY NEW LABEL', 'test')]
+ graph.api.set_label(vertex_id, "TOTALLY NEW LABEL")
+ assert labels_handler.call_args_list == [mocker.call(vertex_id, "TOTALLY NEW LABEL", "test")]
# on_terminal_changed, on_terminal_with_port_changed
- foo_id = graph.api.insert_vertex(440, 40, 20, 20, 'foo')
- bar_id = graph.api.insert_vertex(40, 140, 20, 20, 'bar')
- edge_id = graph.api.insert_edge(vertex_id, foo_id, 'edge')
- bar_port_name = 'a-port'
+ foo_id = graph.api.insert_vertex(440, 40, 20, 20, "foo")
+ bar_id = graph.api.insert_vertex(40, 140, 20, 20, "bar")
+ edge_id = graph.api.insert_edge(vertex_id, foo_id, "edge")
+ bar_port_name = "a-port"
assert not graph.api.has_port(bar_id, bar_port_name)
graph.api.insert_port(bar_id, bar_port_name, 0, 0, 5, 5)
assert graph.api.has_port(bar_id, bar_port_name)
@@ -152,15 +152,15 @@ def test_events_bridge_plain(graph, mocker) -> None:
bar_id,
bar_port_name,
foo_id,
- '',
+ "",
),
mocker.call(
edge_id,
QmxGraphApi.SOURCE_TERMINAL_CELL,
foo_id,
- '',
+ "",
vertex_id,
- '',
+ "",
),
]
# on_cells_removed
@@ -187,7 +187,7 @@ def handler_that_call_api(*args):
events = loaded_graph.events_bridge
events.on_cells_added.connect(handler_that_call_api)
with wait_signals_called(events.on_cells_added):
- loaded_graph.api.insert_vertex(40, 40, 20, 20, 'test')
+ loaded_graph.api.insert_vertex(40, 40, 20, 20, "test")
assert zoom_scale_obtained == [1]
@@ -269,7 +269,7 @@ def test_container_resize(loaded_graph) -> None:
def get_container_dimensions():
width = eval_js(loaded_graph, """document.getElementById('graphContainer').style.width""")
height = eval_js(loaded_graph, """document.getElementById('graphContainer').style.height""")
- return int(width.replace('px', '')), int(height.replace('px', ''))
+ return int(width.replace("px", "")), int(height.replace("px", ""))
width, height = get_container_dimensions()
assert width == expected_width
@@ -289,8 +289,8 @@ def test_web_inspector(loaded_graph, mocker) -> None:
"""
from PyQt5.QtWidgets import QDialog
- mocker.patch.object(QDialog, 'show')
- mocker.patch.object(QDialog, 'hide')
+ mocker.patch.object(QDialog, "show")
+ mocker.patch.object(QDialog, "hide")
loaded_graph.show_inspector()
QDialog.show.assert_called_once_with()
@@ -382,21 +382,21 @@ def test_drag_drop(loaded_graph, drag_drop_events) -> None:
"""
mime_data = qmxgraph.mime.create_qt_mime_data(
{
- 'vertices': [
+ "vertices": [
{
- 'dx': 0,
- 'dy': 0,
- 'width': 64,
- 'height': 64,
- 'label': 'test 1',
+ "dx": 0,
+ "dy": 0,
+ "width": 64,
+ "height": 64,
+ "label": "test 1",
},
{
- 'dx': 50,
- 'dy': 50,
- 'width': 32,
- 'height': 32,
- 'label': 'test 2',
- 'tags': {'foo': '1', 'bar': 'a'},
+ "dx": 50,
+ "dy": 50,
+ "width": 32,
+ "height": 32,
+ "label": "test 2",
+ "tags": {"foo": "1", "bar": "a"},
},
],
}
@@ -417,14 +417,14 @@ def test_drag_drop(loaded_graph, drag_drop_events) -> None:
cell_id = loaded_graph.api.get_cell_id_at(100, 100)
assert loaded_graph.api.get_cell_type(cell_id) == qmxgraph.constants.CELL_TYPE_VERTEX
assert loaded_graph.api.get_geometry(cell_id) == [100.0 - 64 / 2, 100.0 - 64 / 2, 64.0, 64.0]
- assert loaded_graph.api.get_label(cell_id) == 'test 1'
+ assert loaded_graph.api.get_label(cell_id) == "test 1"
cell_id = loaded_graph.api.get_cell_id_at(150, 150)
assert loaded_graph.api.get_cell_type(cell_id) == qmxgraph.constants.CELL_TYPE_VERTEX
assert loaded_graph.api.get_geometry(cell_id) == [150.0 - 32 / 2, 150.0 - 32 / 2, 32.0, 32.0]
- assert loaded_graph.api.get_label(cell_id) == 'test 2'
- assert loaded_graph.api.get_tag(cell_id, 'foo') == '1'
- assert loaded_graph.api.get_tag(cell_id, 'bar') == 'a'
+ assert loaded_graph.api.get_label(cell_id) == "test 2"
+ assert loaded_graph.api.get_tag(cell_id, "foo") == "1"
+ assert loaded_graph.api.get_tag(cell_id, "bar") == "a"
def test_drag_drop_invalid_mime_type(loaded_graph, drag_drop_events) -> None:
@@ -438,11 +438,11 @@ def test_drag_drop_invalid_mime_type(loaded_graph, drag_drop_events) -> None:
item_data = QByteArray()
data_stream = QDataStream(item_data, QIODevice.WriteOnly)
data_stream.writeString(
- json.dumps('Hello World!').encode('utf8')
+ json.dumps('Hello World!').encode("utf8")
)
mime_data = QMimeData()
- mime_data.setData('application/xml', item_data)
+ mime_data.setData("application/xml", item_data)
drag_enter_event = drag_drop_events.drag_enter(mime_data)
loaded_graph.inner_web_view().dragEnterEvent(drag_enter_event)
@@ -465,7 +465,7 @@ def test_drag_drop_invalid_version(loaded_graph, drag_drop_events) -> None:
"""
mime_data = qmxgraph.mime.create_qt_mime_data(
{
- 'version': -1,
+ "version": -1,
}
)
@@ -483,8 +483,8 @@ def test_drag_drop_invalid_version(loaded_graph, drag_drop_events) -> None:
print(
(
- 'This test will cause an exception in a Qt event loop:\n'
- ' ValueError: Unsupported version of QmxGraph MIME data: -1'
+ "This test will cause an exception in a Qt event loop:\n"
+ " ValueError: Unsupported version of QmxGraph MIME data: -1"
),
file=sys.stderr,
)
@@ -498,7 +498,7 @@ def test_drag_drop_invalid_version(loaded_graph, drag_drop_events) -> None:
assert str(exceptions[0][1]) == "Unsupported version of QmxGraph MIME data: -1"
-@pytest.mark.parametrize('debug', (True, False))
+@pytest.mark.parametrize("debug", (True, False))
def test_invalid_api_call(loaded_graph, debug) -> None:
"""
:type loaded_graph: qmxgraph.widget.qmxgraph
@@ -515,33 +515,33 @@ def test_invalid_api_call(loaded_graph, debug) -> None:
'Uncaught Error: [QmxGraph] unable to find function "BOOM" in javascript api'
)
with pytest.raises(InvalidJavaScriptError, match=expected_message):
- loaded_graph.api.call_api('BOOM')
+ loaded_graph.api.call_api("BOOM")
else:
# When debug feature is disabled, code will raise on JavaScript
# side, but unless an error bridge is configured that could go
# unnoticed, as call would return None and could easily be
# mistaken by an OK call.
- assert loaded_graph.api.call_api('BOOM') is None
+ assert loaded_graph.api.call_api("BOOM") is None
finally:
qmxgraph.debug.set_qmxgraph_debug(old_debug)
-@pytest.mark.parametrize('enabled', (True, False))
+@pytest.mark.parametrize("enabled", (True, False))
def test_graph_api_calls(loaded_graph, enabled) -> None:
"""
Tests the available calls to the graph api.
"""
graph_api_functions = [
- ('is_cells_deletable', 'set_cells_deletable'),
- ('is_cells_disconnectable', 'set_cells_disconnectable'),
- ('is_cells_editable', 'set_cells_editable'),
+ ("is_cells_deletable", "set_cells_deletable"),
+ ("is_cells_disconnectable", "set_cells_disconnectable"),
+ ("is_cells_editable", "set_cells_editable"),
(
- 'is_cells_movable',
- 'set_cells_movable',
+ "is_cells_movable",
+ "set_cells_movable",
),
(
- 'is_cells_connectable',
- 'set_cells_connectable',
+ "is_cells_connectable",
+ "set_cells_connectable",
),
]
@@ -559,16 +559,16 @@ def test_tags(loaded_graph) -> None:
"""
:type loaded_graph: qmxgraph.widget.qmxgraph
"""
- no_tags_id = loaded_graph.api.insert_vertex(10, 10, 20, 20, 'test')
+ no_tags_id = loaded_graph.api.insert_vertex(10, 10, 20, 20, "test")
- assert not loaded_graph.api.has_tag(no_tags_id, 'foo')
- loaded_graph.api.set_tag(no_tags_id, 'foo', '1')
- assert loaded_graph.api.has_tag(no_tags_id, 'foo')
- assert loaded_graph.api.get_tag(no_tags_id, 'foo') == '1'
+ assert not loaded_graph.api.has_tag(no_tags_id, "foo")
+ loaded_graph.api.set_tag(no_tags_id, "foo", "1")
+ assert loaded_graph.api.has_tag(no_tags_id, "foo")
+ assert loaded_graph.api.get_tag(no_tags_id, "foo") == "1"
- with_tags_id = loaded_graph.api.insert_vertex(50, 50, 20, 20, 'test', tags={'bar': '2'})
- assert loaded_graph.api.has_tag(with_tags_id, 'bar')
- assert loaded_graph.api.get_tag(with_tags_id, 'bar') == '2'
+ with_tags_id = loaded_graph.api.insert_vertex(50, 50, 20, 20, "test", tags={"bar": "2"})
+ assert loaded_graph.api.has_tag(with_tags_id, "bar")
+ assert loaded_graph.api.get_tag(with_tags_id, "bar") == "2"
def test_get_cell_count(loaded_graph) -> None:
@@ -577,13 +577,13 @@ def test_get_cell_count(loaded_graph) -> None:
"""
from qmxgraph.common_testing import get_cell_count
- node_a = loaded_graph.api.insert_vertex(10, 10, 50, 50, 'A')
- node_b = loaded_graph.api.insert_vertex(400, 300, 50, 50, 'B')
- loaded_graph.api.insert_edge(node_a, node_b, 'AB')
+ node_a = loaded_graph.api.insert_vertex(10, 10, 50, 50, "A")
+ node_b = loaded_graph.api.insert_vertex(400, 300, 50, 50, "B")
+ loaded_graph.api.insert_edge(node_a, node_b, "AB")
- assert get_cell_count(loaded_graph, 'function(cell){ return false }') == 0
- assert get_cell_count(loaded_graph, 'function(cell){ return cell.isEdge() }') == 1
- assert get_cell_count(loaded_graph, 'function(cell){ return cell.isVertex() }') == 2
+ assert get_cell_count(loaded_graph, "function(cell){ return false }") == 0
+ assert get_cell_count(loaded_graph, "function(cell){ return cell.isEdge() }") == 1
+ assert get_cell_count(loaded_graph, "function(cell){ return cell.isVertex() }") == 2
def test_get_cell_ids(loaded_graph) -> None:
@@ -592,17 +592,17 @@ def test_get_cell_ids(loaded_graph) -> None:
"""
from qmxgraph.common_testing import get_cell_ids
- node_a = loaded_graph.api.insert_vertex(10, 10, 50, 50, 'A')
- node_b = loaded_graph.api.insert_vertex(400, 300, 50, 50, 'B')
- loaded_graph.api.insert_edge(node_a, node_b, 'AB')
+ node_a = loaded_graph.api.insert_vertex(10, 10, 50, 50, "A")
+ node_b = loaded_graph.api.insert_vertex(400, 300, 50, 50, "B")
+ loaded_graph.api.insert_edge(node_a, node_b, "AB")
- assert get_cell_ids(loaded_graph, 'function(cell){ return false }') == []
- assert get_cell_ids(loaded_graph, 'function(cell){ return cell.isEdge() }') == ['4']
- assert get_cell_ids(loaded_graph, 'function(cell){ return cell.isVertex() }') == ['2', '3']
+ assert get_cell_ids(loaded_graph, "function(cell){ return false }") == []
+ assert get_cell_ids(loaded_graph, "function(cell){ return cell.isEdge() }") == ["4"]
+ assert get_cell_ids(loaded_graph, "function(cell){ return cell.isVertex() }") == ["2", "3"]
def test_cell_bounds(loaded_graph) -> None:
- node_a = loaded_graph.api.insert_vertex(10, 10, 50, 50, 'A')
+ node_a = loaded_graph.api.insert_vertex(10, 10, 50, 50, "A")
bounds = loaded_graph.api.get_cell_bounds(node_a)
assert bounds == CellBounds(x=10, y=10, width=50, height=50)
@@ -627,7 +627,7 @@ def test_last_index_of(loaded_graph) -> None:
@pytest.mark.parametrize(
- ('zoom_in', 'zoom_to_cursor'),
+ ("zoom_in", "zoom_to_cursor"),
[
(False, False),
(False, True),
@@ -640,16 +640,16 @@ def test_zoom(loaded_graph: QmxGraph, zoom_in: bool, zoom_to_cursor: bool) -> No
y = 234
width = height = 50
initial_geometry = (x, y, width, height)
- node = loaded_graph.api.insert_vertex(*initial_geometry, 'Node')
+ node = loaded_graph.api.insert_vertex(*initial_geometry, "Node")
assert tuple(loaded_graph.api.get_geometry(node)) == initial_geometry
node_center_x = x + width / 2
node_center_y = y + height / 2
- zoom_event = {'clientX': node_center_x, 'clientY': node_center_y}
+ zoom_event = {"clientX": node_center_x, "clientY": node_center_y}
args = ", ".join(json.dumps(arg) for arg in [zoom_event, zoom_in, zoom_to_cursor])
- eval_js(loaded_graph, f'graphs.handleMouseWheelEvent(graphEditor.graph, {args})')
+ eval_js(loaded_graph, f"graphs.handleMouseWheelEvent(graphEditor.graph, {args})")
new_x, new_y, new_width, new_height = loaded_graph.api.get_geometry(node)
assert (new_width > width) == (new_height > height) == zoom_in
@@ -664,7 +664,7 @@ def eval_js(graph_widget, statement):
return graph_widget.inner_web_view().eval_js(statement)
-@pytest.fixture(name='graph')
+@pytest.fixture(name="graph")
def graph_(qtbot) -> QmxGraph:
"""
:type qtbot: pytestqt.plugin.QtBot
@@ -677,7 +677,7 @@ def graph_(qtbot) -> QmxGraph:
return graph_
-@pytest.fixture(name='loaded_graph')
+@pytest.fixture(name="loaded_graph")
def loaded_graph_(graph):
"""
:type graph: qmxgraph.widget.qmxgraph
@@ -687,7 +687,7 @@ def loaded_graph_(graph):
return graph
-@pytest.fixture(name='drag_drop_events')
+@pytest.fixture(name="drag_drop_events")
def drag_drop_events_(mocker):
"""
:type mocker: pyest_mock.MockFixture
@@ -719,8 +719,8 @@ def _create_dd_event(self, event_type, position, mime_data):
position = position or (100, 100)
dd_args = QPoint(*position), Qt.MoveAction, mime_data, Qt.LeftButton, Qt.NoModifier
dd_event = event_type(*dd_args)
- self.mocker.spy(dd_event, 'acceptProposedAction')
- self.mocker.spy(dd_event, 'ignore')
+ self.mocker.spy(dd_event, "acceptProposedAction")
+ self.mocker.spy(dd_event, "ignore")
return dd_event
@@ -758,7 +758,7 @@ def assert_handled(self, *, js_script, called, expected_calls=()):
10,
20,
20,
- 'handler fixture test',
+ "handler fixture test",
)
js_script = js_script.format(
vertex=f"graphEditor.graph.model.getCell({vertex_id})",
@@ -778,7 +778,7 @@ def assert_handled(self, *, js_script, called, expected_calls=()):
self.calls.clear()
-@pytest.fixture(name='handler')
+@pytest.fixture(name="handler")
def handler_(graph, qtbot):
"""
:type graph: qmxgraph.widget.qmxgraph