Graphinate 0.4.0__tar.gz → 0.5.1__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.
Files changed (104) hide show
  1. {graphinate-0.4.0 → graphinate-0.5.1}/.github/workflows/test-beta.yml +1 -1
  2. {graphinate-0.4.0 → graphinate-0.5.1}/PKG-INFO +26 -31
  3. {graphinate-0.4.0 → graphinate-0.5.1}/README.md +24 -11
  4. graphinate-0.5.1/docs/assets/badge/v0.json +7 -0
  5. {graphinate-0.4.0 → graphinate-0.5.1}/docs/index.md +10 -4
  6. graphinate-0.5.1/examples/math/graph_atlas.py +69 -0
  7. {graphinate-0.4.0 → graphinate-0.5.1}/examples/math/graphs.py +74 -20
  8. graphinate-0.5.1/examples/math/gui.py +108 -0
  9. {graphinate-0.4.0 → graphinate-0.5.1}/examples/web/page_links.py +12 -8
  10. {graphinate-0.4.0 → graphinate-0.5.1}/pyproject.toml +12 -9
  11. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/builders.py +5 -5
  12. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/modeling.py +14 -15
  13. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/server/__init__.py +1 -1
  14. graphinate-0.5.1/src/graphinate/server/web/static/images/logo.svg +50 -0
  15. graphinate-0.5.1/src/graphinate/server/web/viewer/index.html +162 -0
  16. graphinate-0.4.0/examples/math/graph_atlas.py +0 -52
  17. graphinate-0.4.0/examples/math/gui.py +0 -133
  18. graphinate-0.4.0/src/graphinate/server/web/static/js/murmurhash3_gc.js +0 -64
  19. graphinate-0.4.0/src/graphinate/server/web/viewer/index.html +0 -66
  20. {graphinate-0.4.0 → graphinate-0.5.1}/.coveragerc +0 -0
  21. {graphinate-0.4.0 → graphinate-0.5.1}/.github/dependabot.yml +0 -0
  22. {graphinate-0.4.0 → graphinate-0.5.1}/.github/workflows/codeql.yml +0 -0
  23. {graphinate-0.4.0 → graphinate-0.5.1}/.github/workflows/publish-docs.yaml +0 -0
  24. {graphinate-0.4.0 → graphinate-0.5.1}/.github/workflows/publish.yml +0 -0
  25. {graphinate-0.4.0 → graphinate-0.5.1}/.github/workflows/test.yml +0 -0
  26. {graphinate-0.4.0 → graphinate-0.5.1}/.gitignore +0 -0
  27. {graphinate-0.4.0 → graphinate-0.5.1}/.sonarcloud.properties +0 -0
  28. {graphinate-0.4.0 → graphinate-0.5.1}/LICENSE +0 -0
  29. {graphinate-0.4.0 → graphinate-0.5.1}/STATS.md +0 -0
  30. {graphinate-0.4.0 → graphinate-0.5.1}/docs/acknowledge.md +0 -0
  31. {graphinate-0.4.0 → graphinate-0.5.1}/docs/assets/images/logo-128.png +0 -0
  32. {graphinate-0.4.0 → graphinate-0.5.1}/docs/assets/images/network_graph.png +0 -0
  33. {graphinate-0.4.0 → graphinate-0.5.1}/docs/assets/stylesheets/extra.css +0 -0
  34. {graphinate-0.4.0 → graphinate-0.5.1}/docs/dev.md +0 -0
  35. {graphinate-0.4.0 → graphinate-0.5.1}/docs/examples/code.md +0 -0
  36. {graphinate-0.4.0 → graphinate-0.5.1}/docs/examples/github.md +0 -0
  37. {graphinate-0.4.0 → graphinate-0.5.1}/docs/examples/math.md +0 -0
  38. {graphinate-0.4.0 → graphinate-0.5.1}/docs/examples/system.md +0 -0
  39. {graphinate-0.4.0 → graphinate-0.5.1}/docs/examples/web.md +0 -0
  40. {graphinate-0.4.0 → graphinate-0.5.1}/docs/gen_ref_pages.py +0 -0
  41. {graphinate-0.4.0 → graphinate-0.5.1}/docs/intro.md +0 -0
  42. {graphinate-0.4.0 → graphinate-0.5.1}/docs/start.md +0 -0
  43. {graphinate-0.4.0 → graphinate-0.5.1}/docs/usage/cli.md +0 -0
  44. {graphinate-0.4.0 → graphinate-0.5.1}/docs/usage/lib.md +0 -0
  45. {graphinate-0.4.0 → graphinate-0.5.1}/examples/code/python_ast.py +0 -0
  46. {graphinate-0.4.0 → graphinate-0.5.1}/examples/code/python_dependencies.py +0 -0
  47. {graphinate-0.4.0 → graphinate-0.5.1}/examples/code/requirements.txt +0 -0
  48. {graphinate-0.4.0 → graphinate-0.5.1}/examples/github/_client.py +0 -0
  49. {graphinate-0.4.0 → graphinate-0.5.1}/examples/github/commits_visibilty_graph.py +0 -0
  50. {graphinate-0.4.0 → graphinate-0.5.1}/examples/github/followers.graphql +0 -0
  51. {graphinate-0.4.0 → graphinate-0.5.1}/examples/github/followers.py +0 -0
  52. {graphinate-0.4.0 → graphinate-0.5.1}/examples/github/graphql.config.yml +0 -0
  53. {graphinate-0.4.0 → graphinate-0.5.1}/examples/github/repositories.graphql +0 -0
  54. {graphinate-0.4.0 → graphinate-0.5.1}/examples/github/repositories.py +0 -0
  55. {graphinate-0.4.0 → graphinate-0.5.1}/examples/github/requirements.txt +0 -0
  56. {graphinate-0.4.0 → graphinate-0.5.1}/examples/math/polygonal_graph.py +0 -0
  57. {graphinate-0.4.0 → graphinate-0.5.1}/examples/math/requirements.txt +0 -0
  58. {graphinate-0.4.0 → graphinate-0.5.1}/examples/system/processes.py +0 -0
  59. {graphinate-0.4.0 → graphinate-0.5.1}/examples/system/requirements.txt +0 -0
  60. {graphinate-0.4.0 → graphinate-0.5.1}/examples/web/requirements.txt +0 -0
  61. {graphinate-0.4.0 → graphinate-0.5.1}/mkdocs.yml +0 -0
  62. {graphinate-0.4.0 → graphinate-0.5.1}/playground/ethernet/traceroute.py +0 -0
  63. {graphinate-0.4.0 → graphinate-0.5.1}/playground/genric_graph.graphql +0 -0
  64. {graphinate-0.4.0 → graphinate-0.5.1}/playground/graphql.config.yml +0 -0
  65. {graphinate-0.4.0 → graphinate-0.5.1}/playground/house_of_graphs.py +0 -0
  66. {graphinate-0.4.0 → graphinate-0.5.1}/playground/social/albums.json +0 -0
  67. {graphinate-0.4.0 → graphinate-0.5.1}/playground/social/musicisians.py +0 -0
  68. {graphinate-0.4.0 → graphinate-0.5.1}/playground/text/nlp_graph.py +0 -0
  69. {graphinate-0.4.0 → graphinate-0.5.1}/playground/text/requirements.txt +0 -0
  70. {graphinate-0.4.0 → graphinate-0.5.1}/playground/time_series/requirements.txt +0 -0
  71. {graphinate-0.4.0 → graphinate-0.5.1}/playground/time_series/visibility_graph.py +0 -0
  72. {graphinate-0.4.0 → graphinate-0.5.1}/sonar-project.properties +0 -0
  73. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/__init__.py +0 -0
  74. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/__main__.py +0 -0
  75. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/cli.py +0 -0
  76. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/color.py +0 -0
  77. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/materializers/__init__.py +0 -0
  78. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/materializers/matplotlib.py +0 -0
  79. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/server/starlette/__init__.py +0 -0
  80. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/server/starlette/views.py +0 -0
  81. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/server/web/__init__.py +0 -0
  82. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/server/web/elements/__init__.py +0 -0
  83. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/server/web/elements/index.html +0 -0
  84. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/server/web/graphiql/__init__.py +0 -0
  85. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/server/web/graphiql/index.html +0 -0
  86. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/server/web/rapidoc/__init__.py +0 -0
  87. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/server/web/rapidoc/index.html +0 -0
  88. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/server/web/static/images/logo-128.png +0 -0
  89. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/server/web/static/images/network_graph.png +0 -0
  90. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/server/web/viewer/__init__.py +0 -0
  91. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/server/web/voyager/__init__.py +0 -0
  92. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/server/web/voyager/index.html +0 -0
  93. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/tools/__init__.py +0 -0
  94. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/tools/converters.py +0 -0
  95. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/tools/mutators.py +0 -0
  96. {graphinate-0.4.0 → graphinate-0.5.1}/src/graphinate/typing.py +0 -0
  97. {graphinate-0.4.0 → graphinate-0.5.1}/tests/conftest.py +0 -0
  98. {graphinate-0.4.0 → graphinate-0.5.1}/tests/graphinate/test_builders.py +0 -0
  99. {graphinate-0.4.0 → graphinate-0.5.1}/tests/graphinate/test_cli.py +0 -0
  100. {graphinate-0.4.0 → graphinate-0.5.1}/tests/graphinate/test_color.py +0 -0
  101. {graphinate-0.4.0 → graphinate-0.5.1}/tests/graphinate/test_materializers.py +0 -0
  102. {graphinate-0.4.0 → graphinate-0.5.1}/tests/graphinate/test_modeling.py +0 -0
  103. {graphinate-0.4.0 → graphinate-0.5.1}/tests/graphinate/test_server.py +0 -0
  104. {graphinate-0.4.0 → graphinate-0.5.1}/tests/graphinate/test_tools.py +0 -0
