Skip to content
Snippets Groups Projects
Unverified Commit 3bc8daf3 authored by Florian Maurer's avatar Florian Maurer
Browse files

allow people to have either pygraphviz or graphviz installed

* Remove graphviz from the required dependencies, as it is not needed when using the mermaid/markdown export
* add both graphviz and pygraphviz in CI for mypy
* add documentation of graphviz flavors
parent f27b2520
No related branches found
No related tags found
No related merge requests found
...@@ -18,6 +18,21 @@ To install eralchemy, just do: ...@@ -18,6 +18,21 @@ To install eralchemy, just do:
$ pip install eralchemy $ pip install eralchemy
### Graph library flavors
To create Pictures and PDFs, eralchemy relies on either graphviz or pygraphviz.
You can use either
$ pip install eralchemy[graphviz]
or
$ pip install eralchemy[pygraphviz]
to retrieve the correct dependencies.
The `graphviz` library is the default if both are installed.
`eralchemy` requires [GraphViz](http://www.graphviz.org/download) to generate the graphs and Python. Both are available for Windows, Mac and Linux. `eralchemy` requires [GraphViz](http://www.graphviz.org/download) to generate the graphs and Python. Both are available for Windows, Mac and Linux.
For Debian based systems, run: For Debian based systems, run:
......
import argparse import argparse
import base64 import base64
import copy import copy
import logging
import re import re
import sys import sys
from importlib.metadata import PackageNotFoundError, version from importlib.metadata import PackageNotFoundError, version
#from pygraphviz.agraph import AGraph
from graphviz import Source
from sqlalchemy.engine.url import make_url from sqlalchemy.engine.url import make_url
from sqlalchemy.exc import ArgumentError from sqlalchemy.exc import ArgumentError
...@@ -23,6 +22,22 @@ from .sqla import ( ...@@ -23,6 +22,22 @@ from .sqla import (
metadata_to_intermediary, metadata_to_intermediary,
) )
USE_PYGRAPHVIZ = True
GRAPHVIZ_AVAILABLE = True
try:
from pygraphviz.agraph import AGraph
logging.debug("using pygraphviz")
except ImportError:
USE_PYGRAPHVIZ = False
try:
from graphviz import Source
logging.debug("using graphviz")
except ImportError:
logging.error("either pygraphviz or graphviz should be installed")
GRAPHVIZ_AVAILABLE = False
try: try:
__version__ = version(__package__) __version__ = version(__package__)
except PackageNotFoundError: except PackageNotFoundError:
...@@ -139,13 +154,18 @@ def intermediary_to_dot(tables, relationships, output, title=""): ...@@ -139,13 +154,18 @@ def intermediary_to_dot(tables, relationships, output, title=""):
def intermediary_to_schema(tables, relationships, output, title=""): def intermediary_to_schema(tables, relationships, output, title=""):
"""Transforms and save the intermediary representation to the file chosen.""" """Transforms and save the intermediary representation to the file chosen."""
if not GRAPHVIZ_AVAILABLE:
raise Exception("neither graphviz or pygraphviz are available. Install either library!")
dot_file = _intermediary_to_dot(tables, relationships, title) dot_file = _intermediary_to_dot(tables, relationships, title)
#graph = AGraph() extension = output.split(".")[-1]
#graph = graph.from_string(dot_file) if USE_PYGRAPHVIZ:
extension = output.split('.')[-1] graph = AGraph()
#graph.draw(path=output, prog='dot', format=extension) graph = graph.from_string(dot_file)
#Source.from_file(filename, engine='dot', format=extension) graph.draw(path=output, prog="dot", format=extension)
return Source(dot_file, engine='dot', format=extension) else:
graph = Source(dot_file, engine="dot", format=extension)
graph.render(outfile=output, cleanup=True)
return graph
def _intermediary_to_markdown(tables, relationships): def _intermediary_to_markdown(tables, relationships):
...@@ -366,13 +386,16 @@ def render_er( ...@@ -366,13 +386,16 @@ def render_er(
""" """
try: try:
tables, relationships = all_to_intermediary(input, schema=schema) tables, relationships = all_to_intermediary(input, schema=schema)
if include is not None: tables, relationships = filter_resources(
tables, relationships = filter_includes(tables, relationships, include) tables,
if exclude is not None: relationships,
tables, relationships = filter_excludes(tables, relationships, exclude) include_tables=include_tables,
include_columns=include_columns,
exclude_tables=exclude_tables,
exclude_columns=exclude_columns,
)
intermediary_to_output = get_output_mode(output, mode) intermediary_to_output = get_output_mode(output, mode)
out = intermediary_to_output(tables, relationships, output) return intermediary_to_output(tables, relationships, output)
return out
except ImportError as e: except ImportError as e:
module_name = e.message.split()[-1] module_name = e.message.split()[-1]
print(f'Please install {module_name} using "pip install {module_name}".') print(f'Please install {module_name} using "pip install {module_name}".')
......
...@@ -26,8 +26,7 @@ classifiers=[ ...@@ -26,8 +26,7 @@ classifiers=[
] ]
requires-python = ">=3.8" requires-python = ">=3.8"
dependencies = [ dependencies = [
"sqlalchemy >= 1.4", "sqlalchemy >= 1.4"
"pygraphviz >= 1.9",
] ]
[project.urls] [project.urls]
...@@ -35,10 +34,14 @@ homepage = "https://github.com/eralchemy/eralchemy" ...@@ -35,10 +34,14 @@ homepage = "https://github.com/eralchemy/eralchemy"
repository = "https://github.com/eralchemy/eralchemy" repository = "https://github.com/eralchemy/eralchemy"
[project.optional-dependencies] [project.optional-dependencies]
graphviz = ["graphviz >= 0.20.3"]
pygraphviz = ["pygraphviz >= 1.9"]
ci = [ ci = [
"flask-sqlalchemy >= 2.5.1", "flask-sqlalchemy >= 2.5.1",
"psycopg2 >= 2.9.3", "psycopg2 >= 2.9.3",
"pytest >= 7.4.3", "pytest >= 7.4.3",
"pygraphviz >= 1.9",
"graphviz >= 0.20.3",
] ]
dev = [ dev = [
"nox", "nox",
...@@ -103,7 +106,7 @@ show_error_codes = true ...@@ -103,7 +106,7 @@ show_error_codes = true
pretty = true pretty = true
[[tool.mypy.overrides]] [[tool.mypy.overrides]]
module = ["pygraphviz.*", "sqlalchemy.*"] module = ["graphviz.*", "pygraphviz.*", "sqlalchemy.*"]
ignore_missing_imports = true ignore_missing_imports = true
......
...@@ -30,6 +30,7 @@ column_inside = re.compile( ...@@ -30,6 +30,7 @@ column_inside = re.compile(
"(?P<key_closing>.*)\\ <FONT\\>\\ \\[(?P<type>.*)\\]\\<\\/FONT\\>", "(?P<key_closing>.*)\\ <FONT\\>\\ \\[(?P<type>.*)\\]\\<\\/FONT\\>",
) )
# This test needs fixing with move to graphviz # This test needs fixing with move to graphviz
def assert_is_dot_format(dot): def assert_is_dot_format(dot):
"""Checks that the dot is usable by graphviz.""" """Checks that the dot is usable by graphviz."""
......
...@@ -115,6 +115,7 @@ def test_flask_sqlalchemy(): ...@@ -115,6 +115,7 @@ def test_flask_sqlalchemy():
check_intermediary_representation_simple_all_table(tables, relationships) check_intermediary_representation_simple_all_table(tables, relationships)
@pytest.mark.external_db
def test_table_names_in_relationships(pg_db_uri): def test_table_names_in_relationships(pg_db_uri):
tables, relationships = database_to_intermediary(pg_db_uri) tables, relationships = database_to_intermediary(pg_db_uri)
table_names = [t.name for t in tables] table_names = [t.name for t in tables]
...@@ -133,6 +134,7 @@ def test_table_names_in_relationships(pg_db_uri): ...@@ -133,6 +134,7 @@ def test_table_names_in_relationships(pg_db_uri):
assert l_name.find(".") == -1 assert l_name.find(".") == -1
@pytest.mark.external_db
def test_table_names_in_relationships_with_schema(pg_db_uri): def test_table_names_in_relationships_with_schema(pg_db_uri):
schema_name = "test" schema_name = "test"
matcher = re.compile(rf"{schema_name}\.[\S+]", re.I) matcher = re.compile(rf"{schema_name}\.[\S+]", re.I)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment