snapquery 0.2.4__tar.gz → 0.2.6__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 (141) hide show
  1. {snapquery-0.2.4 → snapquery-0.2.6}/.github/workflows/build.yml +1 -1
  2. {snapquery-0.2.4 → snapquery-0.2.6}/CITATION.cff +2 -3
  3. {snapquery-0.2.4 → snapquery-0.2.6}/PKG-INFO +21 -7
  4. {snapquery-0.2.4 → snapquery-0.2.6}/README.md +17 -3
  5. {snapquery-0.2.4 → snapquery-0.2.6}/pyproject.toml +2 -2
  6. snapquery-0.2.6/snapquery/__init__.py +1 -0
  7. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/github_access.py +1 -4
  8. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/pid_lookup.py +3 -1
  9. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/prefix_merger.py +3 -4
  10. snapquery-0.2.6/snapquery/query_parameterizer.py +232 -0
  11. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/query_set_cmd.py +6 -8
  12. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/endpoints.yaml +44 -17
  13. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/scholia.py +9 -5
  14. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/snapquery_core.py +37 -1
  15. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/snapquery_webserver.py +30 -8
  16. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/version.py +1 -1
  17. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/wd_page_query_extractor.py +6 -3
  18. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_cmdline.py +6 -2
  19. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_endpoints.py +36 -8
  20. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_namedqueries.py +4 -1
  21. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_pids.py +4 -1
  22. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_prefix_merger.py +12 -2
  23. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_restful_api.py +3 -0
  24. snapquery-0.2.6/tests/test_scholia.py +129 -0
  25. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_wd_query_parsing.py +22 -1
  26. snapquery-0.2.4/snapquery/__init__.py +0 -1
  27. snapquery-0.2.4/tests/action_stats.py +0 -43
  28. snapquery-0.2.4/tests/test_scholia.py +0 -246
  29. {snapquery-0.2.4 → snapquery-0.2.6}/.github/workflows/upload-to-pypi.yml +0 -0
  30. {snapquery-0.2.4 → snapquery-0.2.6}/.gitignore +0 -0
  31. {snapquery-0.2.4 → snapquery-0.2.6}/.project +0 -0
  32. {snapquery-0.2.4 → snapquery-0.2.6}/.pydevproject +0 -0
  33. {snapquery-0.2.4 → snapquery-0.2.6}/LICENSE +0 -0
  34. {snapquery-0.2.4 → snapquery-0.2.6}/docs/index.md +0 -0
  35. {snapquery-0.2.4 → snapquery-0.2.6}/mkdocs.yml +0 -0
  36. {snapquery-0.2.4 → snapquery-0.2.6}/scripts/blackisort +0 -0
  37. {snapquery-0.2.4 → snapquery-0.2.6}/scripts/doc +0 -0
  38. {snapquery-0.2.4 → snapquery-0.2.6}/scripts/fixdomain +0 -0
  39. {snapquery-0.2.4 → snapquery-0.2.6}/scripts/install +0 -0
  40. {snapquery-0.2.4 → snapquery-0.2.6}/scripts/qlv +0 -0
  41. {snapquery-0.2.4 → snapquery-0.2.6}/scripts/release +0 -0
  42. {snapquery-0.2.4 → snapquery-0.2.6}/scripts/restore_db +0 -0
  43. {snapquery-0.2.4 → snapquery-0.2.6}/scripts/test +0 -0
  44. {snapquery-0.2.4 → snapquery-0.2.6}/scripts/test_queries +0 -0
  45. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/authorization.py +0 -0
  46. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/basequeryview.py +0 -0
  47. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/ceurws.py +0 -0
  48. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/dblp.py +0 -0
  49. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/error_filter.py +0 -0
  50. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/execution.py +0 -0
  51. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/graph.py +0 -0
  52. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/models/__init__.py +0 -0
  53. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/models/person.py +0 -0
  54. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/models/sparql_components.py +0 -0
  55. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/mwlogin.py +0 -0
  56. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/namespace_stats_view.py +0 -0
  57. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/orcid.py +0 -0
  58. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/params_view.py +0 -0
  59. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/person_selector.py +0 -0
  60. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/pid.py +0 -0
  61. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/qlever.py +0 -0
  62. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/query_annotate.py +0 -0
  63. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/query_selector.py +0 -0
  64. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/query_set_tool.py +0 -0
  65. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/query_set_tool_view.py +0 -0
  66. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/resources/sparql_language.json +0 -0
  67. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/WikiProject_LSEThesisProject.wiki +0 -0
  68. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/ceur-ws.json +0 -0
  69. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/dblp.json +0 -0
  70. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/endpoints_optional.yaml +0 -0
  71. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/federated-query-examples.json +0 -0
  72. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/graphs.yaml +0 -0
  73. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/meta_query.yaml +0 -0
  74. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/orkg.json +0 -0
  75. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/qlever.json +0 -0
  76. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/qlever_performance.json +0 -0
  77. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/ceur-ws.yaml +0 -0
  78. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/dblp.yaml +0 -0
  79. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/federated-query-examples.yaml +0 -0
  80. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/hartig-eqs-2025-12-16.yaml +0 -0
  81. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/orkg.yaml +0 -0
  82. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/qlever-issues-2025-12-05.yaml +0 -0
  83. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/qlever.yaml +0 -0
  84. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/qlever_performance.yaml +0 -0
  85. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/scholia-2025-12-04.yaml +0 -0
  86. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/scholia-2025-12-16.yaml +0 -0
  87. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/scholia-qlever-2025-12-16.yaml +0 -0
  88. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/scholia.yaml +0 -0
  89. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/sib-2025-12-04.yaml +0 -0
  90. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/snapquery.yaml +0 -0
  91. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/wikidata-WikidataThesisToolkit.yaml +0 -0
  92. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/wikidata-WikidataThesisToolkitAlt.yaml +0 -0
  93. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/wikidata-examples-2025-12-04.yaml +0 -0
  94. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/wikidata-examples.yaml +0 -0
  95. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/wikidata-short-urls-2025-12-06.yaml +0 -0
  96. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query-sets/yaml/wikidata-short-urls.yaml +0 -0
  97. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/query_stats.yaml +0 -0
  98. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/scholia.json +0 -0
  99. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/snapquery.json +0 -0
  100. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/wikidata-WikidataThesisToolkit.json +0 -0
  101. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/wikidata-WikidataThesisToolkitAlt.json +0 -0
  102. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/wikidata-examples.json +0 -0
  103. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/samples/wikidata-short-urls.json +0 -0
  104. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/sib_sparql_examples.py +0 -0
  105. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/snapquery_cmd.py +0 -0
  106. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/snapquery_view.py +0 -0
  107. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/sparql_analyzer.py +0 -0
  108. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/stats_view.py +0 -0
  109. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery/wd_short_url.py +0 -0
  110. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery.puml +0 -0
  111. {snapquery-0.2.4 → snapquery-0.2.6}/snapquery.yaml +0 -0
  112. {snapquery-0.2.4 → snapquery-0.2.6}/tests/__init__.py +0 -0
  113. {snapquery-0.2.4 → snapquery-0.2.6}/tests/query_extractors/__init__.py +0 -0
  114. {snapquery-0.2.4 → snapquery-0.2.6}/tests/query_extractors/sparql_standard_queries.py +0 -0
  115. {snapquery-0.2.4 → snapquery-0.2.6}/tests/resources/error_messages/qlever/ask_unsupported.txt +0 -0
  116. {snapquery-0.2.4 → snapquery-0.2.6}/tests/resources/error_messages/qlever/invalid_literal.txt +0 -0
  117. {snapquery-0.2.4 → snapquery-0.2.6}/tests/resources/error_messages/qlever/invalid_regex_func.txt +0 -0
  118. {snapquery-0.2.4 → snapquery-0.2.6}/tests/resources/error_messages/qlever/memory_limit.txt +0 -0
  119. {snapquery-0.2.4 → snapquery-0.2.6}/tests/resources/error_messages/qlever/timeout.txt +0 -0
  120. {snapquery-0.2.4 → snapquery-0.2.6}/tests/resources/error_messages/triplydb/parser_error.txt +0 -0
  121. {snapquery-0.2.4 → snapquery-0.2.6}/tests/resources/error_messages/wdqs/duplicate_prefix.txt +0 -0
  122. {snapquery-0.2.4 → snapquery-0.2.6}/tests/resources/error_messages/wdqs/invalid_iri_declaration.txt +0 -0
  123. {snapquery-0.2.4 → snapquery-0.2.6}/tests/resources/error_messages/wdqs/invalid_sparql_syntax.txt +0 -0
  124. {snapquery-0.2.4 → snapquery-0.2.6}/tests/resources/error_messages/wdqs/timeout.txt +0 -0
  125. {snapquery-0.2.4 → snapquery-0.2.6}/tests/resources/error_messages/wdqs/undefined_prefix.txt +0 -0
  126. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_authorization.py +0 -0
  127. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_ceurws.py +0 -0
  128. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_error_filter.py +0 -0
  129. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_graph.py +0 -0
  130. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_oauth.py +0 -0
  131. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_orcid.py +0 -0
  132. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_qlever.py +0 -0
  133. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_query_annotate.py +0 -0
  134. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_query_execution.py +0 -0
  135. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_query_name.py +0 -0
  136. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_query_set_tool.py +0 -0
  137. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_scholia_q.py +0 -0
  138. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_sib_examples.py +0 -0
  139. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_sparql_analyzer.py +0 -0
  140. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_sparql_components.py +0 -0
  141. {snapquery-0.2.4 → snapquery-0.2.6}/tests/test_wd_short_url.py +0 -0