@@ -16,7 +16,7 @@ jobs:
16
16
  fail-fast: false
17
17
  matrix:
18
18
  # https://github.com/actions/python-versions/blob/main/versions-manifest.json
19
- python-version: [ "3.14.0-alpha.4" ]
19
+ python-version: [ "3.14.0-alpha.5" ]
20
20
  steps:
21
21
  - uses: actions/checkout@v4
22
22
  - name: Set up Python ${{ matrix.python-version }}
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Graphinate
3
- Version: 0.4.0
4
- Summary: Graphinate. Data to Graphs.
3
+ Version: 0.5.1
4
+ Summary: 𝔾raphinate. Data to Graphs.
5
5
  Project-URL: Homepage, https://erivlis.github.io/graphinate
6
6
  Project-URL: Documentation, https://erivlis.github.io/graphinate
7
7
  Project-URL: Bug Tracker, https://github.com/erivlis/graphinate/issues
@@ -33,32 +33,14 @@ Requires-Dist: loguru
33
33
  Requires-Dist: matplotlib
34
34
  Requires-Dist: networkx
35
35
  Requires-Dist: strawberry-graphql[asgi,opentelemetry]
36
- Provides-Extra: dev
37
- Requires-Dist: pipdeptree; extra == 'dev'
38
- Requires-Dist: ruff; extra == 'dev'
39
- Provides-Extra: docs
40
- Requires-Dist: mkdocs-gen-files; extra == 'docs'
41
- Requires-Dist: mkdocs-git-revision-date-localized-plugin; extra == 'docs'
42
- Requires-Dist: mkdocs-glightbox; extra == 'docs'
43
- Requires-Dist: mkdocs-literate-nav; extra == 'docs'
44
- Requires-Dist: mkdocs-material; extra == 'docs'
45
- Requires-Dist: mkdocs-section-index; extra == 'docs'
46
- Requires-Dist: mkdocstrings-python; extra == 'docs'
47
36
  Provides-Extra: plot
48
37
  Requires-Dist: scipy; extra == 'plot'
49
38
  Provides-Extra: server
