Merge branch 'master' of https://github.com/mingrammer/diagrams into @cbrown/743-mkdocs-site

pull/748/head
Collin Brown 3 years ago
commit 39fc0845d6

@ -55,7 +55,7 @@ or update the `ALIASES` map in [config.py](config.py).
Then just run the `./autogen.sh` to generate the added or updated aliases. (cf. [DEVELOPMENT][DEVELOPMENT.md]) Then just run the `./autogen.sh` to generate the added or updated aliases. (cf. [DEVELOPMENT][DEVELOPMENT.md])
> IMPORTANT NOTE: To run `autogen.sh`, you need [round][round] and > IMPORTANT NOTE: To run `autogen.sh`, you need [round][round] and
> [inkscape][inkscape] command lines that are used for clearning the image > [inkscape][inkscape] command lines that are used for cleaning the image
> resource filenames. > resource filenames.
> >
> Or you should use the docker image. > Or you should use the docker image.

@ -37,6 +37,7 @@ Diagrams lets you draw the cloud system architecture **in Python code**. It was
![generic provider](https://img.shields.io/badge/Generic-orange?color=5f87bf) ![generic provider](https://img.shields.io/badge/Generic-orange?color=5f87bf)
![programming provider](https://img.shields.io/badge/Programming-orange?color=5f87bf) ![programming provider](https://img.shields.io/badge/Programming-orange?color=5f87bf)
![saas provider](https://img.shields.io/badge/SaaS-orange?color=5f87bf) ![saas provider](https://img.shields.io/badge/SaaS-orange?color=5f87bf)
![c4 provider](https://img.shields.io/badge/C4-orange?color=5f87bf)
## Getting Started ## Getting Started
@ -83,7 +84,7 @@ To contribute to diagram, check out [contribution guidelines](CONTRIBUTING.md).
## Other languages ## Other languages
- If you are familiar to Go, you can use [go-diagrams](https://github.com/blushft/go-diagrams) as well. - If you are familiar with Go, you can use [go-diagrams](https://github.com/blushft/go-diagrams) as well.
## License ## License

@ -1,10 +1,9 @@
#!/bin/bash #!/bin/bash
set -e
app_root_dir="diagrams" app_root_dir="diagrams"
# NOTE: azure icon set is not latest version # NOTE: azure icon set is not latest version
providers=("onprem" "aws" "azure" "digitalocean" "gcp" "ibm" "firebase" "k8s" "alibabacloud" "oci" "programming" "saas" "elastic" "generic" "openstack" "outscale" ) providers=("onprem" "aws" "azure" "digitalocean" "gcp" "ibm" "firebase" "k8s" "alibabacloud" "oci" "programming" "saas" "elastic" "generic" "openstack" "outscale")
if ! [ -x "$(command -v round)" ]; then if ! [ -x "$(command -v round)" ]; then
echo 'round is not installed' echo 'round is not installed'
@ -56,6 +55,10 @@ done
echo "generating the docs for custom" echo "generating the docs for custom"
python -m scripts.generate "custom" python -m scripts.generate "custom"
# copy icons across to website
echo "copying icons to website static folder"
cp -r resources website/static/img/resources
# run black # run black
echo "linting the all the diagram modules" echo "linting the all the diagram modules"
black "$app_root_dir"/**/*.py black "$app_root_dir"/**/*.py

@ -15,25 +15,25 @@ __diagram = contextvars.ContextVar("diagrams")
__cluster = contextvars.ContextVar("cluster") __cluster = contextvars.ContextVar("cluster")
def getdiagram(): def getdiagram() -> "Diagram":
try: try:
return __diagram.get() return __diagram.get()
except LookupError: except LookupError:
return None return None
def setdiagram(diagram): def setdiagram(diagram: "Diagram"):
__diagram.set(diagram) __diagram.set(diagram)
def getcluster(): def getcluster() -> "Cluster":
try: try:
return __cluster.get() return __cluster.get()
except LookupError: except LookupError:
return None return None
def setcluster(cluster): def setcluster(cluster: "Cluster"):
__cluster.set(cluster) __cluster.set(cluster)
@ -83,6 +83,7 @@ class Diagram:
direction: str = "LR", direction: str = "LR",
curvestyle: str = "ortho", curvestyle: str = "ortho",
outformat: str = "png", outformat: str = "png",
autolabel: bool = False,
show: bool = True, show: bool = True,
graph_attr: dict = {}, graph_attr: dict = {},
node_attr: dict = {}, node_attr: dict = {},
@ -142,6 +143,7 @@ class Diagram:
self.dot.edge_attr.update(edge_attr) self.dot.edge_attr.update(edge_attr)
self.show = show self.show = show
self.autolabel = autolabel
def __str__(self) -> str: def __str__(self) -> str:
return str(self.dot) return str(self.dot)
@ -258,11 +260,8 @@ class Cluster:
self._diagram.subgraph(self.dot) self._diagram.subgraph(self.dot)
setcluster(self._parent) setcluster(self._parent)
def _validate_direction(self, direction: str): def _validate_direction(self, direction: str) -> bool:
direction = direction.upper() return direction.upper() in self.__directions
if direction in self.__directions:
return True
return False
def node(self, nodeid: str, label: str, **attrs) -> None: def node(self, nodeid: str, label: str, **attrs) -> None:
"""Create a new node in the cluster.""" """Create a new node in the cluster."""
@ -283,20 +282,32 @@ class Node:
_height = 1.9 _height = 1.9
def __init__(self, label: str = "", **attrs: Dict): def __init__(self, label: str = "", *, nodeid: str = None, **attrs: Dict):
"""Node represents a system component. """Node represents a system component.
:param label: Node label. :param label: Node label.
""" """
# Generates an ID for identifying a node. # Generates an ID for identifying a node, unless specified
self._id = self._rand_id() self._id = nodeid or self._rand_id()
self.label = label self.label = label
# Node must be belong to a diagrams.
self._diagram = getdiagram()
if self._diagram is None:
raise EnvironmentError("Global diagrams context not set up")
if self._diagram.autolabel:
prefix = self.__class__.__name__
if self.label:
self.label = prefix + "\n" + self.label
else:
self.label = prefix
# fmt: off # fmt: off
# If a node has an icon, increase the height slightly to avoid # If a node has an icon, increase the height slightly to avoid
# that label being spanned between icon image and white space. # that label being spanned between icon image and white space.
# Increase the height by the number of new lines included in the label. # Increase the height by the number of new lines included in the label.
padding = 0.4 * (label.count('\n')) padding = 0.4 * (self.label.count('\n'))
self._attrs = { self._attrs = {
"shape": "none", "shape": "none",
"height": str(self._height + padding), "height": str(self._height + padding),
@ -306,10 +317,6 @@ class Node:
# fmt: on # fmt: on
self._attrs.update(attrs) self._attrs.update(attrs)
# Node must be belong to a diagrams.
self._diagram = getdiagram()
if self._diagram is None:
raise EnvironmentError("Global diagrams context not set up")
self._cluster = getcluster() self._cluster = getcluster()
# If a node is in the cluster context, add it to cluster. # If a node is in the cluster context, add it to cluster.

@ -8,6 +8,10 @@ class _Compute(_AWS):
_icon_dir = "resources/aws/compute" _icon_dir = "resources/aws/compute"
class AppRunner(_Compute):
_icon = "app-runner.png"
class ApplicationAutoScaling(_Compute): class ApplicationAutoScaling(_Compute):
_icon = "application-auto-scaling.png" _icon = "application-auto-scaling.png"

@ -0,0 +1,97 @@
"""
A set of nodes and edges to visualize software architecture using the C4 model.
"""
import html
import textwrap
from diagrams import Cluster, Node, Edge
def _format_node_label(name, key, description):
"""Create a graphviz label string for a C4 node"""
title = f'<font point-size="12"><b>{html.escape(name)}</b></font><br/>'
subtitle = f'<font point-size="9">[{html.escape(key)}]<br/></font>' if key else ""
text = f'<br/><font point-size="10">{_format_description(description)}</font>' if description else ""
return f"<{title}{subtitle}{text}>"
def _format_description(description):
"""
Formats the description string so it fits into the C4 nodes.
It line-breaks the description so it fits onto exactly three lines. If there are more
than three lines, all further lines are discarded and "..." inserted on the last line to
indicate that it was shortened. This will also html-escape the description so it can
safely be included in a HTML label.
"""
wrapper = textwrap.TextWrapper(width=40, max_lines=3)
lines = [html.escape(line) for line in wrapper.wrap(description)]
lines += [""] * (3 - len(lines)) # fill up with empty lines so it is always three
return "<br/>".join(lines)
def _format_edge_label(description):
"""Create a graphviz label string for a C4 edge"""
wrapper = textwrap.TextWrapper(width=24, max_lines=3)
lines = [html.escape(line) for line in wrapper.wrap(description)]
text = "<br/>".join(lines)
return f'<<font point-size="10">{text}</font>>'
def C4Node(name, technology="", description="", type="Container", **kwargs):
key = f"{type}: {technology}" if technology else type
node_attributes = {
"label": _format_node_label(name, key, description),
"labelloc": "c",
"shape": "rect",
"width": "2.6",
"height": "1.6",
"fixedsize": "true",
"style": "filled",
"fillcolor": "dodgerblue3",
"fontcolor": "white",
}
# collapse boxes to a smaller form if they don't have a description
if not description:
node_attributes.update({"width": "2", "height": "1"})
node_attributes.update(kwargs)
return Node(**node_attributes)
def Container(name, technology="", description="", **kwargs):
return C4Node(name, technology=technology, description=description, type="Container")
def Database(name, technology="", description="", **kwargs):
return C4Node(name, technology=technology, description=description, type="Database", shape="cylinder", labelloc="b")
def System(name, description="", external=False, **kwargs):
type = "External System" if external else "System"
fillcolor = "gray60" if external else "dodgerblue4"
return C4Node(name, description=description, type=type, fillcolor=fillcolor)
def Person(name, description="", external=False, **kwargs):
type = "External Person" if external else "Person"
fillcolor = "gray60" if external else "dodgerblue4"
style = "rounded,filled"
return C4Node(name, description=description, type=type, fillcolor=fillcolor, style=style)
def SystemBoundary(name, **kwargs):
graph_attributes = {
"label": html.escape(name),
"bgcolor": "white",
"margin": "16",
"style": "dashed",
}
graph_attributes.update(kwargs)
return Cluster(name, graph_attr=graph_attributes)
def Relationship(label="", **kwargs):
edge_attribtues = {"style": "dashed", "color": "gray60"}
if label:
edge_attribtues.update({"label": _format_edge_label(label)})
edge_attribtues.update(kwargs)
return Edge(**edge_attribtues)

@ -15,6 +15,6 @@ class Custom(Node):
def _load_icon(self): def _load_icon(self):
return self._icon return self._icon
def __init__(self, label, icon_path): def __init__(self, label, icon_path, *args, **kwargs):
self._icon = icon_path self._icon = icon_path
super().__init__(label) super().__init__(label, *args, **kwargs)

@ -16,6 +16,10 @@ class Centos(_Os):
_icon = "centos.png" _icon = "centos.png"
class Debian(_Os):
_icon = "debian.png"
class IOS(_Os): class IOS(_Os):
_icon = "ios.png" _icon = "ios.png"
@ -24,6 +28,10 @@ class LinuxGeneral(_Os):
_icon = "linux-general.png" _icon = "linux-general.png"
class Raspbian(_Os):
_icon = "raspbian.png"
class Suse(_Os): class Suse(_Os):
_icon = "suse.png" _icon = "suse.png"

@ -20,4 +20,8 @@ class Pushover(_Alerting):
_icon = "pushover.png" _icon = "pushover.png"
class Xmatters(_Alerting):
_icon = "xmatters.png"
# Aliases # Aliases

@ -16,4 +16,8 @@ class Cloudflare(_Cdn):
_icon = "cloudflare.png" _icon = "cloudflare.png"
class Fastly(_Cdn):
_icon = "fastly.png"
# Aliases # Aliases

@ -12,10 +12,18 @@ class Discord(_Chat):
_icon = "discord.png" _icon = "discord.png"
class Line(_Chat):
_icon = "line.png"
class Mattermost(_Chat): class Mattermost(_Chat):
_icon = "mattermost.png" _icon = "mattermost.png"
class Messenger(_Chat):
_icon = "messenger.png"
class RocketChat(_Chat): class RocketChat(_Chat):
_icon = "rocket-chat.png" _icon = "rocket-chat.png"

@ -0,0 +1,15 @@
# This module is automatically generated by autogen.sh. DO NOT EDIT.
from . import _Saas
class _Communication(_Saas):
_type = "communication"
_icon_dir = "resources/saas/communication"
class Twilio(_Communication):
_icon = "twilio.png"
# Aliases

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save