Graphinate 0.2.21__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {graphinate-0.2.21 → graphinate-0.3.0}/.github/workflows/test.yml +1 -1
- {graphinate-0.2.21 → graphinate-0.3.0}/PKG-INFO +12 -13
- {graphinate-0.2.21 → graphinate-0.3.0}/README.md +1 -1
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/start.md +1 -1
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/code/python_ast.py +14 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/code/python_dependencies.py +7 -0
- graphinate-0.3.0/examples/github/_client.py +132 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/github/followers.py +16 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/github/repositories.py +7 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/math/graph_atlas.py +30 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/math/polygonal_graph.py +12 -2
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/system/processes.py +7 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/web/page_links.py +10 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/pyproject.toml +11 -12
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/color.py +4 -3
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/materializers/matplotlib.py +9 -7
- graphinate-0.3.0/src/graphinate/server/__init__.py +80 -0
- graphinate-0.3.0/src/graphinate/tools/mutators.py +153 -0
- graphinate-0.2.21/examples/github/_client.py +0 -61
- graphinate-0.2.21/src/graphinate/server/__init__.py +0 -110
- graphinate-0.2.21/src/graphinate/tools/mutators.py +0 -66
- {graphinate-0.2.21 → graphinate-0.3.0}/.coveragerc +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/.github/dependabot.yml +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/.github/workflows/codeql.yml +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/.github/workflows/publish-docs.yaml +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/.github/workflows/publish.yml +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/.github/workflows/test-beta.yml +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/.gitignore +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/LICENSE +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/STATS.md +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/acknowledge.md +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/assets/images/logo-128.png +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/assets/images/network_graph.png +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/assets/stylesheets/extra.css +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/dev.md +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/examples/code.md +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/examples/github.md +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/examples/math.md +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/examples/system.md +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/examples/web.md +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/gen_ref_pages.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/index.md +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/intro.md +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/usage/cli.md +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/docs/usage/lib.md +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/code/requirements.txt +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/github/commits_visibilty_graph.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/github/followers.graphql +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/github/graphql.config.yml +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/github/repositories.graphql +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/github/requirements.txt +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/math/requirements.txt +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/system/requirements.txt +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/examples/web/requirements.txt +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/mkdocs.yml +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/playground/ethernet/traceroute.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/playground/genric_graph.graphql +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/playground/graphql.config.yml +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/playground/house_of_graphs.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/playground/social/albums.json +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/playground/social/musicisians.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/playground/text/nlp_graph.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/playground/text/requirements.txt +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/playground/time_series/requirements.txt +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/playground/time_series/visibility_graph.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/sonar-project.properties +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/__init__.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/__main__.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/builders.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/cli.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/materializers/__init__.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/modeling.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/server/starlette/__init__.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/server/starlette/views.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/server/web/__init__.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/server/web/elements/__init__.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/server/web/elements/index.html +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/server/web/graphiql/__init__.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/server/web/graphiql/index.html +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/server/web/rapidoc/__init__.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/server/web/rapidoc/index.html +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/server/web/static/images/logo-128.png +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/server/web/static/images/network_graph.png +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/server/web/viewer/__init__.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/server/web/viewer/index.html +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/server/web/voyager/__init__.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/server/web/voyager/index.html +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/tools/__init__.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/tools/converters.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/tools/gui.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/src/graphinate/typing.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/tests/conftest.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/tests/graphinate/test_builders.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/tests/graphinate/test_cli.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/tests/graphinate/test_color.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/tests/graphinate/test_materializers.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/tests/graphinate/test_modeling.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/tests/graphinate/test_server.py +0 -0
- {graphinate-0.2.21 → graphinate-0.3.0}/tests/graphinate/test_tools.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: Graphinate
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Graphinate. Data to Graphs.
|
|
5
5
|
Project-URL: Homepage, https://erivlis.github.io/graphinate
|
|
6
6
|
Project-URL: Documentation, https://erivlis.github.io/graphinate
|
|
@@ -9,7 +9,7 @@ Project-URL: Source, https://github.com/erivlis/graphinate
|
|
|
9
9
|
Author-email: Eran Rivlis <eran@rivlis.info>
|
|
10
10
|
License-File: LICENSE
|
|
11
11
|
Keywords: declarative,graph
|
|
12
|
-
Classifier: Development Status ::
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: Intended Audience :: Information Technology
|
|
15
15
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -18,7 +18,6 @@ Classifier: Natural Language :: English
|
|
|
18
18
|
Classifier: Operating System :: OS Independent
|
|
19
19
|
Classifier: Programming Language :: Python :: 3
|
|
20
20
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.10
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
24
23
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -26,13 +25,13 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
|
26
25
|
Classifier: Topic :: Scientific/Engineering
|
|
27
26
|
Classifier: Topic :: Software Development :: Libraries
|
|
28
27
|
Classifier: Typing :: Typed
|
|
29
|
-
Requires-Python: >=3.
|
|
28
|
+
Requires-Python: >=3.10
|
|
30
29
|
Requires-Dist: click>=8.1.7
|
|
31
|
-
Requires-Dist: inflect>=7.
|
|
30
|
+
Requires-Dist: inflect>=7.3.0
|
|
32
31
|
Requires-Dist: loguru>=0.7.2
|
|
33
|
-
Requires-Dist: matplotlib>=3.
|
|
32
|
+
Requires-Dist: matplotlib>=3.9.0
|
|
34
33
|
Requires-Dist: networkx>=3.3
|
|
35
|
-
Requires-Dist: strawberry-graphql[asgi,opentelemetry]>=0.
|
|
34
|
+
Requires-Dist: strawberry-graphql[asgi,opentelemetry]>=0.235.1
|
|
36
35
|
Provides-Extra: dev
|
|
37
36
|
Requires-Dist: pipdeptree; extra == 'dev'
|
|
38
37
|
Requires-Dist: ruff; extra == 'dev'
|
|
@@ -45,17 +44,17 @@ Requires-Dist: mkdocs-material; extra == 'docs'
|
|
|
45
44
|
Requires-Dist: mkdocs-section-index; extra == 'docs'
|
|
46
45
|
Requires-Dist: mkdocstrings-python; extra == 'docs'
|
|
47
46
|
Provides-Extra: plot
|
|
48
|
-
Requires-Dist: scipy>=1.
|
|
47
|
+
Requires-Dist: scipy>=1.14.0; extra == 'plot'
|
|
49
48
|
Provides-Extra: server
|
|
50
49
|
Requires-Dist: starlette-prometheus; extra == 'server'
|
|
51
|
-
Requires-Dist: uvicorn[standard]>=0.
|
|
50
|
+
Requires-Dist: uvicorn[standard]>=0.30.1; extra == 'server'
|
|
52
51
|
Provides-Extra: test
|
|
53
52
|
Requires-Dist: faker>=23.2.1; extra == 'test'
|
|
54
|
-
Requires-Dist: pytest-asyncio>=0.23.
|
|
53
|
+
Requires-Dist: pytest-asyncio>=0.23.7; extra == 'test'
|
|
55
54
|
Requires-Dist: pytest-cov>=5.0.0; extra == 'test'
|
|
56
55
|
Requires-Dist: pytest-randomly>=3.15.0; extra == 'test'
|
|
57
|
-
Requires-Dist: pytest-xdist>=3.
|
|
58
|
-
Requires-Dist: pytest>=8.
|
|
56
|
+
Requires-Dist: pytest-xdist>=3.6.1; extra == 'test'
|
|
57
|
+
Requires-Dist: pytest>=8.2.2; extra == 'test'
|
|
59
58
|
Description-Content-Type: text/markdown
|
|
60
59
|
|
|
61
60
|
# [Graphinate. Data to Graphs.](https://erivlis.github.io/graphinate/)
|
|
@@ -153,7 +152,7 @@ To install with server support
|
|
|
153
152
|
pip install graphinate[server]
|
|
154
153
|
```
|
|
155
154
|
|
|
156
|
-
**Graphinate** officially supports Python >= 3.
|
|
155
|
+
**Graphinate** officially supports Python >= 3.10.
|
|
157
156
|
|
|
158
157
|
### Example
|
|
159
158
|
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Define functions to create an abstract syntax tree (AST) graph model using the 'graphinate' library.
|
|
3
|
+
The 'ast_graph_model' function parses the AST of a specified class and creates nodes and edges for the graph model.
|
|
4
|
+
The nodes represent AST nodes with their type and label, while the edges represent relationships between AST nodes.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
1
8
|
import ast
|
|
2
9
|
import hashlib
|
|
3
10
|
import inspect
|
|
@@ -35,6 +42,13 @@ def _ast_edge(parsed_ast: AST):
|
|
|
35
42
|
|
|
36
43
|
|
|
37
44
|
def ast_graph_model():
|
|
45
|
+
"""
|
|
46
|
+
Create an abstract syntax tree (AST) graph model.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
GraphModel: A graph model representing the AST nodes and their relationships.
|
|
50
|
+
"""
|
|
51
|
+
|
|
38
52
|
graph_model = graphinate.model(name='AST Graph')
|
|
39
53
|
|
|
40
54
|
root_ast_node = ast.parse(inspect.getsource(graphinate.builders.D3Builder))
|
|
@@ -6,6 +6,13 @@ from pipdeptree._non_host import handle_non_host_target
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def dependency_graph_model():
|
|
9
|
+
"""
|
|
10
|
+
Generate a dependency graph model.
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
GraphModel: A graph model representing the dependency graph.
|
|
14
|
+
"""
|
|
15
|
+
|
|
9
16
|
options = get_options(args=None)
|
|
10
17
|
handle_non_host_target(options)
|
|
11
18
|
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import os
|
|
3
|
+
from collections.abc import Iterable
|
|
4
|
+
from typing import Optional, Union
|
|
5
|
+
|
|
6
|
+
# see requirements.txt
|
|
7
|
+
from github import Auth, Github
|
|
8
|
+
from github.AuthenticatedUser import AuthenticatedUser
|
|
9
|
+
from github.Commit import Commit
|
|
10
|
+
from github.File import File
|
|
11
|
+
from github.NamedUser import NamedUser
|
|
12
|
+
from github.Repository import Repository
|
|
13
|
+
|
|
14
|
+
# define a 'GITHUB_TOKEN' Env Var.
|
|
15
|
+
token = os.getenv('GITHUB_TOKEN')
|
|
16
|
+
|
|
17
|
+
# using an access token
|
|
18
|
+
auth = Auth.Token(token)
|
|
19
|
+
|
|
20
|
+
# Public Web GitHub
|
|
21
|
+
client = Github(auth=auth)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# or GitHub Enterprise with custom hostname
|
|
25
|
+
# g = Github(auth=auth, base_url='https://{hostname}/api/v3')
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@functools.lru_cache
|
|
29
|
+
def github_user(user_id: Optional[str] = None) -> Union[NamedUser, AuthenticatedUser]:
|
|
30
|
+
"""
|
|
31
|
+
Get the GitHub user object for the specified user ID or the authenticated user.
|
|
32
|
+
|
|
33
|
+
Parameters:
|
|
34
|
+
user_id (Optional[str]): The ID of the user to retrieve.
|
|
35
|
+
If not provided, retrieve the authenticated user.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Union[NamedUser, AuthenticatedUser]: The GitHub user object corresponding to the user ID provided,
|
|
39
|
+
or the authenticated user if no user ID is specified.
|
|
40
|
+
Note:
|
|
41
|
+
This function requires authentication with a valid GitHub token.
|
|
42
|
+
"""
|
|
43
|
+
user = client.get_user(user_id) if user_id else client.get_user()
|
|
44
|
+
return user
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@functools.lru_cache
|
|
48
|
+
def github_repositories(
|
|
49
|
+
user_id: Optional[str] = None,
|
|
50
|
+
repo_id: Optional[str] = None) -> Iterable[Repository]:
|
|
51
|
+
"""
|
|
52
|
+
Get the GitHub repositories for the specified user ID or the authenticated user.
|
|
53
|
+
|
|
54
|
+
Parameters:
|
|
55
|
+
user_id (Optional[str]): The ID of the user whose repositories to retrieve.
|
|
56
|
+
If not provided, retrieve repositories of the authenticated user.
|
|
57
|
+
repo_id (Optional[str]): The ID of the repository to retrieve.
|
|
58
|
+
If provided, only that repository will be returned.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Iterable[Repository]:
|
|
62
|
+
A list of GitHub repository objects corresponding to the user ID and/or repository ID provided.
|
|
63
|
+
|
|
64
|
+
Note:
|
|
65
|
+
This function requires authentication with a valid GitHub token.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
user = github_user(user_id)
|
|
69
|
+
if repo_id and (repo := user.get_repo(name=repo_id)):
|
|
70
|
+
return [repo]
|
|
71
|
+
else:
|
|
72
|
+
return user.get_repos()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def github_commits(
|
|
76
|
+
repo: Repository,
|
|
77
|
+
commit_id: Optional[str] = None) -> Iterable[Commit]:
|
|
78
|
+
"""
|
|
79
|
+
Retrieve commits from a GitHub repository.
|
|
80
|
+
|
|
81
|
+
Parameters:
|
|
82
|
+
repo (Repository): The GitHub repository object from which to retrieve commits.
|
|
83
|
+
commit_id (str, optional): The ID of the commit to retrieve.
|
|
84
|
+
If provided, only that commit will be returned.
|
|
85
|
+
Defaults to None.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Iterable[Commit]: An Iterable of Commit objects representing the commits in the repository.
|
|
89
|
+
|
|
90
|
+
Example:
|
|
91
|
+
To retrieve all commits from a repository:
|
|
92
|
+
```
|
|
93
|
+
for commit in github_commits(repo):
|
|
94
|
+
print(commit)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
To retrieve a specific commit by ID:
|
|
98
|
+
```
|
|
99
|
+
for commit in github_commits(repo, commit_id='abcdef123456'):
|
|
100
|
+
print(commit)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Note:
|
|
104
|
+
This function requires authentication with a valid GitHub token.
|
|
105
|
+
"""
|
|
106
|
+
if commit_id and (commit := repo.get_commit(sha=commit_id)):
|
|
107
|
+
yield commit
|
|
108
|
+
else:
|
|
109
|
+
yield from repo.get_commits()
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def github_files(
|
|
113
|
+
commit: Commit,
|
|
114
|
+
file_id: Optional[str] = None) -> Iterable[File]:
|
|
115
|
+
"""
|
|
116
|
+
Retrieves Files from a GitHub Commit
|
|
117
|
+
|
|
118
|
+
Parameters:
|
|
119
|
+
commit (Commit): A Commit object from the GitHub API.
|
|
120
|
+
file_id (Optional[str]): An optional parameter specifying the filename to filter the files. Default is None.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Iterable[File]: An Iterable of File objects based on the filtering criteria.
|
|
124
|
+
|
|
125
|
+
Note:
|
|
126
|
+
This function requires authentication with a valid GitHub token.
|
|
127
|
+
"""
|
|
128
|
+
files: list[File] = commit.files
|
|
129
|
+
if file_id:
|
|
130
|
+
yield from [file for file in files if file.filename == file_id]
|
|
131
|
+
else:
|
|
132
|
+
yield from files
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Defines a function `followers_graph_model` that creates a graph model representing GitHub followers.
|
|
3
|
+
It recursively fetches followers of a given user up to a specified maximum depth.
|
|
4
|
+
The function yields edges between users in the graph.
|
|
5
|
+
"""
|
|
6
|
+
|
|
1
7
|
from typing import Optional
|
|
2
8
|
|
|
3
9
|
import graphinate
|
|
@@ -7,6 +13,16 @@ DEPTH = 0
|
|
|
7
13
|
|
|
8
14
|
|
|
9
15
|
def followers_graph_model(max_depth: int = DEPTH):
|
|
16
|
+
"""
|
|
17
|
+
Create a graph model representing GitHub followers.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
max_depth (int): The maximum depth to fetch followers recursively (default is 0).
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
GraphModel: A graph model representing GitHub followers.
|
|
24
|
+
"""
|
|
25
|
+
|
|
10
26
|
graph_model = graphinate.model(name='Github Followers Graph')
|
|
11
27
|
|
|
12
28
|
def _followers(user_id: Optional[str] = None, depth: int = 0, **kwargs):
|
|
@@ -8,6 +8,13 @@ from _client import github_commits, github_files, github_repositories, github_us
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def repo_graph_model(): # noqa: C901
|
|
11
|
+
"""
|
|
12
|
+
Create a graph model for GitHub repositories.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
GraphModel: A graph model representing GitHub repositories with nodes and edges.
|
|
16
|
+
"""
|
|
17
|
+
|
|
11
18
|
graph_model = graphinate.model(name='GitHub Repository Graph')
|
|
12
19
|
|
|
13
20
|
@graph_model.edge
|
|
@@ -35,6 +35,21 @@ def spiral_torus_edges(n, k):
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def atlas():
|
|
38
|
+
"""
|
|
39
|
+
Generate a dictionary of various graph structures and models based on the provided atlas.
|
|
40
|
+
The function creates different types of graphs and models using NetworkX library.
|
|
41
|
+
The generated graphs include Tetrahedron, Cube, Octahedron, Dodecahedron, Icosahedron, Tesseract, Truncated Cube,
|
|
42
|
+
Truncated Tetrahedron, Ladder, Ring, Möbius, Cylinder, Spiral, Spiral Torus, and Circulant[10,[2]].
|
|
43
|
+
Additionally, the function includes adjacency mappings for specific named graphs like
|
|
44
|
+
Buckyball - Truncated Icosahedral Graph, D30 - Rhombic Triacontahedral Graph, Small Rhombicosidodecahedral Graph,
|
|
45
|
+
Small Rhombicuboctahedral Graph, Great Rhombicosidodecahedral Graph, Disdyakis Dodecahedral Graph,
|
|
46
|
+
Deltoidal Icositetrahedral Graph, Icosidodecahedral Graph, Deltoidal Hexecontahedral Graph, Kocohl74,
|
|
47
|
+
Utility Graph, Errara Graph, and Dragon Curve Blob 6.
|
|
48
|
+
The adjacency mappings define the connections between nodes in each named graph.
|
|
49
|
+
The function returns a dictionary
|
|
50
|
+
containing the named graphs as keys and their corresponding NetworkX graph objects as values.
|
|
51
|
+
"""
|
|
52
|
+
|
|
38
53
|
ladder_size = 16
|
|
39
54
|
ladder = nx.ladder_graph(ladder_size)
|
|
40
55
|
|
|
@@ -775,6 +790,21 @@ def atlas():
|
|
|
775
790
|
|
|
776
791
|
|
|
777
792
|
def models(iterable):
|
|
793
|
+
"""
|
|
794
|
+
Generate a graph model based on the provided iterable of graphs.
|
|
795
|
+
The function creates a graph model named 'Graph Atlas' using the 'graphinate' library.
|
|
796
|
+
It then combines all the graphs from the input iterable into a single disjoint union graph using NetworkX library.
|
|
797
|
+
The function defines edges for the combined graph by iterating over all edges in the disjoint union graph and
|
|
798
|
+
yielding dictionaries with 'source' and 'target' keys representing the edge connections.
|
|
799
|
+
Finally, the function yields the created graph model containing the combined graph with defined edges.
|
|
800
|
+
|
|
801
|
+
Args:
|
|
802
|
+
iterable: An iterable containing graphs to be combined into a single graph model.
|
|
803
|
+
|
|
804
|
+
Yields:
|
|
805
|
+
GraphModel: A graph model containing the combined graph with defined edges.
|
|
806
|
+
"""
|
|
807
|
+
|
|
778
808
|
graph_model = graphinate.model('Graph Atlas')
|
|
779
809
|
|
|
780
810
|
graph_atlas = nx.disjoint_union_all(g for _, g in iterable)
|
|
@@ -5,7 +5,17 @@ import networkx as nx
|
|
|
5
5
|
N: int = 8
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
def
|
|
8
|
+
def polygonal_graph_model(number_of_sides: int = N):
|
|
9
|
+
"""
|
|
10
|
+
Create a polygonal graph model.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
number_of_sides (int): Number of sides in the polygon. Defaults to N.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
GraphModel: A graph model representing a polygonal graph.
|
|
17
|
+
"""
|
|
18
|
+
|
|
9
19
|
# Define GraphModel
|
|
10
20
|
graph_model = graphinate.model(name="Octagonal Graph")
|
|
11
21
|
|
|
@@ -19,7 +29,7 @@ def get_graph_model(number_of_sides: int = N):
|
|
|
19
29
|
return graph_model
|
|
20
30
|
|
|
21
31
|
|
|
22
|
-
model =
|
|
32
|
+
model = polygonal_graph_model()
|
|
23
33
|
|
|
24
34
|
if __name__ == '__main__':
|
|
25
35
|
use_materialize = True
|
|
@@ -7,6 +7,13 @@ import psutil
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def processes_graph_model():
|
|
10
|
+
"""
|
|
11
|
+
Create a graph model representing processes and their parent-child relationships.
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
GraphModel: A graph model representing processes and their parent-child relationships.
|
|
15
|
+
"""
|
|
16
|
+
|
|
10
17
|
graph_model = graphinate.model("Processes Graph")
|
|
11
18
|
|
|
12
19
|
def processes() -> Iterable[psutil.Process]:
|
|
@@ -9,6 +9,16 @@ DEFAULT_MAX_DEPTH = 0
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def page_links_graph_model(max_depth: int = DEFAULT_MAX_DEPTH):
|
|
12
|
+
"""
|
|
13
|
+
Create a graph model based on page links.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
max_depth (int, optional): The maximum depth to crawl for page links. Defaults to DEFAULT_MAX_DEPTH.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
GraphModel: A graph model representing the page links.
|
|
20
|
+
"""
|
|
21
|
+
|
|
12
22
|
def _links(url: str, depth=0, **kwargs):
|
|
13
23
|
reqs = requests.get(url)
|
|
14
24
|
logger.debug('Analyzing Page: {url}')
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "Graphinate"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
authors = [
|
|
5
5
|
{ name = "Eran Rivlis", email = "eran@rivlis.info" },
|
|
6
6
|
]
|
|
7
7
|
description = "Graphinate. Data to Graphs."
|
|
8
8
|
readme = "README.md"
|
|
9
|
-
requires-python = ">=3.
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
10
|
classifiers = [
|
|
11
|
-
"Development Status ::
|
|
11
|
+
"Development Status :: 4 - Beta",
|
|
12
12
|
"Intended Audience :: Developers",
|
|
13
13
|
"Intended Audience :: Information Technology",
|
|
14
14
|
"Intended Audience :: Science/Research",
|
|
15
15
|
"Programming Language :: Python :: 3",
|
|
16
|
-
"Programming Language :: Python :: 3.9",
|
|
17
16
|
"Programming Language :: Python :: 3.10",
|
|
18
17
|
"Programming Language :: Python :: 3.11",
|
|
19
18
|
"Programming Language :: Python :: 3.12",
|
|
@@ -29,11 +28,11 @@ classifiers = [
|
|
|
29
28
|
keywords = ['graph', 'declarative']
|
|
30
29
|
dependencies = [
|
|
31
30
|
"click>=8.1.7",
|
|
32
|
-
"inflect>=7.
|
|
31
|
+
"inflect>=7.3.0",
|
|
33
32
|
"loguru>=0.7.2",
|
|
34
|
-
"matplotlib>=3.
|
|
33
|
+
"matplotlib>=3.9.0",
|
|
35
34
|
"networkx>=3.3",
|
|
36
|
-
"strawberry-graphql[asgi,opentelemetry]>=0.
|
|
35
|
+
"strawberry-graphql[asgi,opentelemetry]>=0.235.1"
|
|
37
36
|
]
|
|
38
37
|
|
|
39
38
|
|
|
@@ -60,18 +59,18 @@ docs = [
|
|
|
60
59
|
]
|
|
61
60
|
test = [
|
|
62
61
|
"faker>=23.2.1",
|
|
63
|
-
"pytest>=8.
|
|
64
|
-
"pytest-asyncio>=0.23.
|
|
62
|
+
"pytest>=8.2.2",
|
|
63
|
+
"pytest-asyncio>=0.23.7",
|
|
65
64
|
"pytest-cov>=5.0.0",
|
|
66
65
|
"pytest-randomly>=3.15.0",
|
|
67
|
-
"pytest-xdist>=3.
|
|
66
|
+
"pytest-xdist>=3.6.1"
|
|
68
67
|
]
|
|
69
68
|
plot = [
|
|
70
|
-
"scipy>=1.
|
|
69
|
+
"scipy>=1.14.0"
|
|
71
70
|
]
|
|
72
71
|
server = [
|
|
73
72
|
"starlette-prometheus",
|
|
74
|
-
"uvicorn[standard]>=0.
|
|
73
|
+
"uvicorn[standard]>=0.30.1"
|
|
75
74
|
]
|
|
76
75
|
|
|
77
76
|
|
|
@@ -10,10 +10,11 @@ import networkx as nx
|
|
|
10
10
|
def node_color_mapping(graph: nx.Graph, cmap: Union[str, mpl.colors.Colormap] = "tab20") -> Mapping:
|
|
11
11
|
"""
|
|
12
12
|
Parameters:
|
|
13
|
-
graph:
|
|
14
|
-
cmap
|
|
13
|
+
graph: nx.Graph - The input graph for which node colors need to be mapped.
|
|
14
|
+
cmap: Union[str, mpl.colors.Colormap], optional - The colormap used to map values to RGBA colors.
|
|
15
|
+
Default is "tab20".
|
|
15
16
|
Returns:
|
|
16
|
-
|
|
17
|
+
Mapping - A dictionary mapping nodes to their corresponding RGBA colors based on the colormap.
|
|
17
18
|
"""
|
|
18
19
|
type_lookup = {t: i for i, t in enumerate(graph.graph['node_types'].keys())}
|
|
19
20
|
color_lookup = {node: type_lookup.get(data.get('type'), 0) for node, data in graph.nodes.data()}
|
|
@@ -8,11 +8,12 @@ def draw(graph: nx.Graph,
|
|
|
8
8
|
with_node_labels: bool = True,
|
|
9
9
|
with_edge_labels: bool = False):
|
|
10
10
|
"""
|
|
11
|
+
Draws the given networkx graph with optional node and edge labels.
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
graph:
|
|
14
|
-
with_node_labels:
|
|
15
|
-
with_edge_labels:
|
|
13
|
+
Parameters:
|
|
14
|
+
graph (nx.Graph): The input graph to be drawn.
|
|
15
|
+
with_node_labels (bool): Whether to display node labels. Default is True.
|
|
16
|
+
with_edge_labels (bool): Whether to display edge labels. Default is False.
|
|
16
17
|
|
|
17
18
|
Returns:
|
|
18
19
|
None
|
|
@@ -54,11 +55,12 @@ def plot(graph: nx.Graph,
|
|
|
54
55
|
with_node_labels: bool = True,
|
|
55
56
|
with_edge_labels: bool = False):
|
|
56
57
|
"""
|
|
58
|
+
Plots the given networkx graph with optional node and edge labels.
|
|
57
59
|
|
|
58
60
|
Args:
|
|
59
|
-
graph:
|
|
60
|
-
with_node_labels:
|
|
61
|
-
with_edge_labels:
|
|
61
|
+
graph (nx.Graph): The input graph to be plotted.
|
|
62
|
+
with_node_labels (bool): Whether to display node labels. Default is True.
|
|
63
|
+
with_edge_labels (bool): Whether to display edge labels. Default is False.
|
|
62
64
|
|
|
63
65
|
Returns:
|
|
64
66
|
None
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import webbrowser
|
|
3
|
+
|
|
4
|
+
import strawberry
|
|
5
|
+
from starlette.applications import Starlette
|
|
6
|
+
from starlette.requests import Request
|
|
7
|
+
from starlette.schemas import SchemaGenerator
|
|
8
|
+
from starlette.types import ASGIApp
|
|
9
|
+
from strawberry.asgi import GraphQL
|
|
10
|
+
from strawberry.extensions.tracing import OpenTelemetryExtension
|
|
11
|
+
|
|
12
|
+
from .starlette import routes
|
|
13
|
+
|
|
14
|
+
DEFAULT_PORT: int = 8072
|
|
15
|
+
|
|
16
|
+
GRAPHQL_ROUTE_PATH = "/graphql"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def openapi_schema(request: Request) -> ASGIApp:
|
|
20
|
+
"""
|
|
21
|
+
Generates an OpenAPI schema for the GraphQL API and other routes.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
request (Request): The HTTP request object.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
ASGIApp: An OpenAPI response containing the schema for the specified routes.
|
|
28
|
+
"""
|
|
29
|
+
schema_data = {
|
|
30
|
+
'openapi': '3.0.0',
|
|
31
|
+
'info': {'title': 'Graphinate API', 'version': '1.0'},
|
|
32
|
+
'paths': {
|
|
33
|
+
'/graphql': {'get': {'responses': {200: {'description': 'GraphQL'}}}},
|
|
34
|
+
'/graphiql': {'get': {'responses': {200: {'description': 'GraphiQL UI.'}}}},
|
|
35
|
+
'/metrics': {'get': {'responses': {200: {'description': 'Prometheus metrics.'}}}},
|
|
36
|
+
'/viewer': {'get': {'responses': {200: {'description': '3D Force-Directed Graph Viewer'}}}},
|
|
37
|
+
'/voyager': {'get': {'responses': {200: {'description': 'Voyager GraphQL Schema Viewer'}}}}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
schema = SchemaGenerator(schema_data)
|
|
42
|
+
return schema.OpenAPIResponse(request=request)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def graphql(graphql_schema: strawberry.Schema, port: int = DEFAULT_PORT):
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
graphql_schema:
|
|
50
|
+
port:
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
|
|
54
|
+
"""
|
|
55
|
+
graphql_schema.extensions.append(OpenTelemetryExtension)
|
|
56
|
+
|
|
57
|
+
@contextlib.asynccontextmanager
|
|
58
|
+
async def lifespan(app: Starlette): # pragma: no cover
|
|
59
|
+
def open_url():
|
|
60
|
+
for app_name in ('voyager', 'graphiql', 'viewer'):
|
|
61
|
+
webbrowser.open(f'http://localhost:{port}/{app_name}')
|
|
62
|
+
|
|
63
|
+
open_url()
|
|
64
|
+
yield
|
|
65
|
+
|
|
66
|
+
graphql_app: GraphQL = GraphQL(graphql_schema)
|
|
67
|
+
app = Starlette(
|
|
68
|
+
lifespan=lifespan,
|
|
69
|
+
routes=routes()
|
|
70
|
+
)
|
|
71
|
+
app.add_route(GRAPHQL_ROUTE_PATH, graphql_app)
|
|
72
|
+
app.add_websocket_route(GRAPHQL_ROUTE_PATH, graphql_app)
|
|
73
|
+
|
|
74
|
+
from starlette_prometheus import PrometheusMiddleware, metrics
|
|
75
|
+
app.add_middleware(PrometheusMiddleware)
|
|
76
|
+
app.add_route("/metrics", metrics)
|
|
77
|
+
app.add_route("/schema", route=openapi_schema, include_in_schema=False)
|
|
78
|
+
|
|
79
|
+
import uvicorn
|
|
80
|
+
uvicorn.run(app, host='0.0.0.0', port=port)
|