50
39
  Requires-Dist: starlette-prometheus; extra == 'server'
51
40
  Requires-Dist: uvicorn[standard]; extra == 'server'
52
- Provides-Extra: test
53
- Requires-Dist: faker; extra == 'test'
54
- Requires-Dist: pytest; extra == 'test'
55
- Requires-Dist: pytest-asyncio; extra == 'test'
56
- Requires-Dist: pytest-cov; extra == 'test'
57
- Requires-Dist: pytest-randomly; extra == 'test'
58
- Requires-Dist: pytest-xdist; extra == 'test'
59
41
  Description-Content-Type: text/markdown
60
42
 
61
- # [Graphinate. Data to Graphs.](https://erivlis.github.io/graphinate/)
43
+ # [𝔾raphinate. Data to Graphs.](https://erivlis.github.io/graphinate/)
62
44
 
63
45
  <img height="360" src="https://github.com/erivlis/graphinate/assets/9897520/dae41f9f-69e5-4eb5-a488-87ce7f51fa32" alt="Graphinate. Data to Graphs.">
64
46
 
@@ -120,10 +102,21 @@ Description-Content-Type: text/markdown
120
102
  <a href="https://snyk.io/test/github/erivlis/graphinate"><img alt="Snyk" src="https://snyk.io/test/github/erivlis/Graphinate/badge.svg"></a>
121
103
  </td>
122
104
  </tr>
105
+ <tr>
106
+ <td>Mentions</td>
107
+ <td>
108
+ <a href="https://www.youtube.com/live/k01G0b0Y0Jg?si=030OT8sK3BqPyy8r&t=1028"><img alt="PythonBytes Podcast" src="https://img.shields.io/badge/Python_Bytes-Ep. 361-D7F9FF?logo=applepodcasts&labelColor=blue"></a>
109
+ <a href="https://pythonhub.dev/digest/2024-03-10/"><img alt="Static Badge" src="https://img.shields.io/badge/PythonHub-2024.03.10-gold?labelColor=blue"></a>
110
+ </td>
111
+ </tr>
112
+ <tr>
113
+ <td>Badge</td>
114
+ <td>
115
+ <a href="https://img.shields.io/badge/%F0%9D%94%BE%3D%7B%F0%9D%95%8D%2C%F0%9D%94%BC%7D-Graphinate-darkviolet"><img alt="Graphinate" src="https://img.shields.io/badge/%F0%9D%94%BE%3D%7B%F0%9D%95%8D%2C%F0%9D%94%BC%7D-Graphinate-darkviolet"></a>
116
+ </td>
117
+ </tr>
123
118
  </table>
124
119
 
125
- ---------------------
126
-
127
120
  ## Introduction
128
121
 
129
122
  ### What is Graphinate?
@@ -302,27 +295,29 @@ python -m mkdocs build
302
295
 
303
296
  #### Python
304
297
 
305
- <a href="https://palletsprojects.com/p/click/"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://click.palletsprojects.com/en/7.x/_images/click-logo.png" alt="Click Logo."></a>
306
- <a href="https://github.com/Delgan/loguru"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://raw.githubusercontent.com/Delgan/loguru/master/docs/_static/img/logo.png" alt="Loguru Logo."></a>
298
+ <a href="https://palletsprojects.com/p/click/"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://click.palletsprojects.com/en/7.x/_images/click-logo.png" alt="Click Logo"></a>
299
+ <a href="https://github.com/Delgan/loguru"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://raw.githubusercontent.com/Delgan/loguru/master/docs/_static/img/logo.png" alt="Loguru Logo"></a>
307
300
  <a href="https://matplotlib.org/"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://matplotlib.org/_static/logo_dark.svg" alt="matplotlib Logo."></a>
308
301
  <a href="https://networkx.org/"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://networkx.org/_static/networkx_logo.svg" alt="NetworkX Logo."></a>
309
- <a href="https://strawberry.rocks/"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://github.com/strawberry-graphql/strawberry/raw/main/.github/logo.png" alt="Strawberry GraphQL Logo."></a>
302
+ <a href="https://strawberry.rocks/"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://github.com/strawberry-graphql/strawberry/raw/main/.github/logo.png" alt="Strawberry GraphQL Logo"></a>
310
303
 
311
304
  #### Javascript and HTML
312
305
 
313
- <a href="https://vasturiano.github.io/3d-force-graph/"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="http://gist.github.com/vasturiano/02affe306ce445e423f992faeea13521/raw/preview.png" alt="3D Force-Directed Graph Logo."></a>
314
- <a href="https://github.com/graphql-kit/graphql-voyager"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://github.com/graphql-kit/graphql-voyager/raw/main/docs/cover.png" alt="Graphql Voyager Logo."></a>
306
+ <a href="https://vasturiano.github.io/3d-force-graph/"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="http://gist.github.com/vasturiano/02affe306ce445e423f992faeea13521/raw/preview.png" alt="3D Force-Directed Graph Logo"></a>
307
+ <a href="https://github.com/graphql-kit/graphql-voyager"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://github.com/graphql-kit/graphql-voyager/raw/main/docs/cover.png" alt="Graphql Voyager Logo"></a>
308
+ <a href="https://github.com/cocopon/tweakpane"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://user-images.githubusercontent.com/602961/184479032-38f50be3-e235-4914-85c0-dce316b33ed2.png" alt="Tweakpane Logo"></a>
315
309
 
316
310
  ### Dev Tools
317
311
 
318
312
  <a href="https://hatch.pypa.io/"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://hatch.pypa.io/latest/assets/images/logo.svg" alt="Hatch logo."></a>
319
313
  <a href="https://squidfunk.github.io/mkdocs-material/"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://raw.githubusercontent.com/squidfunk/mkdocs-material/master/.github/assets/logo.svg" alt="Material for MkDocs"></a>
