Passed
Push — main ( da19e4...14c1e8 )
by Eran
01:21
created

graphinate.cli.import_from_string()   B

Complexity

Conditions 8

Size

Total Lines 31
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 22
nop 1
dl 0
loc 31
rs 7.3333
c 0
b 0
f 0
1
import functools
2
import importlib
3
import json
4
from typing import Any
5
6
import click
7
8
from graphinate import GraphModel, builders, graphql, materialize
9
from graphinate.server import DEFAULT_PORT
10
11
12
def _get_kwargs(ctx) -> dict:
13
    return dict([item.strip('--').split('=') for item in ctx.args if item.startswith("--")])
14
15
16
def import_from_string(import_str: Any) -> Any:
17
    """Import an object from a string reference {module-name}:{variable-name}
18
    For example given a var `model=GraphModel()` defined in app.py file,
19
    then the reference would be app:model
20
    """
21
22
    if not isinstance(import_str, str):
23
        return import_str
24
25
    module_str, _, attrs_str = import_str.partition(":")
26
    if not module_str or not attrs_str:
27
        message = f"Import string '{import_str}' must be in format '<module>:<attribute>'."
28
        raise ImportFromStringError(message)
29
30
    try:
31
        module = importlib.import_module(module_str)
32
    except ModuleNotFoundError as exc:
33
        if exc.name != module_str:
34
            raise exc from None
35
        message = f"Could not import module '{module_str}'."
36
        raise ImportFromStringError(message) from exc
37
38
    instance = module
39
    try:
40
        for attr_str in attrs_str.split("."):
41
            instance = getattr(instance, attr_str)
42
    except AttributeError as exc:
43
        message = f"Attribute '{attrs_str}' not found in module '{module_str}'."
44
        raise ImportFromStringError(message) from exc
45
46
    return instance
47
48
49
class ImportFromStringError(Exception):
50
    pass
51
52
53
class GraphModelType(click.ParamType):
54
    name = "MODEL"
55
56
    def convert(self, value, param, ctx) -> GraphModel:
57
        if isinstance(value, GraphModel):
58
            return value
59
60
        try:
61
            return import_from_string(value) if isinstance(value, str) else value
62
        except Exception as e:
63
            self.fail(str(e))
64
65
66
model_option = click.option('-m', '--model',
67
                            type=GraphModelType(),
68
                            help="A GraphModel instance reference {module-name}:{GraphModel-instance-variable-name}"
69
                                 " For example given a var `model=GraphModel()` defined in app.py file, then the"
70
                                 " reference would be app:model")
71
72
73
@click.group()
74
@click.pass_context
75
def cli(ctx):
76
    pass
77
78
79
@cli.command()
80
@model_option
81
@click.pass_context
82
def save(ctx, model):
83
    with open(f"{model.name}.json", mode='w') as fp:
84
        materialize(model=model,
85
                    builder=builders.D3Builder,
86
                    actualizer=functools.partial(json.dump, fp=fp, default=str),
87
                    **_get_kwargs(ctx))
88
89
90
@cli.command()
91
@model_option
92
@click.option('-p', '--port', type=int, default=DEFAULT_PORT, help='Port number.')
93
@click.pass_context
94
def server(ctx, model, port):
95
    message = """
96
     ██████╗ ██████╗  █████╗ ██████╗ ██╗  ██╗██╗███╗   ██╗ █████╗ ████████╗███████╗
97
    ██╔════╝ ██╔══██╗██╔══██╗██╔══██╗██║  ██║██║████╗  ██║██╔══██╗╚══██╔══╝██╔════╝
98
    ██║  ███╗██████╔╝███████║██████╔╝███████║██║██╔██╗ ██║███████║   ██║   █████╗
99
    ██║   ██║██╔══██╗██╔══██║██╔═══╝ ██╔══██║██║██║╚██╗██║██╔══██║   ██║   ██╔══╝
100
    ╚██████╔╝██║  ██║██║  ██║██║     ██║  ██║██║██║ ╚████║██║  ██║   ██║   ███████╗
101
     ╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝     ╚═╝  ╚═╝╚═╝╚═╝  ╚═══╝╚═╝  ╚═╝   ╚═╝   ╚══════╝"""
102
    click.echo(message)
103
    materialize(model=model,
104
                builder=builders.GraphQLBuilder,
105
                actualizer=functools.partial(graphql, port=port),
106
                **_get_kwargs(ctx))
107