Skip to content

pyMogwai API Documentation

core

mogwaigraph

get_modern()

create the modern graph see https://tinkerpop.apache.org/docs/current/tutorials/getting-started/

Source code in mogwai/core/mogwaigraph.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
def get_modern() -> MogwaiGraph:
    """
    create the modern graph
    see https://tinkerpop.apache.org/docs/current/tutorials/getting-started/
    """
    g = MogwaiGraph()
    marko = g.add_labeled_node("Person", "marko", {"age": 29})
    vadas = g.add_labeled_node("Person", "vadas", {"age": 27})
    lop = g.add_labeled_node("Software", "lop", {"lang": "java"})
    josh = g.add_labeled_node("Person", "josh", {"age": 32})
    ripple = g.add_labeled_node("Software", "ripple", {"lang": "java"})
    peter = g.add_labeled_node("Person", "peter", {"age": 35})

    g.add_labeled_edge(marko, vadas, "knows", {"weight": 0.5})
    g.add_labeled_edge(marko, josh, "knows", {"weight": 1.0})
    g.add_labeled_edge(marko, lop, "created", {"weight": 0.4})
    g.add_labeled_edge(josh, ripple, "created", {"weight": 1.0})
    g.add_labeled_edge(josh, lop, "created", {"weight": 0.4})
    g.add_labeled_edge(peter, lop, "created", {"weight": 0.2})
    return g

steps

base_steps

branch_steps

filter_steps

map_steps

modulation_steps

traversal

AnonymousTraversal

Bases: Traversal

specialized Traversal

Source code in mogwai/core/traversal.py
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
class AnonymousTraversal(Traversal):
    """
    specialized Traversal
    """
    def __init__(self, start:'Step'=None):
        self.query_steps = [start] if start else []
        self.graph = None
        self.terminated = False
        self._needs_path = False

    #we need this since anonymous traversals need to check this before they're run.
    @property
    def needs_path(self):
        return self._needs_path or any((s.needs_path for s in self.query_steps))

    @needs_path.setter
    def needs_path(self, value):
        self._needs_path = value

    def run(self):
        raise ValueError("Cannot run anonymous traversals")

    def _build(self, traversal:Traversal):
        #first, set the necessary fields
        self.graph = traversal.graph
        self.eager = traversal.eager
        self.use_mp = traversal.use_mp
        self.verify_query = traversal.verify_query
        self.needs_path = any([s.needs_path for s in self.query_steps])
        self.optimize = traversal.optimize
        if traversal.optimize: self._optimize_query()
        if self.verify_query: self._verify_query()
        if self.query_steps[0].isstart:
            self.query_steps[0].set_traversal(self)
        super()._build()

    def __call__(self, traversers:Iterable['Traverser']) -> Iterable['Traverser']:
        #if this traversal is empty, just reflect back the incoming traversers
        if len(self.query_steps)==0:
            return traversers
        self.traversers = traversers
        if self.eager:
            try:
                for step in self.query_steps:
                    logger.debug("Running step:"+ str(step))
                    self.traversers = step(self.traversers)
                    if not type(self.traversers) is list:
                        self.traversers = list(self.traversers)
            except Exception as e:
                raise GraphTraversalError(f"Something went wrong in step {step.print_query()}")
        else:
            for step in self.query_steps:
                logger.debug("Running step:"+ str(step))
                self.traversers = step(self.traversers)
            #TODO: Try to do some fancy error handling
        return self.traversers

decorators

decorators

mogwai_cmd

Created on 2024-08-15

@author: wf

MogwaiCmd

Bases: WebserverCmd

command line handling for nicesprinkler

Source code in mogwai/mogwai_cmd.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class MogwaiCmd(WebserverCmd):
    """
    command line handling for nicesprinkler
    """

    def __init__(self):
        """
        constructor
        """
        config = MogwaiWebServer.get_config()
        WebserverCmd.__init__(self, config, MogwaiWebServer, DEBUG)

    def getArgParser(self, description: str, version_msg) -> ArgumentParser:
        """
        override the default argparser call
        """
        parser = super().getArgParser(description, version_msg)

        return parser