320
- <a href="https://pytest.org"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://docs.pytest.org/en/7.4.x/_static/pytest_logo_curves.svg" alt="pytest logo."></a>
321
- <a href="https://astral.sh/ruff"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://astralcms.wpengine.com/wp-content/uploads/2023/03/Ruff-Logo.svg" alt="Ruff logo."></a>
314
+ <a href="https://pytest.org"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://docs.pytest.org/en/7.4.x/_static/pytest_logo_curves.svg" alt="pytest logo"></a>
315
+ <a href="https://astral.sh/ruff"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://astralcms.wpengine.com/wp-content/uploads/2023/03/Ruff-Logo.svg" alt="Ruff logo"></a>
316
+ <a href="https://astral.sh/uv"><img height="60" style="padding: 16px; background: #261230;" src="https://docs.astral.sh/uv/assets/logo-letter.svg" alt="uv logo"></a>
322
317
 
323
318
  ### IDE
324
319
 
325
- <a href="https://www.jetbrains.com/pycharm/"><img height="60" style="background: linear-gradient(-45deg, #FCF84A, #3DEA62, #21D789);" src="https://resources.jetbrains.com/storage/products/company/brand/logos/PyCharm.png" alt="PyCharm logo."></a>
320
+ <a href="https://www.jetbrains.com/pycharm/"><img height="60" style="background: linear-gradient(-45deg, #FCF84A, #3DEA62, #21D789);" src="https://resources.jetbrains.com/storage/products/company/brand/logos/PyCharm.png" alt="PyCharm logo"></a>
326
321
 
327
322
  ---------------------
328
323
 
@@ -1,4 +1,4 @@
1
- # [Graphinate. Data to Graphs.](https://erivlis.github.io/graphinate/)
1
+ # [𝔾raphinate. Data to Graphs.](https://erivlis.github.io/graphinate/)
2
2
 
3
3
  <img height="360" src="https://github.com/erivlis/graphinate/assets/9897520/dae41f9f-69e5-4eb5-a488-87ce7f51fa32" alt="Graphinate. Data to Graphs.">
4
4
 
@@ -60,10 +60,21 @@
60
60
  <a href="https://snyk.io/test/github/erivlis/graphinate"><img alt="Snyk" src="https://snyk.io/test/github/erivlis/Graphinate/badge.svg"></a>
61
61
  </td>
62
62
  </tr>
63
+ <tr>
64
+ <td>Mentions</td>
65
+ <td>
66
+ <a href="https://www.youtube.com/live/k01G0b0Y0Jg?si=030OT8sK3BqPyy8r&t=1028"><img alt="PythonBytes Podcast" src="https://img.shields.io/badge/Python_Bytes-Ep. 361-D7F9FF?logo=applepodcasts&labelColor=blue"></a>
67
+ <a href="https://pythonhub.dev/digest/2024-03-10/"><img alt="Static Badge" src="https://img.shields.io/badge/PythonHub-2024.03.10-gold?labelColor=blue"></a>
68
+ </td>
69
+ </tr>
70
+ <tr>
71
+ <td>Badge</td>
72
+ <td>
73
+ <a href="https://img.shields.io/badge/%F0%9D%94%BE%3D%7B%F0%9D%95%8D%2C%F0%9D%94%BC%7D-Graphinate-darkviolet"><img alt="Graphinate" src="https://img.shields.io/badge/%F0%9D%94%BE%3D%7B%F0%9D%95%8D%2C%F0%9D%94%BC%7D-Graphinate-darkviolet"></a>
74
+ </td>
75
+ </tr>
63
76
  </table>
64
77
 
65
- ---------------------
66
-
67
78
  ## Introduction
68
79
 
69
80
  ### What is Graphinate?
@@ -242,27 +253,29 @@ python -m mkdocs build
242
253
 
243
254
  #### Python
244
255
 
245
- <a href="https://palletsprojects.com/p/click/"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://click.palletsprojects.com/en/7.x/_images/click-logo.png" alt="Click Logo."></a>
246
- <a href="https://github.com/Delgan/loguru"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://raw.githubusercontent.com/Delgan/loguru/master/docs/_static/img/logo.png" alt="Loguru Logo."></a>
256
+ <a href="https://palletsprojects.com/p/click/"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://click.palletsprojects.com/en/7.x/_images/click-logo.png" alt="Click Logo"></a>
257
+ <a href="https://github.com/Delgan/loguru"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://raw.githubusercontent.com/Delgan/loguru/master/docs/_static/img/logo.png" alt="Loguru Logo"></a>
247
258
  <a href="https://matplotlib.org/"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://matplotlib.org/_static/logo_dark.svg" alt="matplotlib Logo."></a>
248
259
  <a href="https://networkx.org/"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://networkx.org/_static/networkx_logo.svg" alt="NetworkX Logo."></a>
249
- <a href="https://strawberry.rocks/"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://github.com/strawberry-graphql/strawberry/raw/main/.github/logo.png" alt="Strawberry GraphQL Logo."></a>
260
+ <a href="https://strawberry.rocks/"><img height="60" style="padding: 5px; background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://github.com/strawberry-graphql/strawberry/raw/main/.github/logo.png" alt="Strawberry GraphQL Logo"></a>
250
261
 
251
262
  #### Javascript and HTML
252
263
 
253
- <a href="https://vasturiano.github.io/3d-force-graph/"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="http://gist.github.com/vasturiano/02affe306ce445e423f992faeea13521/raw/preview.png" alt="3D Force-Directed Graph Logo."></a>
254
- <a href="https://github.com/graphql-kit/graphql-voyager"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://github.com/graphql-kit/graphql-voyager/raw/main/docs/cover.png" alt="Graphql Voyager Logo."></a>
264
+ <a href="https://vasturiano.github.io/3d-force-graph/"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="http://gist.github.com/vasturiano/02affe306ce445e423f992faeea13521/raw/preview.png" alt="3D Force-Directed Graph Logo"></a>
265
+ <a href="https://github.com/graphql-kit/graphql-voyager"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://github.com/graphql-kit/graphql-voyager/raw/main/docs/cover.png" alt="Graphql Voyager Logo"></a>
266
+ <a href="https://github.com/cocopon/tweakpane"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://user-images.githubusercontent.com/602961/184479032-38f50be3-e235-4914-85c0-dce316b33ed2.png" alt="Tweakpane Logo"></a>
255
267
 