@@ -22,7 +22,7 @@ jobs:
22
22
  #python-version: [ '3.10', '3.11', '3.12', '3.13' ]
23
23
  # simplified build matrix to avoid rate limits
24
24
  os: [ubuntu-latest]
25
- python-version: ['3.11']
25
+ python-version: ['3.10']
26
26
 
27
27
  steps:
28
28
  - uses: actions/checkout@v4
@@ -29,7 +29,8 @@ authors:
29
29
  # orcid: 'https://orcid.org/0000-0003-0250-9655'
30
30
  identifiers:
31
31
  - type: doi
32
- value: 10.5281/zenodo.17802425
32
+ value: 10.5281/zenodo.17802424
33
+ description: Concept DOI (all versions) on Zenodo
33
34
  repository-code: 'https://github.com/WolfgangFahl/snapquery'
34
35
  url: 'https://snapquery.bitplan.com'
35
36
  abstract: >-
@@ -45,5 +46,3 @@ keywords:
45
46
  - Query Set
46
47
  - FAIR
47
48
  license: Apache-2.0
48
- version: v0.2.2
49
- date-released: '2025-12-03'
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: snapquery
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Summary: Just Query wikidata and other SPARQL endpoints by query name - a frontend to Introduce Named Queries and Named Query Middleware to wikidata and other SPARQL endpoints
5
5
  Project-URL: Home, https://github.com/WolfgangFahl/snapquery