__init__()

constructor

Source code in mogwai/mogwai_cmd.py
20
21
22
23
24
25
def __init__(self):
    """
    constructor
    """
    config = MogwaiWebServer.get_config()
    WebserverCmd.__init__(self, config, MogwaiWebServer, DEBUG)

getArgParser(description, version_msg)

override the default argparser call

Source code in mogwai/mogwai_cmd.py
27
28
29
30
31
32
33
def getArgParser(self, description: str, version_msg) -> ArgumentParser:
    """
    override the default argparser call
    """
    parser = super().getArgParser(description, version_msg)

    return parser

main(argv=None)

main call

Source code in mogwai/mogwai_cmd.py
36
37
38
39
40
41
42
def main(argv: list = None):
    """
    main call
    """
    cmd = MogwaiCmd()
    exit_code = cmd.cmd_main(argv)
    return exit_code

version

Created on 2024-08-15

@author: wf

Version dataclass

Bases: object

Version handling for pyMogwai

Source code in mogwai/version.py
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@dataclass
class Version(object):
    """
    Version handling for pyMogwai
    """

    name = "pymogwai"
    version = mogwai.__version__
    date = "2024-08-15"
    updated = "2024-08-15"
    description = "python native gremlin implementation"

    authors = "Wolfgang Fahl"

    chat_url = "https://github.com/juupje/pyMogwai/discussions"
    doc_url = "https://cr.bitplan.com/index.php/pyMogwai"
    cm_url = "https://github.com/juupje/pyMogwai"

    license = f"""Copyright 2024 contributors. All rights reserved.

  Licensed under the Apache License 2.0
  http://www.apache.org/licenses/LICENSE-2.0

  Distributed on an "AS IS" basis without warranties
  or conditions of any kind, either express or implied."""
    longDescription = f"""{name} version {version}
{description}

  Created by {authors} on {date} last updated {updated}"""

web

server

Created on 2024-08-15

@author: wf

MogwaiSolution

Bases: InputWebSolution

the Mogwai solution

Source code in mogwai/web/server.py
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
class MogwaiSolution(InputWebSolution):
    """
    the Mogwai solution
    """

    def __init__(self, webserver: MogwaiWebServer, client: Client):
        """
        Initialize the solution

        Args:
            webserver (MogwaiWebServer): The webserver instance associated with this context.
            client (Client): The client instance this context is associated with.
        """
        super().__init__(webserver, client)
        self.graph = None

    def setup_menu(self, detailed: bool = True):
        """
        setup the menu
        """
        super().setup_menu(detailed=detailed)
        ui.button(icon="menu", on_click=lambda: self.header.toggle())
        with self.header:
            if self.webserver.authenticated():
                self.link_button("logout", "/logout", "logout", new_tab=False)
            else:
                self.link_button("login", "/login", "login", new_tab=False)

    async def login_ui(self):
        """
        login ui
        """
        await self.webserver.login.login(self)

    async def home(self):
        """Provide the main content page"""
        await self.query_graph()

    async def parse_file(self):
        """File parsing page"""
        def setup_parse():
            ui.label("Parse File").classes('text-h4')
            file_upload = ui.upload(label="Choose a file", multiple=False, auto_upload=True)
            file_upload.on('upload', self.handle_upload)

        await self.setup_content_div(setup_parse)

    async def query_graph(self):
        """Graph querying page"""
        def setup_query():
            ui.label("Query Graph").classes('text-h4')
            if self.graph:
                query = ui.input(label="Enter Gremlin query")
                ui.button("Run Query", on_click=lambda: self.run_query(query.value))
            else:
                ui.label("No graph loaded. Please parse a file first.")

        await self.setup_content_div(setup_query)

    def handle_upload(self, e):
        """Handle file upload"""
        file = e.content
        if file.name.endswith('.graphml'):
            temp_path = os.path.join(tempfile.gettempdir(), file.name)
            with open(temp_path, 'wb') as f:
                f.write(file.read())
            self.graph = graphml_to_mogwaigraph(file=temp_path)
        elif file.name.endswith('.xlsx'):
            self.graph = EXCELGraph(file)
        elif file.name.endswith('.pdf'):
            self.graph = PDFGraph(file)
        elif file.name.endswith('.pptx'):
            self.graph = powerpoint_converter.PPGraph(file=file)
        else:
            ui.notify(f"Unsupported file type: {file.name}", type="negative")
            return

        if self.graph:
            ui.notify("File parsed successfully", type="positive")
            ui.label(f"Imported a graph with {len(self.graph.nodes)} nodes and {len(self.graph.edges)} edges.")

    def run_query(self, query):
        """Run a Gremlin query on the graph"""
        if not self.graph:
            ui.notify("No graph loaded. Please parse a file first.", type="warning")
            return

        g = Trav.MogwaiGraphTraversalSource(self.graph)
        try:
            result = eval(query, {'g': g})
            res = result.run()
            ui.notify(f"Query result: {res}")
        except Exception as e:
            ui.notify(f"Error executing query: {str(e)}", type="negative")