256
268
  ### Dev Tools
257
269
 
258
270
  <a href="https://hatch.pypa.io/"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://hatch.pypa.io/latest/assets/images/logo.svg" alt="Hatch logo."></a>
259
271
  <a href="https://squidfunk.github.io/mkdocs-material/"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://raw.githubusercontent.com/squidfunk/mkdocs-material/master/.github/assets/logo.svg" alt="Material for MkDocs"></a>
260
- <a href="https://pytest.org"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://docs.pytest.org/en/7.4.x/_static/pytest_logo_curves.svg" alt="pytest logo."></a>
261
- <a href="https://astral.sh/ruff"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://astralcms.wpengine.com/wp-content/uploads/2023/03/Ruff-Logo.svg" alt="Ruff logo."></a>
272
+ <a href="https://pytest.org"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://docs.pytest.org/en/7.4.x/_static/pytest_logo_curves.svg" alt="pytest logo"></a>
273
+ <a href="https://astral.sh/ruff"><img height="60" style="background: linear-gradient(-45deg, #FFFFFF, #CCCCCC);" src="https://astralcms.wpengine.com/wp-content/uploads/2023/03/Ruff-Logo.svg" alt="Ruff logo"></a>
274
+ <a href="https://astral.sh/uv"><img height="60" style="padding: 16px; background: #261230;" src="https://docs.astral.sh/uv/assets/logo-letter.svg" alt="uv logo"></a>
262
275
 
263
276
  ### IDE
264
277
 
265
- <a href="https://www.jetbrains.com/pycharm/"><img height="60" style="background: linear-gradient(-45deg, #FCF84A, #3DEA62, #21D789);" src="https://resources.jetbrains.com/storage/products/company/brand/logos/PyCharm.png" alt="PyCharm logo."></a>
278
+ <a href="https://www.jetbrains.com/pycharm/"><img height="60" style="background: linear-gradient(-45deg, #FCF84A, #3DEA62, #21D789);" src="https://resources.jetbrains.com/storage/products/company/brand/logos/PyCharm.png" alt="PyCharm logo"></a>
266
279
 
267
280
  ---------------------
268
281
 
@@ -0,0 +1,7 @@
1
+ {
2
+ "label": "",
3
+ "message": "Graphinate",
4
+ "logo": "https://github.com/erivlis/graphinate/assets/9897520/dae41f9f-69e5-4eb5-a488-87ce7f51fa32",
5
+ "logoWidth": 10,
6
+ "color": "darkviolet"
7
+ }
@@ -2,7 +2,7 @@
2
2
 
3
3
  <table style="border-width: 0;">
4
4
  <tr style="vertical-align: middle; border-width: 0;">
5
- <td rowspan="5"><img height="240" src="https://github.com/erivlis/graphinate/assets/9897520/dae41f9f-69e5-4eb5-a488-87ce7f51fa32" alt="Graphinate. Data to Graphs."></td>
5
+ <td rowspan="7"><img height="240" src="https://github.com/erivlis/graphinate/assets/9897520/dae41f9f-69e5-4eb5-a488-87ce7f51fa32" alt="Graphinate. Data to Graphs."></td>
6
6
  <td>Package</td>
7
7
  <td>
8
8
  <img alt="PyPI - version" src="https://img.shields.io/pypi/v/graphinate.svg?logo=pypi&logoColor=lightblue">
@@ -35,8 +35,8 @@
35
35
  <tr style="vertical-align: middle;">
36
36
  <td>CI/CD</td>
37
37
  <td>
38
- <a href="https://github.com/erivlis/graphinate/actions/workflows/test.yml"><img alt="Tests" src="https://github.com/erivlis/graphinate/actions/workflows/test.yml/badge.svg?branch=master"></a>
39
- <a href="https://github.com/erivlis/graphinate/actions/workflows/test.yml"><img alt="Tests" src="https://github.com/erivlis/graphinate/actions/workflows/test-beta.yml/badge.svg?branch=master"></a>
38
+ <a href="https://github.com/erivlis/graphinate/actions/workflows/test.yml"><img alt="Test" src="https://github.com/erivlis/graphinate/actions/workflows/test.yml/badge.svg"></a>
39
+ <a href="https://github.com/erivlis/graphinate/actions/workflows/test-beta.yml"><img alt="Test (Beta)" src="https://github.com/erivlis/graphinate/actions/workflows/test-beta.yml/badge.svg"></a>
40
40
  <a href="https://github.com/erivlis/graphinate/actions/workflows/publish.yml"><img alt="Publish" src="https://github.com/erivlis/graphinate/actions/workflows/publish.yml/badge.svg"></a>
41
41
  <a href="https://github.com/erivlis/graphinate/actions/workflows/publish-docs.yaml"><img alt="Publish Docs" src="https://github.com/erivlis/graphinate/actions/workflows/publish-docs.yaml/badge.svg"></a>
42
42
  </td>
@@ -59,5 +59,11 @@
59
59
  <a href="https://snyk.io/test/github/erivlis/graphinate"><img alt="Snyk" src="https://snyk.io/test/github/erivlis/Graphinate/badge.svg"></a>
60
60
  </td>
61
61
  </tr>
62
+ <tr>
63
+ <td>Mentions</td>
64
+ <td>
65
+ <a href="https://www.youtube.com/live/k01G0b0Y0Jg?si=030OT8sK3BqPyy8r&t=1028"><img alt="PythonBytes Podcast" src="https://img.shields.io/badge/Python_Bytes-Ep. 361-D7F9FF?logo=applepodcasts&labelColor=blue"></a>
66
+ <a href="https://pythonhub.dev/digest/2024-03-10/"><img alt="Static Badge" src="https://img.shields.io/badge/PythonHub-2024.03.10-gold?labelColor=blue"></a>
67
+ </td>
68
+ </tr>
62
69
  </table>
