chore: apply pre-commit hooks
This commit is contained in:
parent
a5f767b170
commit
1ec80883f0
79 changed files with 1807 additions and 1451 deletions
|
@ -1,5 +1,4 @@
|
|||
from compose_viz.cli import start_cli
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
start_cli()
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
from enum import Enum
|
||||
import typer
|
||||
from typing import Optional
|
||||
|
||||
import typer
|
||||
|
||||
from compose_viz import __app_name__, __version__
|
||||
from compose_viz.parser import Parser
|
||||
from compose_viz.graph import Graph
|
||||
from compose_viz.parser import Parser
|
||||
|
||||
|
||||
class VisualizationFormats(str, Enum):
|
||||
|
@ -47,7 +49,7 @@ def compose_viz(
|
|||
help="Show the version of compose-viz.",
|
||||
callback=_version_callback,
|
||||
is_eager=True,
|
||||
)
|
||||
),
|
||||
) -> None:
|
||||
parser = Parser()
|
||||
compose = parser.parse(input_path)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from typing import List
|
||||
|
||||
from compose_viz.service import Service
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
from typing import Optional
|
||||
|
||||
|
||||
class Extends:
|
||||
def __init__(self, service_name: str, from_file: str = None):
|
||||
def __init__(self, service_name: str, from_file: Optional[str] = None):
|
||||
self._service_name = service_name
|
||||
self._from_file = from_file
|
||||
|
||||
|
|
|
@ -5,17 +5,17 @@ from compose_viz.compose import Compose
|
|||
|
||||
def apply_vertex_style(type) -> dict:
|
||||
style = {
|
||||
'service': {
|
||||
'shape': 'component',
|
||||
"service": {
|
||||
"shape": "component",
|
||||
},
|
||||
'volume': {
|
||||
'shape': 'folder',
|
||||
"volume": {
|
||||
"shape": "folder",
|
||||
},
|
||||
'network': {
|
||||
'shape': 'pentagon',
|
||||
"network": {
|
||||
"shape": "pentagon",
|
||||
},
|
||||
'port': {
|
||||
'shape': 'circle',
|
||||
"port": {
|
||||
"shape": "circle",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -24,18 +24,18 @@ def apply_vertex_style(type) -> dict:
|
|||
|
||||
def apply_edge_style(type) -> dict:
|
||||
style = {
|
||||
'ports': {
|
||||
'style': 'solid',
|
||||
"ports": {
|
||||
"style": "solid",
|
||||
},
|
||||
'links': {
|
||||
'style': 'solid',
|
||||
"links": {
|
||||
"style": "solid",
|
||||
},
|
||||
'volumes': {
|
||||
'style': 'dashed',
|
||||
"volumes": {
|
||||
"style": "dashed",
|
||||
},
|
||||
"depends_on": {
|
||||
"style": "dotted",
|
||||
},
|
||||
'depends_on': {
|
||||
'style': 'dotted',
|
||||
}
|
||||
}
|
||||
|
||||
return style[type]
|
||||
|
@ -44,7 +44,7 @@ def apply_edge_style(type) -> dict:
|
|||
class Graph:
|
||||
def __init__(self, compose: Compose, filename: str) -> None:
|
||||
self.dot = graphviz.Digraph()
|
||||
self.dot.attr('graph', background='#ffffff', pad='0.5', ratio='fill')
|
||||
self.dot.attr("graph", background="#ffffff", pad="0.5", ratio="fill")
|
||||
self.compose = compose
|
||||
self.filename = filename
|
||||
|
||||
|
@ -56,17 +56,17 @@ class Graph:
|
|||
|
||||
def render(self, format: str, cleanup: bool = True) -> None:
|
||||
for service in self.compose.services:
|
||||
self.add_vertex(service.name, 'service')
|
||||
self.add_vertex(service.name, "service")
|
||||
for network in service.networks:
|
||||
self.add_vertex("net#" + network, 'network')
|
||||
self.add_edge(service.name, "net#" + network, 'links')
|
||||
self.add_vertex("net#" + network, "network")
|
||||
self.add_edge(service.name, "net#" + network, "links")
|
||||
for volume in service.volumes:
|
||||
self.add_vertex(volume, 'volume')
|
||||
self.add_edge(service.name, volume, 'links')
|
||||
self.add_vertex(volume, "volume")
|
||||
self.add_edge(service.name, volume, "links")
|
||||
for port in service.ports:
|
||||
self.add_vertex(port, 'port')
|
||||
self.add_edge(service.name, port, 'ports')
|
||||
self.add_vertex(port, "port")
|
||||
self.add_edge(service.name, port, "ports")
|
||||
for depends_on in service.depends_on:
|
||||
self.dot.edge(depends_on, service.name, 'depends_on')
|
||||
self.dot.edge(depends_on, service.name, "depends_on")
|
||||
|
||||
self.dot.render(outfile=self.filename, format=format, cleanup=cleanup)
|
||||
|
|
|
@ -1,48 +1,60 @@
|
|||
from re import S
|
||||
from compose_viz.compose import Compose
|
||||
from compose_viz.compose import Service
|
||||
from typing import List, Optional
|
||||
|
||||
from ruamel.yaml import YAML
|
||||
|
||||
from compose_viz.compose import Compose, Service
|
||||
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def parse(self, file_path: str) -> Compose:
|
||||
# validate input file using `docker-compose config -q sys.argv[1]` first
|
||||
# load the yaml file
|
||||
with open(file_path, "r") as f:
|
||||
try:
|
||||
yaml = YAML(typ='safe', pure=True)
|
||||
yaml = YAML(typ="safe", pure=True)
|
||||
yaml_data = yaml.load(f)
|
||||
except YAML.YAMLError as exc:
|
||||
raise YAML.YAMLError
|
||||
except Exception as e:
|
||||
raise Exception(f"Error parsing file {file_path}: {e}")
|
||||
|
||||
# validate the yaml file
|
||||
if not yaml_data:
|
||||
print("Error: empty yaml file")
|
||||
raise ValueError
|
||||
|
||||
if not yaml_data.get("services"):
|
||||
print("Error: no services found")
|
||||
raise ValueError
|
||||
|
||||
# parse services data into Service objects
|
||||
services_data = yaml_data["services"]
|
||||
services = []
|
||||
|
||||
for service, service_name in zip(services_data.values(), services_data.keys()):
|
||||
#print("name: {}".format(service_name))
|
||||
# print("name: {}".format(service_name))
|
||||
|
||||
service_image: Optional[str] = None
|
||||
if service.get("image"):
|
||||
service_image = service["image"]
|
||||
#print("image: {}".format(service_image))
|
||||
# print("image: {}".format(service_image))
|
||||
|
||||
service_networks: List[str] = []
|
||||
if service.get("networks"):
|
||||
if(type(service["networks"]) is list):
|
||||
if type(service["networks"]) is list:
|
||||
service_networks = service["networks"]
|
||||
else:
|
||||
service_networks = list(service["networks"].keys())
|
||||
#print("networks: {}".format(service_networks))
|
||||
services.append(Service(
|
||||
# print("networks: {}".format(service_networks))
|
||||
|
||||
services.append(
|
||||
Service(
|
||||
name=service_name,
|
||||
image=service_image,
|
||||
networks=service_networks,
|
||||
))
|
||||
)
|
||||
)
|
||||
|
||||
# create Compose object
|
||||
compose = Compose(services)
|
||||
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
from typing import List
|
||||
from typing import List, Optional
|
||||
|
||||
from compose_viz.extends import Extends
|
||||
|
||||
|
||||
class Service:
|
||||
def __init__(self, name: str, image: str = None, ports: List[str] = [], networks: List[str] = [], volumes: List[str] = [], depends_on: List[str] = [], links: List[str] = [], extends: Extends = None) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
image: Optional[str] = None,
|
||||
ports: List[str] = [],
|
||||
networks: List[str] = [],
|
||||
volumes: List[str] = [],
|
||||
depends_on: List[str] = [],
|
||||
links: List[str] = [],
|
||||
extends: Optional[Extends] = None,
|
||||
) -> None:
|
||||
self._name = name
|
||||
|
||||
if image is None and extends is None:
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from typer.testing import CliRunner
|
||||
from compose_viz import cli
|
||||
|
||||
from compose_viz import cli
|
||||
|
||||
runner = CliRunner()
|
||||
|
||||
@pytest.mark.parametrize("file_number", [
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"file_number",
|
||||
[
|
||||
"000001",
|
||||
"000010",
|
||||
"000011",
|
||||
|
@ -71,7 +74,8 @@ runner = CliRunner()
|
|||
"111101",
|
||||
"111110",
|
||||
"111111",
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_cli(file_number: str):
|
||||
input_path = f"tests/in/{file_number}.yaml"
|
||||
output_path = f"{file_number}.png"
|
||||
|
|
|
@ -1,22 +1,29 @@
|
|||
import pytest
|
||||
|
||||
from compose_viz.extends import Extends
|
||||
from compose_viz.service import Service
|
||||
|
||||
|
||||
def test_extend_init():
|
||||
try:
|
||||
Extends(service_name='frontend', from_file='tests/in/000001.yaml')
|
||||
Extends(service_name='frontend')
|
||||
Extends(service_name="frontend", from_file="tests/in/000001.yaml")
|
||||
Extends(service_name="frontend")
|
||||
|
||||
assert True
|
||||
except:
|
||||
assert False
|
||||
except Exception as e:
|
||||
assert False, e
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
Extends(from_file='tests/in/000001.yaml')
|
||||
Extends(from_file="tests/in/000001.yaml") # type: ignore
|
||||
|
||||
|
||||
def test_service_init():
|
||||
with pytest.raises(ValueError, match=r"Both image and extends are not defined in service 'frontend', aborting."):
|
||||
Service(name='frontend')
|
||||
Service(name="frontend")
|
||||
|
||||
with pytest.raises(ValueError, match=r"Only one of image and extends can be defined in service 'frontend', aborting."):
|
||||
Service(name='frontend', image='image', extends=Extends(service_name='frontend', from_file='tests/in/000001.yaml'))
|
||||
with pytest.raises(
|
||||
ValueError, match=r"Only one of image and extends can be defined in service 'frontend', aborting."
|
||||
):
|
||||
Service(
|
||||
name="frontend", image="image", extends=Extends(service_name="frontend", from_file="tests/in/000001.yaml")
|
||||
)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
from typer.testing import CliRunner
|
||||
from compose_viz import cli, __app_name__, __version__
|
||||
|
||||
from compose_viz import __app_name__, __version__, cli
|
||||
|
||||
runner = CliRunner()
|
||||
|
||||
|
|
Loading…
Reference in a new issue