6
6
  Project-URL: Documentation, https://wiki.bitplan.com/index.php/snapquery
@@ -32,8 +32,8 @@ Requires-Dist: pandas>=2.3.3
32
32
  Requires-Dist: py-3rdparty-mediawiki>=0.18.1
33
33
  Requires-Dist: py-ez-wikidata>=0.3.2
34
34
  Requires-Dist: pybasemkit>=0.1.6
35
- Requires-Dist: pylodstorage>=0.18.6
36
- Requires-Dist: pyopensourceprojects>=0.4.1
35
+ Requires-Dist: pylodstorage>=0.19.9
36
+ Requires-Dist: pyopensourceprojects>=0.5.0
37
37
  Requires-Dist: python-slugify>=8.0.4
38
38
  Requires-Dist: ratelimit>=2.2.1
39
39
  Requires-Dist: requests
@@ -65,10 +65,24 @@ The technology behind the backend knowlede graphs such as RDF, SPARQL, SQL, CSV,
65
65
  | :--- | :--- |
66
66
  | **PyPi** | [![PyPI Status](https://img.shields.io/pypi/v/snapquery.svg)](https://pypi.python.org/pypi/snapquery/) [![License](https://img.shields.io/github/license/WolfgangFahl/snapquery.svg)](https://www.apache.org/licenses/LICENSE-2.0) [![pypi](https://img.shields.io/pypi/pyversions/snapquery)](https://pypi.org/project/snapquery/) [![format](https://img.shields.io/pypi/format/snapquery)](https://pypi.org/project/snapquery/) [![downloads](https://img.shields.io/pypi/dd/snapquery)](https://pypi.org/project/snapquery/) |
67
67
  | **GitHub** | [![Github Actions Build](https://github.com/WolfgangFahl/snapquery/actions/workflows/build.yml/badge.svg)](https://github.com/WolfgangFahl/snapquery/actions/workflows/build.yml) [![Release](https://img.shields.io/github/v/release/WolfgangFahl/snapquery)](https://github.com/WolfgangFahl/snapquery/releases) [![Contributors](https://img.shields.io/github/contributors/WolfgangFahl/snapquery)](https://github.com/WolfgangFahl/snapquery/graphs/contributors) [![Last Commit](https://img.shields.io/github/last-commit/WolfgangFahl/snapquery)](https://github.com/WolfgangFahl/snapquery/commits/) [![GitHub issues](https://img.shields.io/github/issues/WolfgangFahl/snapquery.svg)](https://github.com/WolfgangFahl/snapquery/issues) [![GitHub closed issues](https://img.shields.io/github/issues-closed/WolfgangFahl/snapquery.svg)](https://github.com/WolfgangFahl/snapquery/issues/?q=is%3Aissue+is%3Aclosed) |
68
- | **Code** | [![style-black](https://img.shields.io/badge/%20style-black-000000.svg)](https://github.com/psf/black) [![imports-isort](https://img.shields.io/badge/%20imports-isort-%231674b1)](https://pycqa.github.io/isort/) |
68
+ | **Code** | [![style-black](https://img.shields.io/badge/%20style-black-000000.svg)](https://github.com/psf/black) [![imports-isort](https://img.shields.io/badge/%20imports-isort-%231674b1)](https://pycqa.github.io/isort/) [![Join the discussion at https://github.com/WolfgangFahl/snapquery/discussions](https://img.shields.io/github/discussions/WolfgangFahl/snapquery)](https://github.com/WolfgangFahl/snapquery/discussions) |
69
69
  | **Docs** | [![API Docs](https://img.shields.io/badge/API-Documentation-blue)](https://WolfgangFahl.github.io/snapquery/) [![formatter-docformatter](https://img.shields.io/badge/%20formatter-docformatter-fedcba.svg)](https://github.com/PyCQA/docformatter) [![style-google](https://img.shields.io/badge/%20style-google-3666d6.svg)](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings) |
70
- [![DOI](https://zenodo.org/badge/795424154.svg)](https://doi.org/10.5281/zenodo.17802424)
71
- [![Join the discussion at https://github.com/WolfgangFahl/snapquery/discussions](https://img.shields.io/github/discussions/WolfgangFahl/snapquery)](https://github.com/WolfgangFahl/snapquery/discussions)
70
+ | **Cite** | [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.17802424.svg)](https://doi.org/10.5281/zenodo.17802424) |
71
+
72
+ ## Cite as
73
+
74
+ If you use snapquery in your research, please cite it via its Zenodo concept DOI
75
+ (which always resolves to the latest version):
76
+
77
+ > Fahl, W., Holzheim, T., Hoyt, C. T., Priskorn, D., & Willighagen, E.
78
+ > *SnapQuery — FAIR Management of Query Sets to Mitigate Query Rot in Knowledge Graphs.*
79
+ > Zenodo. https://doi.org/10.5281/zenodo.17802424
80
+
81
+ Machine-readable metadata is available in [`CITATION.cff`](./CITATION.cff);
82
+ GitHub's "Cite this repository" button and Zenodo pick it up automatically.
83
+ For a specific release, use the version DOI shown on the corresponding
84
+ [Zenodo record](https://doi.org/10.5281/zenodo.17802424).
85
+
72
86
  ## Demos
73
87
 
74
88
  * [wikimedia toolhub](https://toolhub.wikimedia.org/tools/snapquery)
@@ -20,10 +20,24 @@ The technology behind the backend knowlede graphs such as RDF, SPARQL, SQL, CSV,
20
20
  | :--- | :--- |
21
21
  | **PyPi** | [![PyPI Status](https://img.shields.io/pypi/v/snapquery.svg)](https://pypi.python.org/pypi/snapquery/) [![License](https://img.shields.io/github/license/WolfgangFahl/snapquery.svg)](https://www.apache.org/licenses/LICENSE-2.0) [![pypi](https://img.shields.io/pypi/pyversions/snapquery)](https://pypi.org/project/snapquery/) [![format](https://img.shields.io/pypi/format/snapquery)](https://pypi.org/project/snapquery/) [![downloads](https://img.shields.io/pypi/dd/snapquery)](https://pypi.org/project/snapquery/) |
22
22
  | **GitHub** | [![Github Actions Build](https://github.com/WolfgangFahl/snapquery/actions/workflows/build.yml/badge.svg)](https://github.com/WolfgangFahl/snapquery/actions/workflows/build.yml) [![Release](https://img.shields.io/github/v/release/WolfgangFahl/snapquery)](https://github.com/WolfgangFahl/snapquery/releases) [![Contributors](https://img.shields.io/github/contributors/WolfgangFahl/snapquery)](https://github.com/WolfgangFahl/snapquery/graphs/contributors) [![Last Commit](https://img.shields.io/github/last-commit/WolfgangFahl/snapquery)](https://github.com/WolfgangFahl/snapquery/commits/) [![GitHub issues](https://img.shields.io/github/issues/WolfgangFahl/snapquery.svg)](https://github.com/WolfgangFahl/snapquery/issues) [![GitHub closed issues](https://img.shields.io/github/issues-closed/WolfgangFahl/snapquery.svg)](https://github.com/WolfgangFahl/snapquery/issues/?q=is%3Aissue+is%3Aclosed) |
23
- | **Code** | [![style-black](https://img.shields.io/badge/%20style-black-000000.svg)](https://github.com/psf/black) [![imports-isort](https://img.shields.io/badge/%20imports-isort-%231674b1)](https://pycqa.github.io/isort/) |
23
+ | **Code** | [![style-black](https://img.shields.io/badge/%20style-black-000000.svg)](https://github.com/psf/black) [![imports-isort](https://img.shields.io/badge/%20imports-isort-%231674b1)](https://pycqa.github.io/isort/) [![Join the discussion at https://github.com/WolfgangFahl/snapquery/discussions](https://img.shields.io/github/discussions/WolfgangFahl/snapquery)](https://github.com/WolfgangFahl/snapquery/discussions) |
24
24
  | **Docs** | [![API Docs](https://img.shields.io/badge/API-Documentation-blue)](https://WolfgangFahl.github.io/snapquery/) [![formatter-docformatter](https://img.shields.io/badge/%20formatter-docformatter-fedcba.svg)](https://github.com/PyCQA/docformatter) [![style-google](https://img.shields.io/badge/%20style-google-3666d6.svg)](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings) |
25
- [![DOI](https://zenodo.org/badge/795424154.svg)](https://doi.org/10.5281/zenodo.17802424)
26
- [![Join the discussion at https://github.com/WolfgangFahl/snapquery/discussions](https://img.shields.io/github/discussions/WolfgangFahl/snapquery)](https://github.com/WolfgangFahl/snapquery/discussions)
25
+ | **Cite** | [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.17802424.svg)](https://doi.org/10.5281/zenodo.17802424) |
26
+
27
+ ## Cite as
28
+
29
+ If you use snapquery in your research, please cite it via its Zenodo concept DOI
30
+ (which always resolves to the latest version):
31
+
32
+ > Fahl, W., Holzheim, T., Hoyt, C. T., Priskorn, D., & Willighagen, E.
33
+ > *SnapQuery — FAIR Management of Query Sets to Mitigate Query Rot in Knowledge Graphs.*
34
+ > Zenodo. https://doi.org/10.5281/zenodo.17802424
35
+
36
+ Machine-readable metadata is available in [`CITATION.cff`](./CITATION.cff);
37
+ GitHub's "Cite this repository" button and Zenodo pick it up automatically.
38
+ For a specific release, use the version DOI shown on the corresponding
39
+ [Zenodo record](https://doi.org/10.5281/zenodo.17802424).
40
+
27
41
  ## Demos
28
42
 
29
43
  * [wikimedia toolhub](https://toolhub.wikimedia.org/tools/snapquery)
@@ -26,7 +26,7 @@ dependencies = [
26
26
  # https://github.com/WolfgangFahl/nicegui_widgets
27
27
  "ngwidgets>=0.30.3",
28
28
  # https://pypi.org/project/pyLodStorage/
29
- "pyLodStorage>=0.18.6",
29
+ "pyLodStorage>=0.19.9",
30
30
  # https://pypi.org/project/py-3rdparty-mediawiki/
31
31
  "py-3rdparty-mediawiki>=0.18.1",
32
32
  "wikitextparser",
@@ -51,7 +51,7 @@ dependencies = [
51
51
  # https://pypi.org/project/nameparser/
52
52
  "nameparser>=1.1.3",
53
53
  # https://github.com/WolfgangFahl/pyOpenSourceProjects
54
- "pyOpenSourceProjects>=0.4.1"
54
+ "pyOpenSourceProjects>=0.5.0"
55
55
  ]
56
56
 
57
57
  requires-python = ">=3.10"
@@ -0,0 +1 @@
1
+ __version__ = "0.2.6"
@@ -23,7 +23,7 @@ class GitHub:
23
23
  repo: str,
24
24
  branch: Optional[str] = None,
25
25
  token: Optional[str] = None,
26
- session: Optional[requests.Session] = None
26
+ session: Optional[requests.Session] = None,
27
27
  ):
28
28
  """
29
29
  Initialize GitHub client.
@@ -39,7 +39,6 @@ class GitHub:
39
39
  self.repo = repo
40
40
  self.branch = branch
41
41
 
42
-
43
42
  self.base_url = f"https://api.github.com/repos/{owner}/{repo}"
44
43
 
45
44
  # Use provided token or read from file
@@ -48,7 +47,6 @@ class GitHub:
48
47
  # Use custom session or create new one
49
48
  self.session = session or requests.Session()
50
49
 
51
-
52
50
  def _headers(self) -> Dict[str, str]:
53
51
  headers = {"Accept": "application/vnd.github.v3+json"}
54
52
  if self.token:
@@ -92,7 +90,6 @@ class GitHub:
92
90
  response.raise_for_status()
93
91
  return response.json()
94
92
 
95
-
96
93
  def list_files_recursive(self, path: str = "", suffix: Optional[str] = None) -> List[Dict[str, Any]]:
97
94
  """
98
95
  Recursively list files under a given path. Optionally filter by file suffix.
@@ -32,13 +32,14 @@ class PersonLookup:
32
32
  self.wikidata_search = WikidataSearch()
33
33
  self.dblp_person_lookup = DblpPersonLookup(self.nqm)
34
34
 
35
- def suggest_from_wikidata(self, search_name: str, limit: int = 10) -> List[Person]:
35
+ def suggest_from_wikidata(self, search_name: str, limit: int = 10, endpoint_name: str = "wikidata") -> List[Person]:
36
36
  """
37
37
  Suggest persons using WikidataSearch.
38
38
 
39
39
  Args:
40
40
  search_name (str): The name to search for suggestions.
41
41
  limit (int): The maximum number of results to return.
42
+ endpoint_name (str): the endpoint to query, default wikidata.
42
43
 
43
44
  Returns:
44
45
  List[Person]: A list of suggested persons from Wikidata.
@@ -88,6 +89,7 @@ WHERE
88
89
  person_lod, stats = self.nqm.execute_query(
89
90
  named_query=named_query,
90
91
  params_dict=params_dict,
92
+ endpoint_name=endpoint_name,
91
93
  limit=limit,
92
94
  with_stats=False,
93
95
  )
@@ -78,11 +78,10 @@ class QueryPrefixMerger(Enum):
78
78
  Returns:
79
79
  merged query
80
80
  """
81
+ merged_query = query_str
81
82
  prefixes_str = endpoint.get_prefixes(PrefixConfigs.get_instance())
82
- if not prefixes_str.strip():
83
- return
84
-
85
- merged_query = Prefixes.merge_prefixes(query_str, prefixes_str)
83
+ if prefixes_str.strip():
84
+ merged_query = Prefixes.merge_prefixes(query_str, prefixes_str)
86
85
  return merged_query
87
86
 
88
87
  @classmethod
@@ -0,0 +1,232 @@
1
+ """
2
+ Created on 2025-12-16
3
+
4
+ @author: wf
5
+ """
6
+
7
+ import os
8
+ import re
9
+ import textwrap
10
+ from typing import Any, Dict, List, Optional
11
+
12
+ from lodstorage.params import Param
13
+ from lodstorage.query import Query
14
+
15
+ from snapquery.snapquery_core import NamedQuery, NamedQuerySet
16
+
17
+
18
+ class QueryParameterizer:
19
+ """
20
+ Parameterizer for Scholia Query Sets.
21
+ Transforms Jinja2-based Scholia templates into standard
22
+ LoDStorage Parameterized Queries.
23
+ """
24
+
25
+ # Replacement for Scholia's label macro
26
+ LABEL_SERVICE = 'SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }'
27
+
28
+ # Defaults for specific Scholia Aspects
29
+ # derived from the prompt list
30
+ ASPECT_DEFAULTS = {
31
+ "author": "Q80", # Tim Berners-Lee
32
+ "authors": "Q80",
33
+ "award": "Q616568", # Turing Award
34
+ "catalogue": "Q2463660", # British Library catalogue
35
+ "chemical": "Q18216", # Aspirin
36
+ "cito": "Q1054942", # citation intent
37
+ "clinical": "Q12136", # Common Cold (disease context)
38
+ "complex": "Q417724", # Protein complex
39
+ "countries": "Q183", # Germany
40
+ "country": "Q183",
41
+ "dataset": "Q1172284", # Data set
42
+ "disease": "Q12136", # Common Cold
43
+ "event": "Q2020153", # WWW Conference
44
+ "gene": "Q7191", # p53
45
+ "index": "Q1", # Universe (generic fallback)
46
+ "language": "Q1860", # English
47
+ "lexeme": "Q151326", # Word
48
+ "license": "Q20007257", # CC BY 4.0
49
+ "location": "Q64", # Berlin
50
+ "ontology": "Q324254", # Ontology
51
+ "organization": "Q95", # Google
52
+ "organizations": "Q95",
53
+ "pathway": "Q26487", # Metabolic pathway
54
+ "podcast": "Q24634210", # The Ozymandias Project
55
+ "printer": "Q11226", # Printer (the device/person)
56
+ "project": "Q5562725", # WikiProject
57
+ "property": "P31", # Instance of
58
+ "protein": "Q11060", # Green fluorescent protein
59
+ "publisher": "Q203019", # Elsevier
60
+ "retraction": "Q45263695", # Retracted paper example
61
+ "series": "Q245209", # Book series
62
+ "software": "Q28865", # Python
63
+ "sponsor": "Q95", # Google
64
+ "taxon": "Q140", # Lion
65
+ "topic": "Q21198", # Computer Science
66
+ "topics": "Q21198",
67
+ "use": "Q1",
68
+ "uses": "Q1",
69
+ "venue": "Q180445", # Nature (Journal)
70
+ "venues": "Q180445",
71
+ "wikiproject": "Q5562725",
72
+ "work": "Q13442814", # Scientific Article
73
+ "works": "Q13442814",
74
+ }
75
+
76
+ def __init__(self, debug: bool = False):
77
+ self.debug = debug
78
+
79
+ def _infer_param_details(self, var_name: str, aspect: Optional[str] = None) -> Dict[str, Any]:
80
+ """
81
+ Heuristics to determine type and default value based on variable name
82
+ and the query aspect (category).
83
+
84
+ Args:
85
+ var_name: The variable name found in the jinja template (e.g. 'q', 'target').
86
+ aspect: The scholia aspect derived from the query name (e.g. 'venue', 'author').
87
+ """
88
+ # Global Default
89
+ details = {"type": "string", "default": "Q80"}
90
+
91
+ # 1. Identify Type based on variable name
92
+ if var_name in ["q", "target", "item", "person", "work", "venue", "gene", "disease"]:
93
+ details["type"] = "WikidataItem"
94
+
95
+ # 2. Assign Default Value based on Aspect
96
+ if aspect and aspect in self.ASPECT_DEFAULTS:
97
+ details["default"] = self.ASPECT_DEFAULTS[aspect]
98
+
99
+ # 3. Fallback defaults if aspect is missing or generic
100
+ elif var_name == "person":
101
+ details["default"] = "Q80" # Tim Berners-Lee
102
+ elif var_name == "work":
103
+ details["default"] = "Q13442814"
104
+ else:
105
+ details["default"] = "Q80"
106
+
107
+ elif var_name in ["p", "property"]:
108
+ details["type"] = "WikidataProperty"
109
+ details["default"] = "P31"
110
+ elif var_name in ["limit"]:
111
+ details["type"] = "int"
112
+ details["default"] = 10
113
+ elif var_name in ["lang", "language"]:
114
+ details["type"] = "string"
115
+ details["default"] = "en"
116
+
117
+ return details
118
+
119
+ def get_queries_by_aspect(self, query_list: List[Query]) -> Dict[str, List[Query]]:
120
+ """
121
+ get queries by aspect
122
+ """
123
+ queries_by_aspect = {}
124
+ for query in query_list:
125
+ aspect = self.get_aspect(query.name)
126
+ if aspect in self.ASPECT_DEFAULTS:
127
+ if aspect not in queries_by_aspect:
128
+ queries_by_aspect[aspect] = []
129
+ queries_by_aspect[aspect].append(query)
130
+ return queries_by_aspect
131
+
132
+ def store_query_list(self, query_list: List[Query], tag: str, path: str = "/tmp/queries"):
133
+ """
134
+ Store query list sorted by aspect into separate YAML files.
135
+
136
+ Args:
137
+ query_list (List[Query]): List of Query objects with aspect metadata.
138
+ tag (str): Tag to include in filename.
139
+ path (str): Directory path where YAML files will be stored.
140
+ """
141
+ queries_by_aspect = self.get_queries_by_aspect(query_list)
142
+ # Create directory if it doesn't exist
143
+ os.makedirs(path, exist_ok=True)
144
+
145
+ # Store each aspect's queries in a separate YAML file
146
+ for aspect, queries in sorted(queries_by_aspect.items()):
147
+ filename = f"{tag}_{aspect}_queries.yaml"
148
+ filepath = os.path.join(path, filename)
149
+
150
+ with open(filepath, "w", encoding="utf-8") as f:
151
+ for query in queries:
152
+ # work around https://github.com/yaml/pyyaml/issues/411
153
+ if query.sparql:
154
+ clean_sparql = textwrap.dedent(query.sparql).strip()
155
+ yaml_str = query.to_yaml()
156
+ f.write(yaml_str)
157
+ pass
158
+
159
+ def parameterize_query_set(self, query_set: NamedQuerySet) -> List[Query]:
160
+ """
161
+ Parameterize the given query set to produce a list of LoDStorage queries.
162
+
163
+ Args:
164
+ query_set (NamedQuerySet): The set of named queries to transform.
165
+
166
+ Returns:
167
+ List[Query]: A list of transformed LoDStorage Query objects.
168
+ """
169
+ query_list = []
170
+ for nq in query_set.queries:
171
+ query = self.parameterize_query(nq)
172
+ query_list.append(query)
173
+ return query_list
174
+
175
+ def get_aspect(self, name: str) -> str:
176
+ aspect = None
177
+ if name:
178
+ # Split by hyphen first, as that is the standard separator in the example
179
+ parts = re.split(r"[-_]", name)
180
+ if parts:
181
+ aspect = parts[0].lower()
182
+ return aspect
183
+
184
+ def parameterize_query(self, nq: NamedQuery) -> Query:
185
+ """
186
+ Parameterize a single named query.
187
+
188
+ 1. Identifies the "Aspect" from the query name (e.g. 'venue-...' -> 'venue').
189
+ 2. Cleans Jinja2 specific imports.
190
+ 3. Replaces Scholia Macros with standard SPARQL.
191
+ 4. Detects variables and creates Param objects using aspect-specific defaults.
192
+
193
+ Args:
194
+ nq (NamedQuery): The named query input.
195
+
196
+ Returns:
197
+ Query: The transformed LoDStorage Query object.
198
+ """
199
+ # 0. Determine Aspect
200
+ # Naming convention: {aspect}-{subname} or {aspect}_{subname}
201
+ # e.g., "venue-curation_missing-author-item" -> "venue"
202
+ aspect = self.get_aspect(nq.name)
203
+
204
+ raw_sparql = nq.sparql
205
+
206
+ # 1. Remove Jinja imports
207
+ # e.g., {% import 'sparql-helpers.sparql' as sparql_helpers -%}
208
+ txt = re.sub(r"\{%\s*import\s*.*?%\}", "", raw_sparql, flags=re.DOTALL)
209
+
210
+ # 2. Replace Label/Description Macros
211
+ # Matches: {{ sparql_helpers.labels(["?mol"], languages) }}
212
+ txt = re.sub(r"\{\{\s*sparql_helpers\.(labels|descriptions).*?\}\}", self.LABEL_SERVICE, txt, flags=re.DOTALL)
213
+
214
+ # 3. Detect Variables to build Param list
215
+ found_vars = set(re.findall(r"\{\{\s*([a-zA-Z0-9_]+)\s*\}\}", txt))
216
+ found_vars.discard("sparql_helpers")
217
+
218
+ # Create lodstorage Query object
219
+ clean_sparql = txt.strip()
220
+
221
+ query_obj = Query(name=nq.name, query=clean_sparql, title=nq.title, description=nq.description, lang="sparql")
222
+
223
+ # 4. Attach Parameters with Aspect context
224
+ param_list = []
225
+ for var in sorted(found_vars):
226
+ details = self._infer_param_details(var, aspect=aspect)
227
+ p = Param(name=var, type=details["type"], default_value=details["default"])
228
+ param_list.append(p)
229
+
230
+ query_obj.param_list = param_list
231
+
232
+ return query_obj
@@ -4,19 +4,20 @@ Created on 2025-12-04
4
4
  @author: wf
5
5
  """
6
6
 
7
- from argparse import ArgumentParser, Namespace
8
7
  import sys
8
+ from argparse import ArgumentParser, Namespace
9
9
 
10
10
  from basemkit.base_cmd import BaseCmd
11
+ from tqdm import tqdm
12
+
11
13
  from snapquery.qlever import QLever
12
14
  from snapquery.query_set_tool import QuerySetTool
13
- from snapquery.scholia import ScholiaQueries, GitHubQueries
15
+ from snapquery.scholia import GitHubQueries, ScholiaQueries
14
16
  from snapquery.sib_sparql_examples import SibSparqlExamples
15
17
  from snapquery.snapquery_core import NamedQueryManager
16
18
  from snapquery.version import Version
17
19
  from snapquery.wd_page_query_extractor import WikidataQueryExtractor
18
20
  from snapquery.wd_short_url import ShortUrl
19
- from tqdm import tqdm
20
21
 
21
22
 
22
23
  class QuerySetCmdVersion(Version):
@@ -214,7 +215,6 @@ class QuerySetCmd(BaseCmd):
214
215
  self._handle_random_short_urls(args)
215
216
  return True
216
217
 
217
-
218
218
  return False
219
219
 
220
220
  def _handle_convert(self, args: Namespace) -> None:
@@ -263,13 +263,12 @@ class QuerySetCmd(BaseCmd):
263
263
  extension=args.github_extension,
264
264
  domain=args.domain,
265
265
  namespace=args.namespace,
266
- debug=args.debug
266
+ debug=args.debug,
267
267
  )
268
268
 
269
269
  gh_queries.extract_queries(limit=args.limit, show_progress=args.progress)
270
270
  self._output_dataset(gh_queries.named_query_set, args)
271
271
 
272
-
273
272
  def _handle_scholia(self, args: Namespace) -> None:
274
273
  """
275
274
  Handle the standard Scholia import workflow using defaults.
@@ -292,12 +291,11 @@ class QuerySetCmd(BaseCmd):
292
291
  repo="scholia",
293
292
  branch="qlever",
294
293
  namespace="named_queries_qlever",
295
- debug=args.debug
294
+ debug=args.debug,
296
295
  )
297
296
  scholia_qlever.extract_queries(limit=args.limit, show_progress=args.progress)
298
297
  self._output_dataset(scholia_qlever.named_query_set, args)
299
298
 
300
-
301
299
  def _handle_wikidata_examples(self, args: Namespace) -> None:
302
300
  """
303
301
  Handle the Wikidata Examples import workflow.
@@ -4,23 +4,9 @@
4
4
  endpoints:
5
5
  wikidata:
6
6
  description: |
7
- Wikimedia Wikidata Query Service (legacy full).
8
- Stable but high-load; prefer -main/-scholarly.
9
- lang: sparql
10
- endpoint: https://query.wikidata.org/sparql
11
- website: https://query.wikidata.org
12
- database: blazegraph
13
- method: POST
14
- calls_per_minute: 30
15
- auto_update: true
16
- data_seeded: 2012-10-29
17
- uptime_days: 4500
18
- mtriples: 22000
19
- prefix_sets:
20
- - rdf
21
- - wikidata
22
- - blazegraph
23
- - commons
7
+ abstract name of the Wikidata endpoint, an alias resolved to a concrete entry;
8
+ a host redirects it in ~/.pylodstorage/endpoints.yaml, e.g. to a local copy
9
+ alias: wikidata-main
24
10
 
25
11
  wikidata-main:
26
12
  description: WDQS Graph Split — main (non-scholarly).
@@ -89,6 +75,30 @@ endpoints:
89
75
  - wikidata
90
76
  - commons
91
77
 
78
+ wikidata-next:
79
+ description: Wikimedia QLever Wikidata full graph (query-next).
80
+ lang: sparql
81
+ method: POST
82
+ database: qlever
83
+ endpoint: https://query-next.wikidata.org/sparql
84
+ website: https://query-next.wikidata.org/
85
+ calls_per_minute: 60
86
+ prefix_sets:
87
+ - rdf
88
+ - wikidata
89
+
90
+ wikidata-scholarly-next:
91
+ description: Wikimedia QLever Wikidata scholarly graph (query-scholarly-next).
92
+ lang: sparql
93
+ method: POST
94
+ database: qlever
95
+ endpoint: https://query-scholarly-next.wikidata.org/sparql
96
+ website: https://query-scholarly-next.wikidata.org/
97
+ calls_per_minute: 60
98
+ prefix_sets:
99
+ - rdf
100
+ - wikidata
101
+
92
102
  wikidata-triply:
93
103
  description: TriplyDB mirror.
94
104
  lang: sparql
@@ -113,6 +123,23 @@ endpoints:
113
123
  - rdf
114
124
  - wikidata
115
125
 
126
+ wikidata-openlink:
127
+ description: |
128
+ OpenLink Wikidata Truthy instance (LOD Cloud demo).
129
+ Optimized for property path queries and transitive closure.
130
+ https://www.openlinksw.com/data/html/about-wikidata-truthy-2025-11.html
131
+ lang: sparql
132
+ endpoint: https://truthy.demo.openlinksw.com/sparql
133
+ website: https://truthy.demo.openlinksw.com
134
+ database: virtuoso
135
+ method: POST
136
+ calls_per_minute: 30
137
+ data_seeded: 2025-11-01
138
+ prefix_sets:
139
+ - rdf
140
+ - wikidata
141
+ - commons
142
+
116
143
  dblp:
117
144
  description: DBLP official (qlever - reliable).
118
145
  lang: sparql
@@ -5,13 +5,16 @@ Created on 2024-05-04
5
5
 
6
6
  @author: wf
7
7
  """
8
+
9
+ from typing import Optional
10
+
8
11
  import requests
9
12
  from tqdm import tqdm
10
- from typing import Optional
11
13
 
12
14
  from snapquery.github_access import GitHub
13
15
  from snapquery.snapquery_core import NamedQuery, NamedQueryManager, NamedQuerySet
14
16
 
17
+
15
18
  class GitHubQueries:
16
19
  """
17
20
  A general class to handle the extraction and management of queries
@@ -29,7 +32,7 @@ class GitHubQueries:
29
32
  domain: Optional[str] = None,
30
33
  namespace: Optional[str] = None,
31
34
  target_graph: str = "wikidata",
32
- debug: bool = False
35
+ debug: bool = False,
33
36
  ):
34
37
  """
35
38
  Constructor
@@ -138,6 +141,7 @@ class ScholiaQueries(GitHubQueries):
138
141
  """
139
142
  Specific implementation for Scholia Queries with configurable repo/owner/branch.
140
143
  """
144
+
141
145
  def __init__(
142
146
  self,
143
147
  nqm: NamedQueryManager,
@@ -146,7 +150,7 @@ class ScholiaQueries(GitHubQueries):
146
150
  branch: Optional[str] = None,
147
151
  domain: str = "scholia.toolforge.org",
148
152
  namespace: str = "named_queries",
149
- debug: bool = False
153
+ debug: bool = False,
150
154
  ):
151
155
  super().__init__(
152
156
  nqm=nqm,
@@ -157,5 +161,5 @@ class ScholiaQueries(GitHubQueries):
157
161
  extension=".sparql",
158
162
  domain=domain,
159
163
  namespace=namespace,
160
- debug=debug
161
- )
164
+ debug=debug,
165
+ )