63
-
@@ -0,0 +1,69 @@
1
+ import operator
2
+
3
+ import graphs
4
+ import networkx as nx
5
+
6
+ import graphinate
7
+ from graphinate.materializers import Materializers
8
+
9
+
10
+ def model(items: list[tuple[str, nx.Graph]]) -> graphinate.GraphModel:
11
+ """
12
+ Generate a graph model based on the provided iterable of graphs.
13
+ The function creates a graph model named 'Graph Atlas' using the 'graphinate' library.
14
+ It then combines all the graphs from the input iterable into a single disjoint union graph using NetworkX library.
15
+ The function defines edges for the combined graph by iterating over all edges in the disjoint union graph and
16
+ yielding dictionaries with 'source' and 'target' keys representing the edge connections.
17
+ Finally, the function yields the created graph model containing the combined graph with defined edges.
18
+
19
+ Args:
20
+ items: A list containing graphs to be combined into a single graph model.
21
+
22
+ Yields:
23
+ GraphModel: A graph model containing the combined graph with defined edges.
24
+ """
25
+
26
+ def items_iter(recs):
27
+ for name, g in recs:
28
+ print(name)
29
+ yield g
30
+
31
+ g = nx.disjoint_union_all(items_iter(items)) if len(items) > 1 else items[0][1]
32
+
33
+ graph_model = graphinate.model('Graph Atlas')
34
+
35
+ @graph_model.node(operator.itemgetter(1),
36
+ key=operator.itemgetter(0),
37
+ value=operator.itemgetter(0))
38
+ def nodes():
39
+ yield from g.nodes(data='type')
40
+
41
+ @graph_model.edge(operator.itemgetter(2),
42
+ source=operator.itemgetter(0),
43
+ target=operator.itemgetter(1),
44
+ label=operator.itemgetter(0, 1),
45
+ value=operator.itemgetter(0, 1))
46
+ def edge():
47
+ yield from g.edges.data('type')
48
+
49
+ return graph_model
50
+
51
+
52
+ if __name__ == '__main__':
53
+ from gui import ListboxChooser, RadiobuttonChooser
54
+
55
+ graph_atlas = graphs.atlas()
56
+
57
+ listbox_chooser = ListboxChooser('Choose Graph', graph_atlas)
58
+ choices = list(listbox_chooser.get_choices())
59
+ model = model(choices)
60
+
61
+ # or
62
+ # model(graph_atlas.values())
63
+
64
+ radiobutton_chooser = RadiobuttonChooser('Choose Materializer',
65
+ options={m.name: m.value for m in Materializers},
66
+ default=(None, None))
67
+ result = radiobutton_chooser.get_choice()
68
+ builder, handler = result[1]
69
+ graphinate.materialize(model, builder=builder, builder_output_handler=handler)
@@ -1,4 +1,5 @@
1
1
  import itertools
2
+ import re
2
3
  from collections.abc import Iterable
3
4
  from typing import NewType
4
5
 