__init__(webserver, client)

Initialize the solution

Parameters:

Name Type Description Default
webserver MogwaiWebServer

The webserver instance associated with this context.

required
client Client

The client instance this context is associated with.

required
Source code in mogwai/web/server.py
81
82
83
84
85
86
87
88
89
90
def __init__(self, webserver: MogwaiWebServer, client: Client):
    """
    Initialize the solution

    Args:
        webserver (MogwaiWebServer): The webserver instance associated with this context.
        client (Client): The client instance this context is associated with.
    """
    super().__init__(webserver, client)
    self.graph = None
handle_upload(e)

Handle file upload

Source code in mogwai/web/server.py
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
def handle_upload(self, e):
    """Handle file upload"""
    file = e.content
    if file.name.endswith('.graphml'):
        temp_path = os.path.join(tempfile.gettempdir(), file.name)
        with open(temp_path, 'wb') as f:
            f.write(file.read())
        self.graph = graphml_to_mogwaigraph(file=temp_path)
    elif file.name.endswith('.xlsx'):
        self.graph = EXCELGraph(file)
    elif file.name.endswith('.pdf'):
        self.graph = PDFGraph(file)
    elif file.name.endswith('.pptx'):
        self.graph = powerpoint_converter.PPGraph(file=file)
    else:
        ui.notify(f"Unsupported file type: {file.name}", type="negative")
        return

    if self.graph:
        ui.notify("File parsed successfully", type="positive")
        ui.label(f"Imported a graph with {len(self.graph.nodes)} nodes and {len(self.graph.edges)} edges.")
home() async

Provide the main content page

Source code in mogwai/web/server.py
110
111
112
async def home(self):
    """Provide the main content page"""
    await self.query_graph()
login_ui() async

login ui

Source code in mogwai/web/server.py
104
105
106
107
108
async def login_ui(self):
    """
    login ui
    """
    await self.webserver.login.login(self)
parse_file() async

File parsing page

Source code in mogwai/web/server.py
114
115
116
117
118
119
120
121
async def parse_file(self):
    """File parsing page"""
    def setup_parse():
        ui.label("Parse File").classes('text-h4')
        file_upload = ui.upload(label="Choose a file", multiple=False, auto_upload=True)
        file_upload.on('upload', self.handle_upload)

    await self.setup_content_div(setup_parse)
query_graph() async

Graph querying page

Source code in mogwai/web/server.py
123
124
125
126
127
128
129
130
131
132
133
async def query_graph(self):
    """Graph querying page"""
    def setup_query():
        ui.label("Query Graph").classes('text-h4')
        if self.graph:
            query = ui.input(label="Enter Gremlin query")
            ui.button("Run Query", on_click=lambda: self.run_query(query.value))
        else:
            ui.label("No graph loaded. Please parse a file first.")

    await self.setup_content_div(setup_query)
run_query(query)

Run a Gremlin query on the graph

