Graphinate 0.15.3__tar.gz → 0.16.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.15.3 → graphinate-0.16.0}/CHANGELOG.md +10 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/PKG-INFO +4 -3
- {graphinate-0.15.3 → graphinate-0.16.0}/README.md +2 -2
- graphinate-0.16.0/design/proposals/GEP-003_Roadmap.md +122 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-010_Explicit_Dependency_Injection.md +10 -9
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-016_CLI_Argument_Parsing_and_Path_Safety.md +2 -1
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-017_Decoupled_Server_Architecture.md +24 -4
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-031_High_Performance_Vectorized_Operations.md +9 -3
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-032_GraphModel_Compilation_and_Validation_Lifecycle.md +5 -3
- graphinate-0.16.0/docs/usage/cli.md +56 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/usage/lib.md +1 -1
- {graphinate-0.15.3 → graphinate-0.16.0}/pyproject.toml +3 -1
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/.agents/skills/graphinate/SKILL.md +3 -3
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/builders/graphql.py +39 -26
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/builders/networkx.py +27 -10
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/modeling.py +63 -24
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/renderers/graphql.py +23 -7
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/graphinate/builders/test_graphql.py +97 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/graphinate/renderers/test_graphql_server.py +2 -3
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/graphinate/test_modeling.py +114 -6
- graphinate-0.16.0/tests/graphinate/test_tools.py +63 -0
- graphinate-0.16.0/uv.lock +3788 -0
- graphinate-0.15.3/design/proposals/GEP-003_Roadmap.md +0 -84
- graphinate-0.15.3/docs/usage/cli.md +0 -53
- {graphinate-0.15.3 → graphinate-0.16.0}/.coveragerc +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/.deepsource.toml +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/.github/dependabot.yml +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/.github/workflows/codeql.yml +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/.github/workflows/codspeed.yml +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/.github/workflows/publish-docs.yaml +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/.github/workflows/publish.yml +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/.github/workflows/test-beta.yml +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/.github/workflows/test.yml +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/.gitignore +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/.python-version +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/.sonarcloud.properties +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/AGENTS.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/LICENSE +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/PERSONA.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/PRINCIPLES.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/STYLEGUIDE.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/TELEMETRY.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/TOOLS.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/benchmarks/color_benchmark.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/benchmarks/conftest.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/benchmarks/test_builders_benchmark.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/benchmarks/test_color_benchmark.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/benchmarks/test_converters_benchmark.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/benchmarks/test_modeling_benchmark.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/analysis/Builders_Analysis.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/analysis/CLI_Analysis.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/analysis/Core_Analysis.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/analysis/GraphModel_Analysis.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/analysis/Renderers_Analysis.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/analysis/Server_Analysis.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/analysis/Viewer_Analysis.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/art_prompts.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/art_prompts_v1.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/art_prompts_v2.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/grading/Builders_Grading.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/grading/CLI_Grading.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/grading/Core_Grading.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/grading/Modeling_Grading.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/grading/Renderers_Grading.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/grading/Server_Grading.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/grading/Viewer_Grading.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/prompts/01_The_Foundations.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/prompts/02_The_Fantastical.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/prompts/03_The_Analog.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/prompts/04_The_Avant_Garde.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/prompts/05_The_Pop_Culture.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/prompts/06_The_Modern.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/prompts/07_Graphinate_2.0.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-000_Graphinate_Enhancement_Proposals.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-001_The_Graphinate_Mission.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-002_Modularization_Strategy.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-007_Theoretical_Foundations.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-011_Standardized_Element_Factory.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-012_Robust_Model_Composition.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-013_Stable_ID_Serialization.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-014_Explicit_GraphQL_Schema_Generation.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-015_Refactored_Graph_Population_Strategies.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-018_Relay_Support.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-019_Offline_Viewer_Support.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-020_Modular_Frontend_Architecture.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-022_2D_Visualization_Mode.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-023_Async_Support.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-024_The_Graph_Engine.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-025_Signed_ID_Serialization.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-026_Pluggable_Visualization_and_Notebook_Support.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-027_Advanced_ThreeJS_Visualizations.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-028_MCP_Server_Integration.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-029_Extraction_Strategies.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-030_Node_Type_Taxonomy.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/acknowledgements.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/advanced/modeling.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/advanced/optimization.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/advanced/secure_ids.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/assets/badge/v0.json +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/assets/images/logo-128.png +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/assets/images/network_graph.png +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/assets/stylesheets/extra.css +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/development.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/diagrams/class_diagram.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/diagrams/component_diagram.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/diagrams/function_call_graph.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/examples/code.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/examples/github.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/examples/math.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/examples/social.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/examples/system.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/examples/web.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/gen_ref_pages.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/index.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/introduction.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/start.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/docs/tutorial.md +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/code/git_commits.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/code/python_ast.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/code/python_dependencies.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/code/requirements.txt +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/code/tokens.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/github/_client.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/github/commits_visibilty_graph.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/github/followers.graphql +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/github/followers.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/github/graphql.config.yml +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/github/repositories.graphql +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/github/repositories.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/github/requirements.txt +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/math/_test_materializers.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/math/graph_atlas.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/math/graphs.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/math/gui.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/math/materializers.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/math/polygonal_graph.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/math/requirements.txt +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/social/cache/13/dd/73ce25face7beb30b69b64feeb77.val +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/social/cache/21/9e/00846f323987ba16cfbe0127d8eb.val +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/social/cache/70/b6/2aefb0269adce7fedf877fa0d267.val +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/social/cache/87/f5/ec1739bc369e84c3fcb302bf532a.val +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/social/cache/ba/fe/3aca7b2c38abff60e7ce5eb486a8.val +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/social/cache/c7/9e/ce82b0288020b7152779df09bd73.val +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/social/cache/cache.db +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/social/cache/d2/53/3b88f2fc162561cfdbbe9abc352a.val +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/social/cache/e2/d5/5d079f200eabf9b625b0473f6fbe.val +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/social/gui.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/social/music_artists.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/social/requirements.txt +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/system/.ignore +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/system/files.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/system/processes.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/system/requirements.txt +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/web/html_dom.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/web/page_links.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/examples/web/requirements.txt +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/playground/check_repo.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/playground/ethernet/traceroute.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/playground/genric_graph.graphql +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/playground/graphql.config.yml +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/playground/house_of_graphs.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/playground/octagonal_graph.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/playground/science/caffeine.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/playground/social/db.xml +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/playground/social/music.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/playground/social/requirements.txt +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/playground/text/nlp_graph.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/playground/text/requirements.txt +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/playground/time_series/requirements.txt +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/playground/time_series/visibility_graph.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/playground/word_graph.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/properdocs.yml +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/sonar-project.properties +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/__init__.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/__main__.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/_secure.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/builders/__init__.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/builders/builder.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/builders/d3.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/builders/mermaid.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/cli.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/color.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/constants.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/converters.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/enums.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/renderers/__init__.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/renderers/matplotlib.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/server/__init__.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/server/starlette/__init__.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/server/starlette/views.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/server/web/__init__.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/server/web/elements/index.html +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/server/web/graphiql/index.html +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/server/web/rapidoc/index.html +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/server/web/static/images/logo-128.png +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/server/web/static/images/logo.svg +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/server/web/static/images/network_graph.png +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/server/web/viewer/index.html +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/server/web/voyager/index.html +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/tools.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/src/graphinate/typing.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/conftest.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/graphinate/builders/test_build.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/graphinate/builders/test_d3.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/graphinate/builders/test_mermaid.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/graphinate/builders/test_networkx.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/graphinate/renderers/test_matplotlib_draw.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/graphinate/renderers/test_matplotlib_plot.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/graphinate/server/test_starlette.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/graphinate/test_cli.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/graphinate/test_color.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/graphinate/test_converters.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/graphinate/test_modeling_add.py +0 -0
- {graphinate-0.15.3 → graphinate-0.16.0}/tests/graphinate/test_server.py +0 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: Graphinate
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16.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
|
|
7
7
|
Project-URL: Bug Tracker, https://github.com/erivlis/graphinate/issues
|
|
8
8
|
Project-URL: Source, https://github.com/erivlis/graphinate
|
|
9
9
|
Author-email: Eran Rivlis <eran@rivlis.info>
|
|
10
|
+
License-Expression: LGPL-3.0-or-later
|
|
10
11
|
License-File: LICENSE
|
|
11
12
|
Keywords: declarative,graph
|
|
12
13
|
Classifier: Development Status :: 4 - Beta
|
|
@@ -208,7 +209,7 @@ or
|
|
|
208
209
|
uv add graphinate[server]
|
|
209
210
|
```
|
|
210
211
|
|
|
211
|
-
**Graphinate** officially supports Python >= 3.
|
|
212
|
+
**Graphinate** officially supports Python >= 3.11.
|
|
212
213
|
|
|
213
214
|
### Example
|
|
214
215
|
|
|
@@ -251,7 +252,7 @@ mermaid_markdown: str = graphinate.mermaid.markdown(diagram)
|
|
|
251
252
|
mermaid_html: str = graphinate.mermaid.html(diagram, title=graph_model.name)
|
|
252
253
|
|
|
253
254
|
# or use the GraphQL Builder
|
|
254
|
-
builder = graphinate.builders.GraphQLBuilder(
|
|
255
|
+
builder = graphinate.builders.GraphQLBuilder(graph_model)
|
|
255
256
|
|
|
256
257
|
# to create a Strawberry GraphQL schema
|
|
257
258
|
schema = builder.build()
|
|
@@ -159,7 +159,7 @@ or
|
|
|
159
159
|
uv add graphinate[server]
|
|
160
160
|
```
|
|
161
161
|
|
|
162
|
-
**Graphinate** officially supports Python >= 3.
|
|
162
|
+
**Graphinate** officially supports Python >= 3.11.
|
|
163
163
|
|
|
164
164
|
### Example
|
|
165
165
|
|
|
@@ -202,7 +202,7 @@ mermaid_markdown: str = graphinate.mermaid.markdown(diagram)
|
|
|
202
202
|
mermaid_html: str = graphinate.mermaid.html(diagram, title=graph_model.name)
|
|
203
203
|
|
|
204
204
|
# or use the GraphQL Builder
|
|
205
|
-
builder = graphinate.builders.GraphQLBuilder(
|
|
205
|
+
builder = graphinate.builders.GraphQLBuilder(graph_model)
|
|
206
206
|
|
|
207
207
|
# to create a Strawberry GraphQL schema
|
|
208
208
|
schema = builder.build()
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# GEP-003: Graphinate Development Roadmap
|
|
2
|
+
|
|
3
|
+
| Field | Value |
|
|
4
|
+
|:------------|:------------------------|
|
|
5
|
+
| **GEP** | 3 |
|
|
6
|
+
| **Title** | Development Roadmap |
|
|
7
|
+
| **Author** | Eran Rivlis |
|
|
8
|
+
| **Status** | Active |
|
|
9
|
+
| **Type** | Process |
|
|
10
|
+
| **Created** | 2025-12-30 |
|
|
11
|
+
| **Updated** | 2026-10-17 |
|
|
12
|
+
|
|
13
|
+
## Abstract
|
|
14
|
+
|
|
15
|
+
This document outlines the strategic execution plan for the Graphinate Enhancement Proposals (GEPs). It serves as a living document to track the prioritization and status of major initiatives.
|
|
16
|
+
|
|
17
|
+
## Phase 1: Stabilization (Completed)
|
|
18
|
+
|
|
19
|
+
*Focus: Fixing brittle code, security risks, and "bad magic". All Phase 1 stabilization proposals (**GEP-010**, **GEP-016**, **GEP-017**, **GEP-025**, **GEP-032**) have been implemented and archived.*
|
|
20
|
+
|
|
21
|
+
## Phase 2: Core Spine & Architectural Health
|
|
22
|
+
|
|
23
|
+
*Focus: Strengthening the core execution engine, schema generation, and modularity.*
|
|
24
|
+
|
|
25
|
+
| GEP | Title | Impact | Difficulty | Rationale |
|
|
26
|
+
|:------------|:----------------------------------------------|:---------|:-----------|:-------------------------------------------------------------------------------------------------------------------------------------|
|
|
27
|
+
| **GEP-024** | **The Graph Engine** | **High** | **Hard** | **Core Architecture.** Extracting the execution logic is the foundation for Async, Realtime, and better testing. Supersedes GEP-015. |
|
|
28
|
+
| **GEP-014** | **Explicit GraphQL Schema Generation** | **High** | **Hard** | **Major Refactor.** Refactoring dynamic class generation to `strawberry.tools.create_type` and context-injected resolvers. |
|
|
29
|
+
| **GEP-023** | **Async Support** | **High** | **Hard** | **Performance.** Massive gains for I/O-bound crawling (`async def` generators). Dependent on GEP-024. |
|
|
30
|
+
| **GEP-019** | **Offline Viewer Support** | Medium | Easy | **Reliability.** GraphiQL/Voyager are vendored; completing local vendoring for `viewer` removes remaining CDN dependencies. |
|
|
31
|
+
| **GEP-031** | **High-Performance Vectorized Operations** | Medium | Medium | **Performance.** Progressive enhancement via optional NumPy/Numba (partially active in `color.py`). |
|
|
32
|
+
| **GEP-011** | **Standardized Element Factory** | Low | Easy | **Cleanup.** Minor API improvement for element tuple construction. |
|
|
33
|
+
| **GEP-012** | **Robust Model Composition** | Low | Easy | **Cleanup.** Handling advanced edge cases in `ModelA + ModelB` merging. |
|
|
34
|
+
|
|
35
|
+
## Phase 3: Focused Expansion
|
|
36
|
+
|
|
37
|
+
*Focus: Practical extensions that build directly on the core engine and schema.*
|
|
38
|
+
|
|
39
|
+
| GEP | Title | Impact | Difficulty | Rationale |
|
|
40
|
+
|:------------|:----------------------------------|:---------|:-----------|:-------------------------------------------------------------------------------------------------------|
|
|
41
|
+
| **GEP-018** | **Relay Support** | **High** | Medium | **Enterprise Feature.** Makes the API compatible with modern frontend clients (React Relay, Apollo). |
|
|
42
|
+
| **GEP-020** | **Modular Frontend Architecture** | Medium | Medium | **Maintainability.** Splitting the monolithic `viewer/index.html` into maintainable ES modules. |
|
|
43
|
+
| **GEP-029** | **Extraction Strategies** | Medium | Medium | **Ergonomics.** Lightweight iterator/generator helpers (`scan`, `walk`, `listen`) or cookbook recipes. |
|
|
44
|
+
|
|
45
|
+
## Phase 4: Exploratory & Spin-Off Track (Ideation / Brainstorming)
|
|
46
|
+
|
|
47
|
+
*Focus: Ideas originating from exploratory brainstorming sessions. Rather than bloating the core `graphinate` package, these proposals should be treated as candidates for standalone companion packages, external integrations, or example recipes.*
|
|
48
|
+
|
|
49
|
+
| GEP | Title | Recommended Vehicle | Rationale |
|
|
50
|
+
|:------------|:-----------------------------------------------|:-------------------------------------|:------------------------------------------------------------------------------------------------------------------------------|
|
|
51
|
+
| **GEP-026** | **Pluggable Visualization & Notebook Support** | Companion Package / Cookbook Recipes | Keeps core `graphinate` free of heavy frontend widget toolchains while enabling Jupyter/Cosmograph recipes. |
|
|
52
|
+
| **GEP-027** | **Advanced Three.js Visualizations** | Standalone Frontend / Demo Showcase | Custom WebGL shaders, procedural cities, and time tunnels belong in a dedicated visualization showcase, not a Python ETL lib. |
|
|
53
|
+
| **GEP-028** | **MCP Server Integration** | Companion Package (`graphinate-mcp`) | Ideal as a lightweight wrapper or example recipe exposing `GraphModel` and `GraphQLBuilder` to LLM agents via `fastmcp`. |
|
|
54
|
+
| **GEP-030** | **Node Type Taxonomy** | Cookbook Recipes / Domain Extensions | Universal ontologies (C4, Schema.org, Pygments) are best demonstrated as user-space models/recipes rather than core classes. |
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Strategic Assessment of the GEP Trajectory
|
|
59
|
+
|
|
60
|
+
### 1. Engineering Assessment: The Three Buckets
|
|
61
|
+
|
|
62
|
+
The trajectory from **Graphinate 0.x** (a synchronous, decorator-based NetworkX/GraphQL builder) toward **Graphinate 2.0** (an observable, async-capable, type-safe Graph Synthesis Engine) is architecturally cohesive and well-differentiated in the Python ecosystem—provided that **implementation consolidation takes precedence over scope expansion**.
|
|
63
|
+
|
|
64
|
+
Across the GEP archive, proposals fall naturally into three distinct tiers:
|
|
65
|
+
|
|
66
|
+
1. **The Core Structural Spine (`GEP-010` → `GEP-032` → `GEP-012` → `GEP-024` → `GEP-023`)**:
|
|
67
|
+
- This is the true heart of Graphinate: moving from implicit `_id` naming magic to explicit `ParentId` dependency injection (**GEP-010**), compiling immutable validated models (**GEP-032**), decoupling traversal (`GraphEngine`, **GEP-024**) from storage (`NetworkxBuilder`), and unlocking `async def` generators (**GEP-023**).
|
|
68
|
+
- Every link in this chain directly enables the next and strengthens the library's core value proposition.
|
|
69
|
+
2. **Boundary & Hygiene Refactorings (`GEP-002`, `GEP-014`, `GEP-016`, `GEP-017`, `GEP-019`, `GEP-020`, `GEP-031`)**:
|
|
70
|
+
- Practical engineering debt paydown: exposing `create_app()` (**GEP-017**), replacing fragile dynamic class construction in `GraphQLBuilder` with `strawberry.tools.create_type` and context injection (**GEP-014**), and keeping heavy dependencies optional (**GEP-002**).
|
|
71
|
+
3. **Exploratory Ideation / Ambition Creep (`GEP-026`, `GEP-027`, `GEP-028`, `GEP-029`, `GEP-030`)**:
|
|
72
|
+
- These proposals originated in exploratory brainstorming sessions. While intellectually rich, features like custom Three.js shaders/procedural cities (**GEP-027**), universal class ontologies mapping Schema.org/C4/Pygments (**GEP-030**), and multi-engine WebGL abstractions (**GEP-026**) risk pulling a focused ~1,200-line Python library into maintaining a sprawling JavaScript/WebGL framework or ontology library ("Second-System Syndrome").
|
|
73
|
+
- **Strategic Decision:** Treat Tier 3 proposals as **Exploratory / Spin-Off Candidates** (separate high-level projects, plugin packages, or cookbook examples) so the core library stays lean and faithful to **GEP-001**.
|
|
74
|
+
|
|
75
|
+
### 2. The Council's Opinion (By Pillar)
|
|
76
|
+
|
|
77
|
+
Evaluating the codebase and GEP trajectory through the **7 Pillars of the Council Framework** (**GEP-001**):
|
|
78
|
+
|
|
79
|
+
| Council Member | Verdict | Critique & Trajectory Guidance |
|
|
80
|
+
|:-------------------------------|:-------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
81
|
+
| **1. Symmetry (Noether)** | **A-** | `@model.node` supports `ParentId`, hierarchy, multiplicity, and deferred compilation (**GEP-010**, **GEP-032**). Future work in **GEP-024** should consider bringing symmetric dependency/scoping ergonomics to `@model.edge`, and ensuring edges can naturally target hierarchical (`unique=False`) nodes whose keys are lineage tuples. |
|
|
82
|
+
| **2. Falsifiability (Popper)** | **A** | High branch coverage (~98%) and property-style tests provide a strong safety net. Every Standards Track GEP must be paired with falsifying regression tests before its status transitions to `Active`. |
|
|
83
|
+
| **3. Efficiency (Shannon)** | **A-** | `color.py` (**GEP-031**), `VariableNameManager` (`tools.py`), and $O(\text{deg}(v))$ GraphQL neighbor resolution are fast and lean. The primary remaining efficiency win is **GEP-002**: moving heavy packages (`matplotlib`, `strawberry-graphql`) out of mandatory core install dependencies into optional extras. |
|
|
84
|
+
| **4. Safety (The Golem)** | **A-** | With **GEP-025** (HMAC-SHA256 signed IDs), **GEP-032** (immutable `model.compile()` clones), and isolated `GraphNodeType` schema enums, thread-safety and concurrency hazards have been substantially hardened—critical for Python 3.13t–3.15t free-threaded execution. |
|
|
85
|
+
| **5. Clarity (Feynman)** | **A** | The `@model.node` / `@model.edge` declarative DSL remains simple and expressive. Completing **GEP-014** (explicit GraphQL schema generation with context injection) will remove the last major pocket of closure metaprogramming in `builders/graphql.py`. |
|
|
86
|
+
| **6. Consistency (Russell)** | **A-** | Case-insensitive parent resolution and explicit `_lineage` tuple propagation across recursion depths have unified behavior between `modeling.py` and `builders/networkx.py`. |
|
|
87
|
+
| **7. Harmony (The Steward)** | **A-** | **The Dennis Point:** Resist building custom 3D shaders (**GEP-027**) or rigid taxonomies (**GEP-030**) inside core before the execution spine (`compile()` → `GraphEngine` → `abuild()`) is complete. Keep Graphinate focused on its mission: *"A declarative, Pythonic ETL engine for synthesizing graphs from hierarchical data."* |
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Summary Priority Matrix (Core Library)
|
|
92
|
+
|
|
93
|
+
| Priority | GEP | Title | Phase |
|
|
94
|
+
|:---------|:------------|:-------------------------------------------|:--------|
|
|
95
|
+
| 1 | **GEP-024** | The Graph Engine | Phase 2 |
|
|
96
|
+
| 2 | **GEP-014** | Explicit GraphQL Schema Generation | Phase 2 |
|
|
97
|
+
| 3 | **GEP-023** | Async Support | Phase 2 |
|
|
98
|
+
| 4 | **GEP-019** | Offline Viewer Support | Phase 2 |
|
|
99
|
+
| 5 | **GEP-031** | High-Performance Vectorized Operations | Phase 2 |
|
|
100
|
+
| 6 | **GEP-018** | Relay Support | Phase 3 |
|
|
101
|
+
| 7 | **GEP-020** | Modular Frontend Architecture | Phase 3 |
|
|
102
|
+
| 8 | **GEP-029** | Extraction Strategies (Helpers / Recipes) | Phase 3 |
|
|
103
|
+
|
|
104
|
+
## Archive (Completed / Withdrawn / Superseded)
|
|
105
|
+
|
|
106
|
+
| GEP | Title | Status | Reason |
|
|
107
|
+
|:------------|:---------------------------------------|:------------------|:-----------------------------------------------------------------------|
|
|
108
|
+
| **GEP-000** | Graphinate Enhancement Proposals | **Active** | Process definition. |
|
|
109
|
+
| **GEP-001** | The Graphinate Mission | **Active** | Mission statement. |
|
|
110
|
+
| **GEP-002** | Modularization Strategy | **Active** | Architectural principle. |
|
|
111
|
+
| **GEP-007** | Theoretical Foundations | **Active** | Informational / Theory. |
|
|
112
|
+
| **GEP-010** | Explicit Dependency Injection | **Active** | Implemented explicit dependency injection using `ParentId`. |
|
|
113
|
+
| **GEP-013** | Stable ID Serialization | **Withdrawn** | `repr()` deemed sufficient and more robust for Python types. |
|
|
114
|
+
| **GEP-016** | CLI Argument Parsing & Path Safety | **Active** | Implemented Typer CLI with safe dynamic argument parsing & paths. |
|
|
115
|
+
| **GEP-017** | Decoupled Server Architecture | **Active** | Exposed `create_app()` ASGI factory in `graphinate.renderers.graphql`. |
|
|
116
|
+
| **GEP-025** | Signed ID Serialization | **Active** | Implemented as an optional, opt-in HMAC-SHA256 signature layer. |
|
|
117
|
+
| **GEP-032** | GraphModel Compilation & Validation | **Active** | Implemented `GraphModel.compile()` and deferred validation. |
|
|
118
|
+
| **GEP-015** | Refactored Graph Population Strategies | **Superseded** | Replaced by **GEP-024** (The Graph Engine). |
|
|
119
|
+
| **GEP-022** | 2D Visualization Mode | **Superseded** | Replaced by **GEP-026** (Pluggable Visualization). |
|
|
120
|
+
| **GEP-027** | Advanced Three.js Visualizations | **Informational** | Exploratory design concepts (Spin-Off / Showcase Track). |
|
|
121
|
+
|
|
122
|
+
|
{graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-010_Explicit_Dependency_Injection.md
RENAMED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
| **GEP** | 10 |
|
|
6
6
|
| **Title** | Explicit Dependency Injection |
|
|
7
7
|
| **Author** | Eran Rivlis |
|
|
8
|
-
| **Status** |
|
|
8
|
+
| **Status** | Active |
|
|
9
9
|
| **Type** | Standards Track |
|
|
10
10
|
| **Created** | 2025-12-25 |
|
|
11
|
-
| **Updated** | 2026-
|
|
11
|
+
| **Updated** | 2026-10-17 |
|
|
12
12
|
|
|
13
13
|
## Abstract
|
|
14
14
|
|
|
@@ -144,16 +144,17 @@ and resolved within [modeling.py](file:///C:/dev/erivlis/graphinate/src/graphina
|
|
|
144
144
|
* 2025-12-25: Initial Draft
|
|
145
145
|
* 2026-06-21: Accepted Option 2 (Type Hinting) and implemented the injection engine.
|
|
146
146
|
* 2026-06-22: Documented remaining structural and validation constraints as open issues/future work.
|
|
147
|
+
* 2026-10-17: Resolved all 5 open issues (deferred compilation validation via GEP-032, immutable `compile()` clone, explicit `_lineage` tuple tracking for non-unique recursive nodes, case-insensitive lineage resolution, and removal of `NodeModel.parameters`).
|
|
147
148
|
|
|
148
|
-
##
|
|
149
|
+
## Resolved Issues (Formerly Open Issues)
|
|
149
150
|
|
|
150
|
-
During the design review of the GEP-010 implementation, the Council of Principles identified
|
|
151
|
+
During the initial design review of the GEP-010 implementation, the Council of Principles identified five follow-up items, all of which have now been resolved:
|
|
151
152
|
|
|
152
|
-
1. **
|
|
153
|
-
2. **
|
|
154
|
-
3. **Recursive Lineage Namespace Collision
|
|
155
|
-
4. **Lineage Casing
|
|
156
|
-
5. **Dead Code Cleanup (`NodeModel.parameters`):**
|
|
153
|
+
1. **Deferred Registration Validation (Resolved via GEP-032):** Parameter validation (`_validate_node_dependency_registration`) now runs during `GraphModel.compile()` rather than eagerly at decorator execution time, removing topological decoration-order constraints and enabling cross-model composition (`ModelA + ModelB`).
|
|
154
|
+
2. **Immutable Model Compilation (Resolved via GEP-032):** `NetworkxBuilder` now compiles a clone of the `GraphModel` via `self.model.compile(...)` instead of mutating the shared `GraphModel` in-place via `rectify()`.
|
|
155
|
+
3. **Recursive Lineage Namespace Collision (Resolved):** `_populate_nodes` and `_populate_node_type` now track an explicit `_lineage` tuple across recursion depth, preventing `folder -> folder` self-parenting key collisions when `unique=False`.
|
|
156
|
+
4. **Lineage Casing Symmetry (Resolved):** `node_children_types`, `_validate_node_dependency_registration`, and `_parent_node_id` now resolve parent types case-insensitively.
|
|
157
|
+
5. **Dead Code Cleanup (`NodeModel.parameters`) (Resolved):** Removed the obsolete `parameters` attribute from `NodeModel`.
|
|
157
158
|
|
|
158
159
|
## Copyright
|
|
159
160
|
|
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
| **GEP** | 16 |
|
|
6
6
|
| **Title** | CLI Argument Parsing & Path Safety |
|
|
7
7
|
| **Author** | Eran Rivlis |
|
|
8
|
-
| **Status** |
|
|
8
|
+
| **Status** | Active |
|
|
9
9
|
| **Type** | Standards Track |
|
|
10
10
|
| **Created** | 2025-12-25 |
|
|
11
|
+
| **Updated** | 2026-10-17 |
|
|
11
12
|
|
|
12
13
|
## Abstract
|
|
13
14
|
|
{graphinate-0.15.3 → graphinate-0.16.0}/design/proposals/GEP-017_Decoupled_Server_Architecture.md
RENAMED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
| **GEP** | 17 |
|
|
6
6
|
| **Title** | Decoupled Server Architecture |
|
|
7
7
|
| **Author** | Eran Rivlis |
|
|
8
|
-
| **Status** |
|
|
8
|
+
| **Status** | Active |
|
|
9
9
|
| **Type** | Standards Track |
|
|
10
10
|
| **Created** | 2025-12-25 |
|
|
11
11
|
|
|
@@ -28,13 +28,23 @@ This proposal suggests separating the app creation from the server execution.
|
|
|
28
28
|
Refactor `renderers.graphql` to expose a factory function:
|
|
29
29
|
|
|
30
30
|
```python
|
|
31
|
-
def create_app(
|
|
31
|
+
def create_app(
|
|
32
|
+
graphql_schema: strawberry.Schema,
|
|
33
|
+
port: int = DEFAULT_PORT,
|
|
34
|
+
debug: bool = False,
|
|
35
|
+
**kwargs: Any,
|
|
36
|
+
) -> Starlette:
|
|
32
37
|
# ... construct and return the app ...
|
|
33
38
|
return app
|
|
34
39
|
|
|
35
40
|
|
|
36
|
-
def server(
|
|
37
|
-
|
|
41
|
+
def server(
|
|
42
|
+
graphql_schema: strawberry.Schema,
|
|
43
|
+
port: int = DEFAULT_PORT,
|
|
44
|
+
debug: bool = False,
|
|
45
|
+
**kwargs: Any,
|
|
46
|
+
) -> None:
|
|
47
|
+
app = create_app(graphql_schema, port=port, debug=debug, **kwargs)
|
|
38
48
|
uvicorn.run(app, ...)
|
|
39
49
|
```
|
|
40
50
|
|
|
@@ -42,3 +52,13 @@ def server(schema: Schema, **kwargs):
|
|
|
42
52
|
|
|
43
53
|
The `server` function signature will remain the same, ensuring backward compatibility. The new `create_app` function
|
|
44
54
|
will be an additive change.
|
|
55
|
+
|
|
56
|
+
## Reference Implementation
|
|
57
|
+
|
|
58
|
+
- [`src/graphinate/renderers/graphql.py`](file:///C:/dev/erivlis/graphinate/src/graphinate/renderers/graphql.py)
|
|
59
|
+
- [`tests/graphinate/renderers/test_graphql_server.py`](file:///C:/dev/erivlis/graphinate/tests/graphinate/renderers/test_graphql_server.py)
|
|
60
|
+
|
|
61
|
+
## Change Log
|
|
62
|
+
|
|
63
|
+
- **2025-12-25:** Initial draft.
|
|
64
|
+
- **2026-10-17:** Implemented `create_app` in `graphinate.renderers.graphql` and refactored `server()` to delegate to `create_app`. Updated status to `Active`.
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
# GEP-031: High-Performance Vectorized Operations
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
| Field | Value |
|
|
4
|
+
|:------------|:---------------------------------------|
|
|
5
|
+
| **GEP** | 31 |
|
|
6
|
+
| **Title** | High-Performance Vectorized Operations |
|
|
7
|
+
| **Author** | Eran Rivlis |
|
|
8
|
+
| **Status** | Draft |
|
|
9
|
+
| **Type** | Standards Track |
|
|
10
|
+
| **Created** | 2023-10-27 |
|
|
11
|
+
| **Updated** | 2026-10-17 |
|
|
6
12
|
|
|
7
13
|
## Abstract
|
|
8
14
|
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
| **GEP** | 32 |
|
|
6
6
|
| **Title** | GraphModel Compilation and Validation Lifecycle |
|
|
7
7
|
| **Author** | Eran Rivlis |
|
|
8
|
-
| **Status** |
|
|
8
|
+
| **Status** | Active |
|
|
9
9
|
| **Type** | Standards Track |
|
|
10
10
|
| **Created** | 2026-06-22 |
|
|
11
|
-
| **Updated** | 2026-
|
|
11
|
+
| **Updated** | 2026-10-17 |
|
|
12
12
|
|
|
13
13
|
## Abstract
|
|
14
14
|
|
|
@@ -132,10 +132,12 @@ This proposal serves as the structural glue between several critical enhancement
|
|
|
132
132
|
## Reference Implementation
|
|
133
133
|
|
|
134
134
|
* **Source File:** [modeling.py](file:///C:/dev/erivlis/graphinate/src/graphinate/modeling.py)
|
|
135
|
-
* **Builder Integration:** [
|
|
135
|
+
* **Builder Integration:** [networkx.py](file:///C:/dev/erivlis/graphinate/src/graphinate/builders/networkx.py)
|
|
136
136
|
|
|
137
137
|
---
|
|
138
138
|
|
|
139
139
|
## Change Log
|
|
140
140
|
|
|
141
141
|
* 2026-06-22: Initial Draft outlining the compilation phases, late validation, and synergies with GEP-010, GEP-012, and GEP-024.
|
|
142
|
+
* 2026-10-17: Implemented `GraphModel.compile()`, `_validate_structural_dependencies()`, deferred dependency validation, and immutable model compilation in `NetworkxBuilder`.
|
|
143
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: CLI
|
|
3
|
+
icon: lucide/command
|
|
4
|
+
---
|
|
5
|
+
# CLI
|
|
6
|
+
|
|
7
|
+
## Commands
|
|
8
|
+
|
|
9
|
+
``` shell
|
|
10
|
+
Usage: python -m graphinate [OPTIONS] COMMAND [ARGS]...
|
|
11
|
+
|
|
12
|
+
Options:
|
|
13
|
+
--help Show this message and exit.
|
|
14
|
+
|
|
15
|
+
Commands:
|
|
16
|
+
save
|
|
17
|
+
server
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Save
|
|
21
|
+
|
|
22
|
+
```console
|
|
23
|
+
Usage: python -m graphinate save [OPTIONS]
|
|
24
|
+
|
|
25
|
+
Options:
|
|
26
|
+
-m, --model MODEL A GraphModel instance reference {module-
|
|
27
|
+
name}:{GraphModel-instance-variable-name} For example,
|
|
28
|
+
given var `model=GraphModel()` defined in app.py file,
|
|
29
|
+
then the reference should be app:model
|
|
30
|
+
--debug / --no-debug Enable debug logging. [env var: GRAPHINATE_DEBUG]
|
|
31
|
+
--help Show this message and exit.
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Server
|
|
35
|
+
|
|
36
|
+
!!! tip
|
|
37
|
+
|
|
38
|
+
requires the `server` extra to be installed.
|
|
39
|
+
|
|
40
|
+
```shell
|
|
41
|
+
pip install graphinate[server]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```console
|
|
45
|
+
Usage: python -m graphinate server [OPTIONS]
|
|
46
|
+
|
|
47
|
+
Options:
|
|
48
|
+
-m, --model MODEL A GraphModel instance reference {module-
|
|
49
|
+
name}:{GraphModel-instance-variable-name} For example,
|
|
50
|
+
given var `model=GraphModel()` defined in app.py file,
|
|
51
|
+
then the reference should be app:model
|
|
52
|
+
-p, --port INTEGER Port number.
|
|
53
|
+
-b, --browse / --no-browse Open web browser on start.
|
|
54
|
+
--debug / --no-debug Enable debug logging. [env var: GRAPHINATE_DEBUG]
|
|
55
|
+
--help Show this message and exit.
|
|
56
|
+
```
|
|
@@ -21,7 +21,7 @@ icon: lucide/package
|
|
|
21
21
|
|
|
22
22
|
The `GraphModel` Class which is used to declaratively register, Edge and/or Node data supplier functions.
|
|
23
23
|
Using the [`GraphModel.node()`](../reference/graphinate/modeling.md#graphinate.modeling.GraphModel.node)
|
|
24
|
-
and [`
|
|
24
|
+
and [`GraphModel.edge()`](../reference/graphinate/modeling.md#graphinate.modeling.GraphModel.edge) decorators.
|
|
25
25
|
|
|
26
26
|
### Builders
|
|
27
27
|
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "Graphinate"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.16.0"
|
|
4
4
|
description = "Graphinate. Data to Graphs."
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Eran Rivlis", email = "eran@rivlis.info" },
|
|
7
7
|
]
|
|
8
|
+
license = "LGPL-3.0-or-later"
|
|
9
|
+
license-files = ["LICENSE"]
|
|
8
10
|
readme = "README.md"
|
|
9
11
|
requires-python = ">=3.11"
|
|
10
12
|
classifiers = [
|
|
@@ -103,9 +103,9 @@ print(mermaid_string)
|
|
|
103
103
|
## 5. Gotchas & Best Practices
|
|
104
104
|
|
|
105
105
|
- **The Command Center (`graphinate.cli`)**: For quick builds or serving, use the CLI:
|
|
106
|
-
- `graphinate
|
|
107
|
-
- `graphinate
|
|
108
|
-
- **The Broadcaster (`graphinate.server`)**: The `
|
|
106
|
+
- `graphinate save --model <module:model>`
|
|
107
|
+
- `graphinate server --model <module:model>`
|
|
108
|
+
- **The Broadcaster (`graphinate.server`)**: The `server` command requires optional dependencies. If it fails, the user
|
|
109
109
|
needs to run:
|
|
110
110
|
```bash
|
|
111
111
|
pip install "graphinate[server]"
|
|
@@ -28,6 +28,7 @@ from ..converters import (
|
|
|
28
28
|
)
|
|
29
29
|
from ..enums import GraphType
|
|
30
30
|
from ..modeling import GraphModel
|
|
31
|
+
from ..tools import VariableNameManager
|
|
31
32
|
from .networkx import NetworkxBuilder
|
|
32
33
|
|
|
33
34
|
|
|
@@ -173,7 +174,7 @@ class GraphQLBuilder(NetworkxBuilder):
|
|
|
173
174
|
number_of_isolates = 'number_of_isolates'
|
|
174
175
|
number_connected_components = 'number_connected_components'
|
|
175
176
|
number_strongly_connected_components = 'number_strongly_connected_components'
|
|
176
|
-
number_weakly_connected_components = '
|
|
177
|
+
number_weakly_connected_components = 'number_weakly_connected_components'
|
|
177
178
|
number_attracting_components = 'number_attracting_components'
|
|
178
179
|
node_connectivity = 'node_connectivity'
|
|
179
180
|
transitivity = 'transitivity'
|
|
@@ -193,6 +194,7 @@ class GraphQLBuilder(NetworkxBuilder):
|
|
|
193
194
|
def __init__(self, model: GraphModel, graph_type: GraphType = GraphType.Graph):
|
|
194
195
|
super().__init__(model, graph_type)
|
|
195
196
|
self._node_value_graphql_type_supplier: Callable[[str], StrawberryType | None] | None = None
|
|
197
|
+
self._cached_graphql_types: dict[str, type[GraphQLBuilder.GraphNode]] | None = None
|
|
196
198
|
|
|
197
199
|
@staticmethod
|
|
198
200
|
def add_field_resolver(class_dict: dict, field_name: str, resolver: Callable, graphql_type: Any | None = None):
|
|
@@ -248,8 +250,9 @@ class GraphQLBuilder(NetworkxBuilder):
|
|
|
248
250
|
|
|
249
251
|
@staticmethod
|
|
250
252
|
def _graphql_enum(name: str, values: list[str]) -> EnumType:
|
|
253
|
+
name_manager = VariableNameManager()
|
|
251
254
|
return strawberry.enum(
|
|
252
|
-
Enum(name, {v: v for v in values}),
|
|
255
|
+
Enum(name, {name_manager.make_valid(v): v for v in values}),
|
|
253
256
|
name=name,
|
|
254
257
|
description=f"{name} Enumeration"
|
|
255
258
|
)
|
|
@@ -263,50 +266,56 @@ class GraphQLBuilder(NetworkxBuilder):
|
|
|
263
266
|
from strawberry.types.enum import EnumValue
|
|
264
267
|
|
|
265
268
|
types_to_populate = node_types if node_types else ['node']
|
|
269
|
+
name_manager = VariableNameManager()
|
|
270
|
+
|
|
271
|
+
self.GraphNodeType.__strawberry_definition__.values.clear()
|
|
266
272
|
|
|
267
273
|
for v in types_to_populate:
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
self.GraphNodeType.
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
274
|
+
member_name = name_manager.make_valid(v)
|
|
275
|
+
if member_name not in self.GraphNodeType._member_names_:
|
|
276
|
+
self.GraphNodeType._member_names_.append(member_name)
|
|
277
|
+
self.GraphNodeType._member_map_[member_name] = v
|
|
278
|
+
self.GraphNodeType._value2member_map_[v] = v
|
|
279
|
+
|
|
280
|
+
self.GraphNodeType.__strawberry_definition__.values.append(
|
|
281
|
+
EnumValue(
|
|
282
|
+
name=member_name,
|
|
283
|
+
value=v,
|
|
284
|
+
description=f"Graph Node Type: {v}"
|
|
279
285
|
)
|
|
280
|
-
|
|
286
|
+
)
|
|
281
287
|
|
|
282
288
|
@property
|
|
283
|
-
@functools.lru_cache
|
|
284
289
|
def _graphql_types(self) -> dict[str, type['GraphQLBuilder.GraphNode']]:
|
|
290
|
+
if self._cached_graphql_types is not None:
|
|
291
|
+
return self._cached_graphql_types
|
|
292
|
+
|
|
285
293
|
node_types = list(self._graph.graph['node_types'].keys())
|
|
286
294
|
|
|
287
295
|
self._populate_graph_node_type_enum(node_types)
|
|
288
296
|
|
|
289
|
-
def neighbors_resolver():
|
|
297
|
+
def neighbors_resolver(current_node_type: str):
|
|
290
298
|
graph = self._graph
|
|
291
299
|
|
|
292
|
-
children_types = set(self._children_types(self.model,
|
|
300
|
+
children_types = set(self._children_types(self.model, current_node_type))
|
|
293
301
|
|
|
294
302
|
def node_neighbors(self,
|
|
295
303
|
type: 'GraphQLBuilder.GraphNodeType | None' = None,
|
|
296
304
|
children: bool = False) -> list['GraphQLBuilder.GraphNode']:
|
|
297
305
|
node = decode_node_id(self.id)
|
|
298
|
-
items = (
|
|
299
|
-
|
|
300
|
-
|
|
306
|
+
items = (
|
|
307
|
+
GraphQLBuilder._graph_node(graphql_types[(d := graph.nodes[n])['type']], n, d)
|
|
308
|
+
for n in graph.neighbors(node)
|
|
309
|
+
)
|
|
301
310
|
|
|
302
311
|
if type is not None:
|
|
303
|
-
|
|
312
|
+
target_type = getattr(type, 'value', type)
|
|
313
|
+
items = (item for item in items if item.type == target_type)
|
|
304
314
|
|
|
305
315
|
if children and children_types:
|
|
306
316
|
items = (item for item in items if item.type in children_types)
|
|
307
317
|
|
|
308
|
-
|
|
309
|
-
return items
|
|
318
|
+
return list(items)
|
|
310
319
|
|
|
311
320
|
return node_neighbors
|
|
312
321
|
|
|
@@ -320,10 +329,11 @@ class GraphQLBuilder(NetworkxBuilder):
|
|
|
320
329
|
|
|
321
330
|
return node_edges
|
|
322
331
|
|
|
332
|
+
class_name_manager = VariableNameManager()
|
|
323
333
|
# Create classes for nodes according to their type
|
|
324
334
|
graphql_types: dict[str, type[GraphQLBuilder.GraphNode]] = {}
|
|
325
335
|
for node_type in node_types:
|
|
326
|
-
class_name = node_type.capitalize()
|
|
336
|
+
class_name = class_name_manager.make_valid(node_type.capitalize())
|
|
327
337
|
bases = (GraphQLBuilder.GraphNode,)
|
|
328
338
|
class_dict = {
|
|
329
339
|
'__doc__': f"A {class_name} Graph Node",
|
|
@@ -336,13 +346,14 @@ class GraphQLBuilder(NetworkxBuilder):
|
|
|
336
346
|
):
|
|
337
347
|
class_dict['value'] = list[value_graphql_type]
|
|
338
348
|
|
|
339
|
-
self.add_field_resolver(class_dict, 'neighbors', neighbors_resolver())
|
|
349
|
+
self.add_field_resolver(class_dict, 'neighbors', neighbors_resolver(node_type))
|
|
340
350
|
self.add_field_resolver(class_dict, 'edges', edges_resolver())
|
|
341
351
|
|
|
342
352
|
# noinspection PyTypeChecker
|
|
343
353
|
graphql_type: type[GraphQLBuilder.GraphNode] = type(class_name, bases, class_dict)
|
|
344
354
|
graphql_types[node_type] = GraphQLBuilder._graphql_type(node_type, graphql_type)
|
|
345
355
|
|
|
356
|
+
self._cached_graphql_types = graphql_types
|
|
346
357
|
return graphql_types
|
|
347
358
|
|
|
348
359
|
def _graphql_query(self): # noqa: C901
|
|
@@ -434,8 +445,9 @@ class GraphQLBuilder(NetworkxBuilder):
|
|
|
434
445
|
# endregion
|
|
435
446
|
|
|
436
447
|
# region - Defining GraphQL Query Class dict - fields for GraphQL types implementing 'GraphNode' interface
|
|
448
|
+
field_name_manager = VariableNameManager()
|
|
437
449
|
for node_type, graphql_type in self._graphql_types.items():
|
|
438
|
-
field_name = inflection.plural(node_type)
|
|
450
|
+
field_name = field_name_manager.make_valid(inflection.plural(node_type))
|
|
439
451
|
resolver = graph_nodes_resolver(graphql_type, node_type)
|
|
440
452
|
self.add_field_resolver(query_class_dict, field_name, resolver)
|
|
441
453
|
|
|
@@ -521,6 +533,7 @@ class GraphQLBuilder(NetworkxBuilder):
|
|
|
521
533
|
Returns:
|
|
522
534
|
Strawberry GraphQL Schema
|
|
523
535
|
"""
|
|
536
|
+
self._cached_graphql_types = None
|
|
524
537
|
super().build(**kwargs)
|
|
525
538
|
|
|
526
539
|
self._node_value_graphql_type_supplier = node_value_graphql_type_supplier
|