@@ -692,18 +693,20 @@ SPECIAL_GRAPHS_ADJACENCY_LISTS = {
692
693
  AdjacencyList = NewType('AdjacencyList', dict[int, list[int]])
693
694
 
694
695
 
695
- def ladder_ring_graph(size: int):
696
- ring = nx.ladder_graph(size)
697
- ring.add_edge(size, size * 2 - 1)
698
- ring.add_edge(0, size - 1)
699
- return ladder_ring_graph
696
+ def ladder_ring_graph(size: int) -> nx.Graph:
697
+ g: nx.Graph = nx.ladder_graph(size)
698
+ g.add_edge(size, size * 2 - 1)
699
+ g.add_edge(0, size - 1)
700
+ g.name = f'Ladder Ring[{size}]'
701
+ return g
700
702
 
701
703
 
702
- def ladder_mobius_graph(size: int):
703
- mobius = nx.ladder_graph(size)
704
- mobius.add_edge(size, size - 1)
705
- mobius.add_edge(0, size * 2 - 1)
706
- return mobius
704
+ def ladder_mobius_graph(size: int) -> nx.Graph:
705
+ g = nx.ladder_graph(size)
706
+ g.add_edge(size, size - 1)
707
+ g.add_edge(0, size * 2 - 1)
708
+ g.name = f'Ladder Möbius Ring[{size}]'
709
+ return g
707
710
 
708
711
 
709
712
  def _cylinder_edges(circumference: int, length: int) -> Iterable[tuple[int, int]]:
@@ -721,7 +724,9 @@ def _cylinder_edges(circumference: int, length: int) -> Iterable[tuple[int, int]
721
724
 
722
725
 
723
726
  def cylinder_graph(circumference: int, length: int) -> nx.Graph:
724
- return nx.Graph(_cylinder_edges(circumference, length))
727
+ g = nx.Graph(_cylinder_edges(circumference, length))
728
+ g.name = f'Cylinder[circumference={circumference},length={length}]'
729
+ return g
725
730
 
726
731
 
727
732
  def _spiral_edges(n, k) -> Iterable[tuple[int, int]]:
@@ -733,7 +738,9 @@ def _spiral_edges(n, k) -> Iterable[tuple[int, int]]:
733
738
 
734
739
 
735
740
  def spiral_graph(n, k) -> nx.Graph:
736
- return nx.Graph(_spiral_edges(n, k))
741
+ g = nx.Graph(_spiral_edges(n, k))
742
+ g.name = f'Spiral[n={n},k={k}]'
743
+ return g
737
744
 
738
745
 
739
746
  def _spiral_torus_edges(n, k) -> Iterable[tuple[int, int]]:
@@ -744,7 +751,20 @@ def _spiral_torus_edges(n, k) -> Iterable[tuple[int, int]]:
744
751
 
745
752
 
746
753
  def spiral_torus_graph(n, k) -> nx.Graph:
747
- return nx.Graph(_spiral_torus_edges(n, k))
754
+ g = nx.Graph(_spiral_torus_edges(n, k))
755
+ g.name = f'Spiral Torus[n={n},k={k}]'
756
+ return g
757
+
758
+
759
+ def k_regular_edges(n, k) -> Iterable[tuple[int, int]]:
760
+ yield from itertools.chain.from_iterable(
761
+ ((i, j) for j in range(i + 1, i + k + 1))
762
+ for i in range(n-k))
763
+
764
+ def k_regular_graph(n, k) -> nx.Graph:
765
+ g = nx.Graph(k_regular_edges(n, k))
766
+ g.name = f'Generalized Buckyball[n={n},k={k}]'
767
+ return g
748
768
 
749
769
 
750
770
  def adjacency_edges(adjacency_list: AdjacencyList) -> Iterable[tuple[int, int]]:
@@ -786,23 +806,57 @@ def atlas():
786
806
  """
787
807
 
788
808
  graph_atlas = {
809
+ 'Triangle': nx.cycle_graph(3),
810
+ 'Square': nx.cycle_graph(4),
811
+ 'Square Lattice[3,3]': nx.grid_2d_graph(3, 3),
812
+ 'Pentagon': nx.cycle_graph(5),
813
+ 'Hexagon': nx.cycle_graph(6),
814
+ 'Heptagon': nx.cycle_graph(7),
815
+ 'Octagon': nx.cycle_graph(8),
789
816
  'Tetrahedron': nx.tetrahedral_graph(),
790
817
  'Cube': nx.hypercube_graph(3),
791
818
  'Octahedron': nx.octahedral_graph(),
792
819
  'Dodecahedron': nx.dodecahedral_graph(),
793
820
  'Icosahedron': nx.icosahedral_graph(),
794
821
  'Tesseract': nx.hypercube_graph(4),
822
+ 'Hypercube[5]': nx.hypercube_graph(5),
795
823
  'Truncated Cube': nx.truncated_cube_graph(),
796
824
  'Truncated Tetrahedron': nx.truncated_tetrahedron_graph(),
797
- 'Ladder': nx.ladder_graph(16),
798
- 'Ring': ladder_ring_graph(16),
799
- 'Möbius': ladder_mobius_graph(16),
800
- 'Cylinder': cylinder_graph(6, 8),
801
- 'Spiral': spiral_graph(18, 8),
802
- 'Spiral Torus': spiral_torus_graph(128, 8),
803
- 'Circulant[10,[2]]': nx.circulant_graph(10, [2])
825
+ 'Ladder[16]': nx.ladder_graph(16),
826
+ 'Ladder Ring[16]': ladder_ring_graph(16),
827
+ 'Ladder Möbius Ring[16]': ladder_mobius_graph(16),
828
+ 'Cylinder[6,8]': cylinder_graph(6, 8),
829
+ 'Spiral[128,8]': spiral_graph(128, 8),
830
+ 'Spiral Torus[128,8]': spiral_torus_graph(128, 8),
831
+ 'Chvátal': nx.chvatal_graph(),
832
+ 'Circulant[10,[2]]': nx.circulant_graph(10, [2]),
833
+ 'Desargues': nx.desargues_graph(),
834
+ 'Dorogovtsev-Goltsev-Mendes[4]': nx.dorogovtsev_goltsev_mendes_graph(4),
835
+ 'Frucht': nx.frucht_graph(),
836
+ 'Heawood': nx.heawood_graph(),
837
+ 'Hoffman-Singleton': nx.hoffman_singleton_graph(),
838
+ # 'Margulis-Gabber-Galil[8]': nx.margulis_gabber_galil_graph(8),
839
+ 'Papus': nx.pappus_graph(),
840
+ 'Petersen': nx.petersen_graph(),
841
+ 'Sedgewick Maze': nx.sedgewick_maze_graph(),
842
+ 'Tutte': nx.tutte_graph(),
804
843
  }
805
844
 
806
845
  graph_atlas.update(special_graphs())
807
846
 
847
+ def clean(s: str):
848
+ # Remove invalid characters
849
+ s = re.sub('[^0-9a-zA-Z_]', '_', s)
850
+
851
+ # Remove leading characters until we find a letter or underscore
852
+ s = re.sub('^[^a-zA-Z_]+', '', s)
853
+
854
+ return s
855
+
856
+ for name, g in graph_atlas.items():
857
+ _type = clean(name).capitalize()
858
+ nx.set_node_attributes(g, _type, 'type')
859
+ nx.set_edge_attributes(g, _type, 'type')
860
+
808
861
  return graph_atlas
862
+
@@ -0,0 +1,108 @@
1
+ import platform
2
+ import tkinter as tk
3
+ from tkinter import ttk
4
+
5
+
6
+ class ModalWindow(tk.Tk):
7
+ def __init__(self, title: str):
8
+ super().__init__()
9
+ self.title(title)
10
+ self.configure_window()
11
+
12
+ def configure_window(self):
13
+ if platform.system().lower() == 'windows':
14
+ self.wm_attributes('-toolwindow', 'True')
15
+ self.wm_attributes('-topmost', 'True')
16
+ self.resizable(False, False)
17
+
18
+
19
+ class RadiobuttonChooser(ModalWindow):
20
+ """
21
+ Usage Example:
22
+ ```python
23
+ radiobutton_chooser = RadiobuttonChooser("Choose an option", {"Option 1": 1, "Option 2": 2})
24
+ choice, value = radiobutton_chooser.get_choice()
25
+ print(choice, value)
26
+ ```
27
+ """
28
+
29
+ def __init__(self, window_title: str, options: dict, default=None):
30
+ super().__init__(window_title)
31
+ self.exit_button = None
32
+ self.choice_var = tk.StringVar(self, None)
33
+ self.default = default
34
+ self.options = options
35
+ self.create_widgets()
36
+ self.mainloop()
37
+
38
+ def create_widgets(self):
39
+ frame = ttk.Frame(self, borderwidth=5, relief='solid')
40
+ frame.pack(padx=4, pady=4)
41
+
42
+ ttk.Label(frame, text="Output Mode:").pack()
43
+
44
+ for option in self.options:
45
+ ttk.Radiobutton(
46
+ frame,
47
+ text=option,
48
+ variable=self.choice_var,
49
+ value=option,
50
+ command=self.enable_exit_button,
51
+ padding=4
52
+ ).pack(side=tk.TOP, anchor="w")
53
+
54
+ self.exit_button = ttk.Button(self, text="OK", command=self.destroy, state=tk.DISABLED)
55
+ self.exit_button.pack(pady=4, side=tk.BOTTOM)
56
+
57
+ def enable_exit_button(self):
58
+ self.exit_button['state'] = tk.NORMAL
59
+
60
+ def get_choice(self):
61
+ return self.choice_var.get(), self.options.get(self.choice_var.get(), self.default)
62
+
63
+
64
+ class ListboxChooser(ModalWindow):
65
+ """
66
+ Usage Example:
67
+
68
+ ```python
69
+ listbox_chooser = ListboxChooser("Choose options", {"Option 1": 1, "Option 2": 2, "Option 3": 3})
70
+ for choice, value in listbox_chooser.get_choices():
71
+ print(choice, value)
72
+ ```
73
+ """
74
+
75
+ def __init__(self, window_title: str, options: dict, default=None):
76
+ super().__init__(window_title)
77
+ self.exit_button = None
78
+ self.choices = list(options.keys())
79
+ self.options = options
80
+ self.default = default
81
+ self.selection_var = tk.Variable(self)
82
+ self.create_widgets()
83
+ self.mainloop()
84
+
85
+ def create_widgets(self):
86
+ frame = ttk.Frame(self)
87
+ frame.pack(padx=2, pady=2)
88
+
89
+ listbox = tk.Listbox(frame, listvariable=tk.Variable(self, value=self.choices), selectmode="multiple",
90
+ height=min(len(self.choices), 50), width=max(len(c) for c in self.choices))
91
+ listbox.pack(side=tk.LEFT, fill=tk.BOTH)
92
+
93
+ scrollbar = ttk.Scrollbar(frame, command=listbox.yview)
94
+ scrollbar.pack(side=tk.RIGHT, fill=tk.BOTH)
95
+ listbox.config(yscrollcommand=scrollbar.set)
96
+
97
+ listbox.bind("<<ListboxSelect>>", self.on_select)
98
+
99
+ self.exit_button = ttk.Button(self, text="OK", command=self.destroy, state=tk.DISABLED)
100
+ self.exit_button.pack(pady=4, side=tk.BOTTOM)
101
+
102
+ def on_select(self, event):
103
+ self.exit_button['state'] = tk.NORMAL
104
+ self.selection_var.set(event.widget.curselection())
105
+
106
+ def get_choices(self):
107
+ for choice in self.selection_var.get():
108
+ yield self.choices[choice], self.options.get(self.choices[choice], self.default)
@@ -1,4 +1,4 @@
1
- from urllib.parse import urljoin, urlparse
1
+ from urllib.parse import urlparse
2
2
 
3
3
  import requests
4
4
  from bs4 import BeautifulSoup
@@ -28,13 +28,17 @@ def page_links_graph_model(max_depth: int = DEFAULT_MAX_DEPTH):
28
28
  for link in soup.find_all('a', href=True):
29
29
  child_url = link.get('href')
30
30
 
31
- if child_url.startswith('javascript:'):
31
+ if child_url.startswith('javascript:'): # Skip JavaScript links
32
32
  continue
33
- elif child_url.startswith('//'):
33
+
34
+ if child_url.startswith('//'): # Handle protocol-relative URLs
34
35
  child_url = f"https:{child_url}"
35
- elif not bool(urlparse(child_url).netloc):
36
- child_url = urljoin(url, child_url)
37
- elif not child_url.startswith('http'):
36
+
37
+ if not bool(urlparse(child_url).netloc): # Skip relative URLs
38
+ # child_url = urljoin(url, child_url)
39
+ continue
40
+
41
+ if not child_url.startswith('http'): # Skip non-HTTP URLs
38
42
  continue
39
43
 
40
44
  yield {'source': url, 'target': child_url}
@@ -62,7 +66,7 @@ if __name__ == '__main__':
62
66
  model=model,
63
67
  graph_type=graphinate.GraphType.DiGraph,
64
68
  default_node_attributes={'type': 'url'},
65
- builder=graphinate.builders.NetworkxBuilder,
66
- builder_output_handler=graphinate.materializers.matplotlib.plot,
69
+ builder=graphinate.builders.GraphQLBuilder,
70
+ builder_output_handler=graphinate.graphql,
67
71
  **params
68
72
  )
@@ -1,10 +1,10 @@
1
1
  [project]
2
2
  name = "Graphinate"
3
- version = "0.4.0"
3
+ version = "0.5.1"
4
4
  authors = [
5
5
  { name = "Eran Rivlis", email = "eran@rivlis.info" },
6
6
  ]
7
- description = "Graphinate. Data to Graphs."
7
+ description = "𝔾raphinate. Data to Graphs."
8
8
  readme = "README.md"
9
9
  requires-python = ">=3.10"
10
10
  classifiers = [
@@ -45,6 +45,15 @@ dependencies = [
45
45
 
46
46
 
47
47
  [project.optional-dependencies]
48
+ plot = [
49
+ "scipy"
50
+ ]
51
+ server = [
52
+ "starlette-prometheus",
53
+ "uvicorn[standard]"
54
+ ]
55
+
56
+ [dependency-groups]
48
57
  dev = [
49
58
  "ruff",
50
59
  "pipdeptree"
@@ -66,13 +75,7 @@ test = [
66
75
  "pytest-randomly",
67
76
  "pytest-xdist"
68
77
  ]
69
- plot = [
70
- "scipy"
71
- ]
72
- server = [
73
- "starlette-prometheus",
74
- "uvicorn[standard]"
75
- ]
78
+
76
79
 
77
80
 
78
81
  [build-system]