Source code in mogwai/web/server.py
157
158
159
160
161
162
163
164
165
166
167
168
169
def run_query(self, query):
    """Run a Gremlin query on the graph"""
    if not self.graph:
        ui.notify("No graph loaded. Please parse a file first.", type="warning")
        return

    g = Trav.MogwaiGraphTraversalSource(self.graph)
    try:
        result = eval(query, {'g': g})
        res = result.run()
        ui.notify(f"Query result: {res}")
    except Exception as e:
        ui.notify(f"Error executing query: {str(e)}", type="negative")
setup_menu(detailed=True)

setup the menu

Source code in mogwai/web/server.py
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
def setup_menu(self, detailed: bool = True):
    """
    setup the menu
    """
    super().setup_menu(detailed=detailed)
    ui.button(icon="menu", on_click=lambda: self.header.toggle())
    with self.header:
        if self.webserver.authenticated():
            self.link_button("logout", "/logout", "logout", new_tab=False)
        else:
            self.link_button("login", "/login", "login", new_tab=False)

MogwaiWebServer

Bases: InputWebserver

Mogwai WebServer

Source code in mogwai/web/server.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
class MogwaiWebServer(InputWebserver):
    """
    Mogwai WebServer
    """
    @classmethod
    def get_config(cls) -> WebserverConfig:
        copy_right = "(c)2024 Wolfgang Fahl"
        config = WebserverConfig(
            copy_right=copy_right,
            version=Version(),
            default_port=9850,
            short_name="mogwai",
        )
        server_config = WebserverConfig.get(config)
        server_config.solution_class = MogwaiSolution
        return server_config

    def __init__(self):
        """Constructs all the necessary attributes for the WebServer object."""
        InputWebserver.__init__(self, config=MogwaiWebServer.get_config())
        users = Users("~/.solutions/mogwai")
        self.login = Login(self, users)

        @ui.page("/")
        async def home(client: Client):
            return await self.page(client, MogwaiSolution.home)

        @ui.page("/parse")
        async def parse_file(client: Client):
            if not self.login.authenticated():
                return RedirectResponse("/login")
            return await self.page(client, MogwaiSolution.parse_file)

        @ui.page("/query")
        async def query_graph(client: Client):
            return await self.page(client, MogwaiSolution.query_graph)

        @ui.page("/login")
        async def login(client: Client):
            return await self.page(client, MogwaiSolution.login_ui)

        @ui.page("/logout")
        async def logout(client: Client) -> RedirectResponse:
            if self.login.authenticated():
                await self.login.logout()
            return RedirectResponse("/")

    def authenticated(self) -> bool:
        """
        Check if the user is authenticated.
        Returns:
            True if the user is authenticated, False otherwise.
        """
        return self.login.authenticated()
__init__()

Constructs all the necessary attributes for the WebServer object.

Source code in mogwai/web/server.py
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def __init__(self):
    """Constructs all the necessary attributes for the WebServer object."""
    InputWebserver.__init__(self, config=MogwaiWebServer.get_config())
    users = Users("~/.solutions/mogwai")
    self.login = Login(self, users)

    @ui.page("/")
    async def home(client: Client):
        return await self.page(client, MogwaiSolution.home)

    @ui.page("/parse")
    async def parse_file(client: Client):
        if not self.login.authenticated():
            return RedirectResponse("/login")
        return await self.page(client, MogwaiSolution.parse_file)

    @ui.page("/query")
    async def query_graph(client: Client):
        return await self.page(client, MogwaiSolution.query_graph)

    @ui.page("/login")
    async def login(client: Client):
        return await self.page(client, MogwaiSolution.login_ui)

    @ui.page("/logout")
    async def logout(client: Client) -> RedirectResponse:
        if self.login.authenticated():
            await self.login.logout()
        return RedirectResponse("/")
authenticated()

Check if the user is authenticated. Returns: True if the user is authenticated, False otherwise.

Source code in mogwai/web/server.py
68
69
70
71
72
73
74
def authenticated(self) -> bool:
    """
    Check if the user is authenticated.
    Returns:
        True if the user is authenticated, False otherwise.
    """
    return self.login.authenticated()