weave-python 0.27.0__tar.gz → 0.28.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.
Files changed (136) hide show
  1. {weave_python-0.27.0 → weave_python-0.28.0}/.github/workflows/generate.yaml +8 -6
  2. {weave_python-0.27.0 → weave_python-0.28.0}/.gitignore +4 -0
  3. {weave_python-0.27.0 → weave_python-0.28.0}/PKG-INFO +1 -1
  4. weave_python-0.28.0/tools/sqlcgen/README.md +106 -0
  5. weave_python-0.28.0/tools/sqlcgen/sqlcgen.py +147 -0
  6. weave_python-0.28.0/tools/sqlcgen/test_sqlcgen.py +280 -0
  7. {weave_python-0.27.0 → weave_python-0.28.0}/uv.lock +8 -8
  8. weave_python-0.28.0/weave/weaveapi/llmx/v1/architecture_pb2.py +74 -0
  9. weave_python-0.28.0/weave/weaveapi/llmx/v1/architecture_pb2.pyi +1323 -0
  10. weave_python-0.28.0/weave/weaveapi/llmx/v1/capabilities_pb2.py +88 -0
  11. weave_python-0.28.0/weave/weaveapi/llmx/v1/capabilities_pb2.pyi +1613 -0
  12. weave_python-0.28.0/weave/weaveapi/llmx/v1/model_pb2.py +54 -0
  13. {weave_python-0.27.0/weave/weaveapi/modex → weave_python-0.28.0/weave/weaveapi/llmx}/v1/model_pb2.pyi +294 -189
  14. weave_python-0.28.0/weave/weaveapi/llmx/v1/pricing_pb2.py +54 -0
  15. weave_python-0.28.0/weave/weaveapi/llmx/v1/pricing_pb2.pyi +597 -0
  16. weave_python-0.28.0/weave/weaveapi/llmx/v1/provider_pb2.py +38 -0
  17. {weave_python-0.27.0/weave/weaveapi/modex → weave_python-0.28.0/weave/weaveapi/llmx}/v1/provider_pb2.pyi +31 -19
  18. weave_python-0.28.0/weave/weaveapi/llmx/v1/service_pb2.py +180 -0
  19. {weave_python-0.27.0/weave/weaveapi/modex → weave_python-0.28.0/weave/weaveapi/llmx}/v1/service_pb2.pyi +174 -44
  20. {weave_python-0.27.0/weave/weaveapi/modex → weave_python-0.28.0/weave/weaveapi/llmx}/v1/service_pb2_grpc.py +103 -105
  21. weave_python-0.28.0/weave/weaveapi/llmx/v1/service_pb2_grpc.pyi +266 -0
  22. weave_python-0.28.0/weave/weaveapi/synthesize/v1/inline_data_pb2_grpc.py +2 -0
  23. weave_python-0.28.0/weave/weaveapi/synthesize/v1/inline_data_pb2_grpc.pyi +20 -0
  24. weave_python-0.28.0/weave/weaveapi/synthesize/v1/relationship_pb2_grpc.py +2 -0
  25. weave_python-0.28.0/weave/weaveapi/synthesize/v1/relationship_pb2_grpc.pyi +20 -0
  26. weave_python-0.28.0/weave/weaveapi/synthesize/v1/training_pb2_grpc.py +2 -0
  27. weave_python-0.28.0/weave/weaveapi/synthesize/v1/training_pb2_grpc.pyi +20 -0
  28. weave_python-0.27.0/sqlc.yaml +0 -19
  29. weave_python-0.27.0/weave/weaveapi/modex/v1/model_pb2.py +0 -58
  30. weave_python-0.27.0/weave/weaveapi/modex/v1/provider_pb2.py +0 -38
  31. weave_python-0.27.0/weave/weaveapi/modex/v1/service_pb2.py +0 -180
  32. weave_python-0.27.0/weave/weaveapi/modex/v1/service_pb2_grpc.pyi +0 -268
  33. weave_python-0.27.0/weave/weavesql/weavedb/models.py +0 -124
  34. weave_python-0.27.0/weave/weavesql/weavedb/queries.py +0 -306
  35. {weave_python-0.27.0 → weave_python-0.28.0}/.github/workflows/format-lint.yaml +0 -0
  36. {weave_python-0.27.0 → weave_python-0.28.0}/.github/workflows/release.yaml +0 -0
  37. {weave_python-0.27.0 → weave_python-0.28.0}/.python-version +0 -0
  38. {weave_python-0.27.0 → weave_python-0.28.0}/buf.gen.yaml +0 -0
  39. {weave_python-0.27.0 → weave_python-0.28.0}/pyproject.toml +0 -0
  40. {weave_python-0.27.0 → weave_python-0.28.0}/renovate.json +0 -0
  41. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/service_pb2.py +0 -0
  42. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/service_pb2.pyi +0 -0
  43. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/service_pb2_grpc.py +0 -0
  44. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/service_pb2_grpc.pyi +0 -0
  45. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/session_pb2.py +0 -0
  46. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/session_pb2.pyi +0 -0
  47. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/session_pb2_grpc.py +0 -0
  48. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/session_pb2_grpc.pyi +0 -0
  49. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/usage_pb2.py +0 -0
  50. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/usage_pb2.pyi +0 -0
  51. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/usage_pb2_grpc.py +0 -0
  52. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/usage_pb2_grpc.pyi +0 -0
  53. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/user_pb2.py +0 -0
  54. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/user_pb2.pyi +0 -0
  55. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/user_pb2_grpc.py +0 -0
  56. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/auth/v1/user_pb2_grpc.pyi +0 -0
  57. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/generate/v1/configuration_pb2.py +0 -0
  58. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/generate/v1/configuration_pb2.pyi +0 -0
  59. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/generate/v1/configuration_pb2_grpc.py +0 -0
  60. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/generate/v1/configuration_pb2_grpc.pyi +0 -0
  61. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/generate/v1/generate_pb2.py +0 -0
  62. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/generate/v1/generate_pb2.pyi +0 -0
  63. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/generate/v1/generate_pb2_grpc.py +0 -0
  64. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/generate/v1/generate_pb2_grpc.pyi +0 -0
  65. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/generate/v1/service_pb2.py +0 -0
  66. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/generate/v1/service_pb2.pyi +0 -0
  67. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/generate/v1/service_pb2_grpc.py +0 -0
  68. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/generate/v1/service_pb2_grpc.pyi +0 -0
  69. /weave_python-0.27.0/weave/weaveapi/mcpregistry/v1/server_pb2_grpc.py → /weave_python-0.28.0/weave/weaveapi/llmx/v1/architecture_pb2_grpc.py +0 -0
  70. /weave_python-0.27.0/weave/weaveapi/mcpregistry/v1/server_pb2_grpc.pyi → /weave_python-0.28.0/weave/weaveapi/llmx/v1/architecture_pb2_grpc.pyi +0 -0
  71. /weave_python-0.27.0/weave/weaveapi/modex/v1/model_pb2_grpc.py → /weave_python-0.28.0/weave/weaveapi/llmx/v1/capabilities_pb2_grpc.py +0 -0
  72. /weave_python-0.27.0/weave/weaveapi/modex/v1/model_pb2_grpc.pyi → /weave_python-0.28.0/weave/weaveapi/llmx/v1/capabilities_pb2_grpc.pyi +0 -0
  73. /weave_python-0.27.0/weave/weaveapi/modex/v1/provider_pb2_grpc.py → /weave_python-0.28.0/weave/weaveapi/llmx/v1/model_pb2_grpc.py +0 -0
  74. /weave_python-0.27.0/weave/weaveapi/modex/v1/provider_pb2_grpc.pyi → /weave_python-0.28.0/weave/weaveapi/llmx/v1/model_pb2_grpc.pyi +0 -0
  75. /weave_python-0.27.0/weave/weaveapi/payment/v1/invoice_pb2_grpc.py → /weave_python-0.28.0/weave/weaveapi/llmx/v1/pricing_pb2_grpc.py +0 -0
  76. /weave_python-0.27.0/weave/weaveapi/payment/v1/invoice_pb2_grpc.pyi → /weave_python-0.28.0/weave/weaveapi/llmx/v1/pricing_pb2_grpc.pyi +0 -0
  77. /weave_python-0.27.0/weave/weaveapi/payment/v1/subscription_pb2_grpc.py → /weave_python-0.28.0/weave/weaveapi/llmx/v1/provider_pb2_grpc.py +0 -0
  78. /weave_python-0.27.0/weave/weaveapi/payment/v1/subscription_pb2_grpc.pyi → /weave_python-0.28.0/weave/weaveapi/llmx/v1/provider_pb2_grpc.pyi +0 -0
  79. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/mcpregistry/v1/server_pb2.py +0 -0
  80. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/mcpregistry/v1/server_pb2.pyi +0 -0
  81. /weave_python-0.27.0/weave/weaveapi/storage/v1/auth_pb2_grpc.py → /weave_python-0.28.0/weave/weaveapi/mcpregistry/v1/server_pb2_grpc.py +0 -0
  82. /weave_python-0.27.0/weave/weaveapi/storage/v1/auth_pb2_grpc.pyi → /weave_python-0.28.0/weave/weaveapi/mcpregistry/v1/server_pb2_grpc.pyi +0 -0
  83. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/mcpregistry/v1/service_pb2.py +0 -0
  84. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/mcpregistry/v1/service_pb2.pyi +0 -0
  85. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/mcpregistry/v1/service_pb2_grpc.py +0 -0
  86. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/mcpregistry/v1/service_pb2_grpc.pyi +0 -0
  87. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/payment/v1/invoice_pb2.py +0 -0
  88. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/payment/v1/invoice_pb2.pyi +0 -0
  89. /weave_python-0.27.0/weave/weaveapi/storage/v1/nosql_database_pb2_grpc.py → /weave_python-0.28.0/weave/weaveapi/payment/v1/invoice_pb2_grpc.py +0 -0
  90. /weave_python-0.27.0/weave/weaveapi/storage/v1/nosql_database_pb2_grpc.pyi → /weave_python-0.28.0/weave/weaveapi/payment/v1/invoice_pb2_grpc.pyi +0 -0
  91. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/payment/v1/service_pb2.py +0 -0
  92. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/payment/v1/service_pb2.pyi +0 -0
  93. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/payment/v1/service_pb2_grpc.py +0 -0
  94. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/payment/v1/service_pb2_grpc.pyi +0 -0
  95. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/payment/v1/subscription_pb2.py +0 -0
  96. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/payment/v1/subscription_pb2.pyi +0 -0
  97. /weave_python-0.27.0/weave/weaveapi/storage/v1/object_store_pb2_grpc.py → /weave_python-0.28.0/weave/weaveapi/payment/v1/subscription_pb2_grpc.py +0 -0
  98. /weave_python-0.27.0/weave/weaveapi/storage/v1/object_store_pb2_grpc.pyi → /weave_python-0.28.0/weave/weaveapi/payment/v1/subscription_pb2_grpc.pyi +0 -0
  99. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/storage/v1/auth_pb2.py +0 -0
  100. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/storage/v1/auth_pb2.pyi +0 -0
  101. /weave_python-0.27.0/weave/weaveapi/storage/v1/sql_database_pb2_grpc.py → /weave_python-0.28.0/weave/weaveapi/storage/v1/auth_pb2_grpc.py +0 -0
  102. /weave_python-0.27.0/weave/weaveapi/storage/v1/sql_database_pb2_grpc.pyi → /weave_python-0.28.0/weave/weaveapi/storage/v1/auth_pb2_grpc.pyi +0 -0
  103. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/storage/v1/nosql_database_pb2.py +0 -0
  104. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/storage/v1/nosql_database_pb2.pyi +0 -0
  105. /weave_python-0.27.0/weave/weaveapi/storage/v1/storage_pb2_grpc.py → /weave_python-0.28.0/weave/weaveapi/storage/v1/nosql_database_pb2_grpc.py +0 -0
  106. /weave_python-0.27.0/weave/weaveapi/storage/v1/storage_pb2_grpc.pyi → /weave_python-0.28.0/weave/weaveapi/storage/v1/nosql_database_pb2_grpc.pyi +0 -0
  107. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/storage/v1/object_store_pb2.py +0 -0
  108. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/storage/v1/object_store_pb2.pyi +0 -0
  109. /weave_python-0.27.0/weave/weaveapi/synthesize/v1/dataset_pb2_grpc.py → /weave_python-0.28.0/weave/weaveapi/storage/v1/object_store_pb2_grpc.py +0 -0
  110. /weave_python-0.27.0/weave/weaveapi/synthesize/v1/dataset_pb2_grpc.pyi → /weave_python-0.28.0/weave/weaveapi/storage/v1/object_store_pb2_grpc.pyi +0 -0
  111. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/storage/v1/service_pb2.py +0 -0
  112. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/storage/v1/service_pb2.pyi +0 -0
  113. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/storage/v1/service_pb2_grpc.py +0 -0
  114. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/storage/v1/service_pb2_grpc.pyi +0 -0
  115. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/storage/v1/sql_database_pb2.py +0 -0
  116. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/storage/v1/sql_database_pb2.pyi +0 -0
  117. /weave_python-0.27.0/weave/weaveapi/synthesize/v1/inline_data_pb2_grpc.py → /weave_python-0.28.0/weave/weaveapi/storage/v1/sql_database_pb2_grpc.py +0 -0
  118. /weave_python-0.27.0/weave/weaveapi/synthesize/v1/inline_data_pb2_grpc.pyi → /weave_python-0.28.0/weave/weaveapi/storage/v1/sql_database_pb2_grpc.pyi +0 -0
  119. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/storage/v1/storage_pb2.py +0 -0
  120. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/storage/v1/storage_pb2.pyi +0 -0
  121. /weave_python-0.27.0/weave/weaveapi/synthesize/v1/relationship_pb2_grpc.py → /weave_python-0.28.0/weave/weaveapi/storage/v1/storage_pb2_grpc.py +0 -0
  122. /weave_python-0.27.0/weave/weaveapi/synthesize/v1/relationship_pb2_grpc.pyi → /weave_python-0.28.0/weave/weaveapi/storage/v1/storage_pb2_grpc.pyi +0 -0
  123. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/synthesize/v1/dataset_pb2.py +0 -0
  124. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/synthesize/v1/dataset_pb2.pyi +0 -0
  125. /weave_python-0.27.0/weave/weaveapi/synthesize/v1/training_pb2_grpc.py → /weave_python-0.28.0/weave/weaveapi/synthesize/v1/dataset_pb2_grpc.py +0 -0
  126. /weave_python-0.27.0/weave/weaveapi/synthesize/v1/training_pb2_grpc.pyi → /weave_python-0.28.0/weave/weaveapi/synthesize/v1/dataset_pb2_grpc.pyi +0 -0
  127. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/synthesize/v1/inline_data_pb2.py +0 -0
  128. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/synthesize/v1/inline_data_pb2.pyi +0 -0
  129. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/synthesize/v1/relationship_pb2.py +0 -0
  130. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/synthesize/v1/relationship_pb2.pyi +0 -0
  131. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/synthesize/v1/service_pb2.py +0 -0
  132. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/synthesize/v1/service_pb2.pyi +0 -0
  133. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/synthesize/v1/service_pb2_grpc.py +0 -0
  134. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/synthesize/v1/service_pb2_grpc.pyi +0 -0
  135. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/synthesize/v1/training_pb2.py +0 -0
  136. {weave_python-0.27.0 → weave_python-0.28.0}/weave/weaveapi/synthesize/v1/training_pb2.pyi +0 -0
@@ -53,7 +53,6 @@ jobs:
53
53
  with:
54
54
  cache-dependency-glob: "uv.lock"
55
55
  enable-cache: true
56
- pyproject-file: pyproject.toml
57
56
 
58
57
  - name: Clear out gen previous api gen files
59
58
  uses: weave-labs/ci/.github/actions/clean-generated-output-dir@main
@@ -65,15 +64,18 @@ jobs:
65
64
  with:
66
65
  working-directory: "weave/weavesql"
67
66
 
68
- - name: Generate sql schema
69
- run: sqlc generate
67
+ # disabled until sqlc supports copyfrom command for python
68
+ # https://github.com/sqlc-dev/sqlc-gen-python/pull/92
69
+ #
70
+ # - name: Generate sqlc configuration
71
+ # run: python3 tools/sqlcgen/sqlcgen.py --schema schema/weavesql
72
+ #
73
+ # - name: Generate sql schema
74
+ # run: sqlc generate
70
75
 
71
76
  - name: Generate proto schema
72
77
  run: buf generate
73
78
 
74
- - name: Remove schema directory
75
- run: rm -rf schema
76
-
77
79
  - name: Run uv sync
78
80
  run: uv sync
79
81
 
@@ -328,3 +328,7 @@ cython_debug/
328
328
  # option (not recommended) you can uncomment the following to ignore the entire idea folder.
329
329
  #.idea/
330
330
 
331
+ ### Custom
332
+
333
+ schema/
334
+ sqlc.yaml
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: weave-python
3
- Version: 0.27.0
3
+ Version: 0.28.0
4
4
  Requires-Python: >=3.10
5
5
  Requires-Dist: protobuf>=6.30.2
6
6
  Requires-Dist: sqlalchemy>=2.0.40
@@ -0,0 +1,106 @@
1
+ # sqlcgen - SQLC Configuration Generator for Python
2
+
3
+ This tool automatically generates `sqlc.yaml` configuration for Python projects based on directories found in the
4
+ schema/weavesql directory.
5
+
6
+ ## Usage
7
+
8
+ From the `weave-python` directory:
9
+
10
+ ```bash
11
+ python tools/sqlcgen/sqlcgen.py [options]
12
+ ```
13
+
14
+ ### Options
15
+
16
+ - `--schema`: Path to schema directory containing database folders (default: "schema/weavesql")
17
+ - `--output`: Output file path for generated sqlc.yaml (default: "sqlc.yaml")
18
+
19
+ ### Examples
20
+
21
+ Generate configuration:
22
+
23
+ ```bash
24
+ python tools/sqlcgen/sqlcgen.py
25
+ ```
26
+
27
+ Use custom schema directory:
28
+
29
+ ```bash
30
+ python tools/sqlcgen/sqlcgen.py --schema ../custom/schema --output custom-sqlc.yaml
31
+ ```
32
+
33
+ ## How it Works
34
+
35
+ 1. Scans the schema directory for subdirectories
36
+ 2. For each subdirectory that contains both `migrations/` and `queries/` folders:
37
+ - Creates an SQLC configuration entry
38
+ - Sets the package name as `{dirname}db` (e.g., `weave` → `weavedb`)
39
+ - Sets the output directory as `weave/weavesql/{package}`
40
+ 3. Generates a complete `sqlc.yaml` with all discovered databases
41
+
42
+ ## Example Structure
43
+
44
+ Given this structure:
45
+
46
+ ```
47
+ schema/weavesql/
48
+ ├── weave/
49
+ │ ├── migrations/
50
+ │ └── queries/
51
+ └── llmx/
52
+ ├── migrations/
53
+ └── queries/
54
+ ```
55
+
56
+ The tool will generate configurations for:
57
+
58
+ - `weave` → package `weavedb`, output to `weave/weavesql/weavedb`
59
+ - `llmx` → package `llmxdb`, output to `weave/weavesql/llmxdb`
60
+
61
+ ## Generated Configuration
62
+
63
+ The tool generates sqlc.yaml with:
64
+
65
+ - The sqlc Python plugin (sqlc-gen-python_1.3.0)
66
+ - Both sync and async querier generation
67
+ - String enum support
68
+ - Query parameter limit of 2
69
+
70
+ ## Integration with CI/CD
71
+
72
+ This tool is used in the GitHub Actions workflow to dynamically generate sqlc.yaml before running `sqlc generate`:
73
+
74
+ ```yaml
75
+ - name: Generate sqlc configuration
76
+ run: python tools/sqlcgen/sqlcgen.py
77
+
78
+ - name: Generate sql schema
79
+ run: sqlc generate
80
+ ```
81
+
82
+ ## Using with Task
83
+
84
+ The project includes a Taskfile for common operations:
85
+
86
+ ```bash
87
+ # Generate sqlc configuration
88
+ task generate-sqlc-config
89
+
90
+ # Generate all code (sqlc config + sqlc generate)
91
+ task generate
92
+
93
+ # Run tests for sqlcgen
94
+ task test-sqlcgen
95
+
96
+ # Clean generated files
97
+ task clean
98
+
99
+ # Show all available tasks
100
+ task --list
101
+ ```
102
+
103
+ ## Requirements
104
+
105
+ - Python 3.7+
106
+ - No external dependencies (uses only Python standard library)
@@ -0,0 +1,147 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ sqlcgen - SQLC Configuration Generator for Python projects
4
+
5
+ This tool automatically generates sqlc.yaml configuration based on directories
6
+ found in the schema/weavesql directory.
7
+ """
8
+
9
+ import argparse
10
+ import sys
11
+ from pathlib import Path
12
+ from typing import List, NamedTuple
13
+
14
+
15
+ class Database(NamedTuple):
16
+ """Represents a database configuration."""
17
+
18
+ name: str # e.g., "weave", "llmx"
19
+ package: str # e.g., "weavedb", "llmxdb"
20
+
21
+
22
+ def find_databases(schema_dir: Path) -> List[Database]:
23
+ """
24
+ Find all valid database directories in the schema directory.
25
+
26
+ A valid database directory must contain both 'migrations' and 'queries' subdirectories.
27
+
28
+ Args:
29
+ schema_dir: Path to the schema directory containing database folders
30
+
31
+ Returns:
32
+ List of Database objects sorted by name
33
+ """
34
+ databases = []
35
+
36
+ if not schema_dir.exists():
37
+ print(f"Schema directory {schema_dir} does not exist", file=sys.stderr)
38
+ sys.exit(1)
39
+
40
+ for entry in sorted(schema_dir.iterdir()):
41
+ if not entry.is_dir():
42
+ continue
43
+
44
+ # Skip hidden directories
45
+ if entry.name.startswith("."):
46
+ continue
47
+
48
+ # Check if migrations and queries directories exist
49
+ migrations_path = entry / "migrations"
50
+ queries_path = entry / "queries"
51
+
52
+ if not migrations_path.exists():
53
+ print(f"Skipping {entry.name}: migrations directory not found")
54
+ continue
55
+
56
+ if not queries_path.exists():
57
+ print(f"Skipping {entry.name}: queries directory not found")
58
+ continue
59
+
60
+ databases.append(Database(name=entry.name, package=f"{entry.name}db"))
61
+
62
+ return databases
63
+
64
+
65
+ def generate_sqlc_config(
66
+ databases: List[Database], output_file: Path, schema_prefix: str = "schema/weavesql"
67
+ ):
68
+ """
69
+ Generate sqlc.yaml configuration for Python using the sqlc Python plugin.
70
+
71
+ Args:
72
+ databases: List of Database objects
73
+ output_file: Path where the generated config should be written
74
+ schema_prefix: Prefix path to schema directory
75
+ """
76
+ # Start with version and plugin configuration
77
+ config_lines = [
78
+ 'version: "2"',
79
+ "plugins:",
80
+ " - name: py",
81
+ " wasm:",
82
+ " url: https://downloads.sqlc.dev/plugin/sqlc-gen-python_1.3.0.wasm",
83
+ " sha256: fbedae96b5ecae2380a70fb5b925fd4bff58a6cfb1f3140375d098fbab7b3a3c",
84
+ "sql:",
85
+ ]
86
+
87
+ for db in databases:
88
+ db_config = f''' - schema: "{schema_prefix}/{db.name}/migrations"
89
+ queries: "{schema_prefix}/{db.name}/queries"
90
+ engine: "postgresql"
91
+ codegen:
92
+ - out: "weave/weavesql/{db.package}"
93
+ plugin: "py"
94
+ options:
95
+ package: "weave.weavesql.{db.package}"
96
+ emit_async_querier: true
97
+ emit_str_enum: true
98
+ emit_sync_querier: true
99
+ query_parameter_limit: 2'''
100
+ config_lines.append(db_config)
101
+
102
+ # Write output file
103
+ with open(output_file, "w") as f:
104
+ f.write("\n".join(config_lines) + "\n")
105
+
106
+ print(f"Generated {output_file} with {len(databases)} database configurations")
107
+ for db in databases:
108
+ print(f" - {db.name} -> {db.package}")
109
+
110
+
111
+ def main():
112
+ """Main entry point for the script."""
113
+ parser = argparse.ArgumentParser(
114
+ description="Generate sqlc.yaml configuration for Python projects from schema directories"
115
+ )
116
+ parser.add_argument(
117
+ "--schema",
118
+ type=str,
119
+ default="schema/weavesql",
120
+ help="Path to schema directory containing database folders (default: schema/weavesql)",
121
+ )
122
+ parser.add_argument(
123
+ "--output",
124
+ type=str,
125
+ default="sqlc.yaml",
126
+ help="Output file path for generated sqlc.yaml (default: sqlc.yaml)",
127
+ )
128
+
129
+ args = parser.parse_args()
130
+
131
+ # Convert paths
132
+ schema_dir = Path(args.schema)
133
+ output_file = Path(args.output)
134
+
135
+ # Find databases
136
+ databases = find_databases(schema_dir)
137
+
138
+ if not databases:
139
+ print("No valid database directories found")
140
+ sys.exit(0)
141
+
142
+ # Generate configuration
143
+ generate_sqlc_config(databases, output_file, schema_prefix=args.schema)
144
+
145
+
146
+ if __name__ == "__main__":
147
+ main()
@@ -0,0 +1,280 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Tests for the sqlcgen tool.
4
+ """
5
+
6
+ import tempfile
7
+ import unittest
8
+ from pathlib import Path
9
+ from unittest.mock import patch
10
+ import sys
11
+ import os
12
+
13
+ # Add the parent directory to the path so we can import sqlcgen
14
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
15
+ import sqlcgen
16
+
17
+
18
+ class TestSQLCGen(unittest.TestCase):
19
+ """Test cases for the sqlcgen tool."""
20
+
21
+ def setUp(self):
22
+ """Set up test fixtures."""
23
+ # Create a temporary directory for testing
24
+ self.test_dir = tempfile.TemporaryDirectory()
25
+ self.test_path = Path(self.test_dir.name)
26
+
27
+ def tearDown(self):
28
+ """Clean up test fixtures."""
29
+ self.test_dir.cleanup()
30
+
31
+ def create_test_schema(self, databases):
32
+ """
33
+ Create a test schema directory structure.
34
+
35
+ Args:
36
+ databases: List of database names to create
37
+ """
38
+ schema_dir = self.test_path / "schema" / "weavesql"
39
+ for db_name in databases:
40
+ db_dir = schema_dir / db_name
41
+ (db_dir / "migrations").mkdir(parents=True)
42
+ (db_dir / "queries").mkdir(parents=True)
43
+ # Create dummy files
44
+ (db_dir / "migrations" / "001_init.sql").touch()
45
+ (db_dir / "queries" / "queries.sql").touch()
46
+ return schema_dir
47
+
48
+ def test_find_databases_with_valid_structure(self):
49
+ """Test finding databases with valid directory structure."""
50
+ schema_dir = self.create_test_schema(["weave", "llmx", "modex"])
51
+
52
+ databases = sqlcgen.find_databases(schema_dir)
53
+
54
+ self.assertEqual(len(databases), 3)
55
+ self.assertEqual(databases[0].name, "llmx")
56
+ self.assertEqual(databases[0].package, "llmxdb")
57
+ self.assertEqual(databases[1].name, "modex")
58
+ self.assertEqual(databases[1].package, "modexdb")
59
+ self.assertEqual(databases[2].name, "weave")
60
+ self.assertEqual(databases[2].package, "weavedb")
61
+
62
+ def test_find_databases_skips_invalid_directories(self):
63
+ """Test that directories without migrations or queries are skipped."""
64
+ schema_dir = self.create_test_schema(["valid"])
65
+
66
+ # Create invalid directories
67
+ (schema_dir / "no_migrations").mkdir()
68
+ (schema_dir / "no_migrations" / "queries").mkdir()
69
+
70
+ (schema_dir / "no_queries").mkdir()
71
+ (schema_dir / "no_queries" / "migrations").mkdir()
72
+
73
+ (schema_dir / ".hidden").mkdir()
74
+ (schema_dir / ".hidden" / "migrations").mkdir()
75
+ (schema_dir / ".hidden" / "queries").mkdir()
76
+
77
+ # Create a file (not a directory)
78
+ (schema_dir / "not_a_dir.txt").touch()
79
+
80
+ databases = sqlcgen.find_databases(schema_dir)
81
+
82
+ # Should only find the valid database
83
+ self.assertEqual(len(databases), 1)
84
+ self.assertEqual(databases[0].name, "valid")
85
+
86
+ def test_find_databases_with_nonexistent_directory(self):
87
+ """Test that nonexistent directory causes exit."""
88
+ nonexistent = self.test_path / "nonexistent"
89
+
90
+ with self.assertRaises(SystemExit) as cm:
91
+ sqlcgen.find_databases(nonexistent)
92
+
93
+ self.assertEqual(cm.exception.code, 1)
94
+
95
+ def test_generate_sqlc_config(self):
96
+ """Test generation of sqlc.yaml configuration."""
97
+ databases = [
98
+ sqlcgen.Database("weave", "weavedb"),
99
+ sqlcgen.Database("llmx", "llmxdb"),
100
+ ]
101
+ output_file = self.test_path / "sqlc.yaml"
102
+
103
+ sqlcgen.generate_sqlc_config(databases, output_file)
104
+
105
+ # Check that file was created
106
+ self.assertTrue(output_file.exists())
107
+
108
+ # Read and verify content
109
+ content = output_file.read_text()
110
+
111
+ # Check for required elements
112
+ self.assertIn('version: "2"', content)
113
+ self.assertIn("plugins:", content)
114
+ self.assertIn("name: py", content)
115
+ self.assertIn("sqlc-gen-python_1.3.0.wasm", content)
116
+
117
+ # Check for database configurations
118
+ self.assertIn('schema: "schema/weavesql/weave/migrations"', content)
119
+ self.assertIn('queries: "schema/weavesql/weave/queries"', content)
120
+ self.assertIn('package: "weave.weavesql.weavedb"', content)
121
+ self.assertIn('out: "weave/weavesql/weavedb"', content)
122
+
123
+ self.assertIn('schema: "schema/weavesql/llmx/migrations"', content)
124
+ self.assertIn('queries: "schema/weavesql/llmx/queries"', content)
125
+ self.assertIn('package: "weave.weavesql.llmxdb"', content)
126
+ self.assertIn('out: "weave/weavesql/llmxdb"', content)
127
+
128
+ # Check for options
129
+ self.assertIn("emit_async_querier: true", content)
130
+ self.assertIn("emit_str_enum: true", content)
131
+ self.assertIn("emit_sync_querier: true", content)
132
+ self.assertIn("query_parameter_limit: 2", content)
133
+
134
+ def test_generate_sqlc_config_with_custom_schema_prefix(self):
135
+ """Test generation with custom schema prefix."""
136
+ databases = [
137
+ sqlcgen.Database("test", "testdb"),
138
+ ]
139
+ output_file = self.test_path / "sqlc.yaml"
140
+
141
+ sqlcgen.generate_sqlc_config(
142
+ databases, output_file, schema_prefix="custom/path"
143
+ )
144
+
145
+ content = output_file.read_text()
146
+ self.assertIn('schema: "custom/path/test/migrations"', content)
147
+ self.assertIn('queries: "custom/path/test/queries"', content)
148
+
149
+ def test_main_integration(self):
150
+ """Test the main function with real directory structure."""
151
+ schema_dir = self.create_test_schema(["db1", "db2"])
152
+ output_file = self.test_path / "output.yaml"
153
+
154
+ # Mock sys.argv
155
+ test_args = [
156
+ "sqlcgen.py",
157
+ "--schema",
158
+ str(schema_dir),
159
+ "--output",
160
+ str(output_file),
161
+ ]
162
+
163
+ with patch.object(sys, "argv", test_args):
164
+ sqlcgen.main()
165
+
166
+ # Verify output file was created
167
+ self.assertTrue(output_file.exists())
168
+
169
+ # Verify content
170
+ content = output_file.read_text()
171
+ self.assertIn("db1", content)
172
+ self.assertIn("db2", content)
173
+ self.assertIn("db1db", content)
174
+ self.assertIn("db2db", content)
175
+
176
+ def test_main_with_no_databases(self):
177
+ """Test main function when no valid databases are found."""
178
+ empty_dir = self.test_path / "empty"
179
+ empty_dir.mkdir()
180
+ output_file = self.test_path / "output.yaml"
181
+
182
+ test_args = [
183
+ "sqlcgen.py",
184
+ "--schema",
185
+ str(empty_dir),
186
+ "--output",
187
+ str(output_file),
188
+ ]
189
+
190
+ with patch.object(sys, "argv", test_args):
191
+ with self.assertRaises(SystemExit) as cm:
192
+ sqlcgen.main()
193
+
194
+ # Should exit with code 0 (not an error, just no databases)
195
+ self.assertEqual(cm.exception.code, 0)
196
+
197
+ # Output file should not be created
198
+ self.assertFalse(output_file.exists())
199
+
200
+ def test_database_namedtuple(self):
201
+ """Test the Database namedtuple."""
202
+ db = sqlcgen.Database("mydb", "mydbpkg")
203
+ self.assertEqual(db.name, "mydb")
204
+ self.assertEqual(db.package, "mydbpkg")
205
+
206
+ def test_sorting_of_databases(self):
207
+ """Test that databases are sorted alphabetically."""
208
+ schema_dir = self.create_test_schema(["zebra", "alpha", "beta"])
209
+
210
+ databases = sqlcgen.find_databases(schema_dir)
211
+
212
+ # Should be sorted alphabetically
213
+ self.assertEqual(databases[0].name, "alpha")
214
+ self.assertEqual(databases[1].name, "beta")
215
+ self.assertEqual(databases[2].name, "zebra")
216
+
217
+
218
+ class TestSQLCGenOutput(unittest.TestCase):
219
+ """Test the actual output format of generated configurations."""
220
+
221
+ def test_yaml_structure(self):
222
+ """Test that the generated YAML has the correct structure."""
223
+ with tempfile.NamedTemporaryFile(mode="w+", suffix=".yaml", delete=False) as f:
224
+ databases = [
225
+ sqlcgen.Database("test", "testdb"),
226
+ ]
227
+ output_file = Path(f.name)
228
+
229
+ sqlcgen.generate_sqlc_config(databases, output_file)
230
+
231
+ # Read and parse line by line to check structure
232
+ lines = output_file.read_text().splitlines()
233
+
234
+ # Check indentation and structure
235
+ self.assertEqual(lines[0], 'version: "2"')
236
+ self.assertEqual(lines[1], "plugins:")
237
+ self.assertTrue(lines[2].startswith(" - name:"))
238
+
239
+ # Find sql section
240
+ sql_line = next(i for i, line in enumerate(lines) if line == "sql:")
241
+ self.assertTrue(sql_line > 0)
242
+
243
+ # Check database configuration starts with proper indentation
244
+ db_start = sql_line + 1
245
+ self.assertTrue(lines[db_start].startswith(" - schema:"))
246
+
247
+ # Clean up
248
+ output_file.unlink()
249
+
250
+ def test_multiple_databases_formatting(self):
251
+ """Test formatting with multiple databases."""
252
+ with tempfile.NamedTemporaryFile(mode="w+", suffix=".yaml", delete=False) as f:
253
+ databases = [
254
+ sqlcgen.Database("first", "firstdb"),
255
+ sqlcgen.Database("second", "seconddb"),
256
+ ]
257
+ output_file = Path(f.name)
258
+
259
+ sqlcgen.generate_sqlc_config(databases, output_file)
260
+
261
+ content = output_file.read_text()
262
+
263
+ # Count database entries
264
+ schema_count = content.count(" - schema:")
265
+ self.assertEqual(schema_count, 2)
266
+
267
+ # Verify each database has all required fields
268
+ for db in databases:
269
+ self.assertIn(
270
+ f'schema: "schema/weavesql/{db.name}/migrations"', content
271
+ )
272
+ self.assertIn(f'queries: "schema/weavesql/{db.name}/queries"', content)
273
+ self.assertIn(f'package: "weave.weavesql.{db.package}"', content)
274
+
275
+ # Clean up
276
+ output_file.unlink()
277
+
278
+
279
+ if __name__ == "__main__":
280
+ unittest.main()
@@ -55,16 +55,16 @@ wheels = [
55
55
 
56
56
  [[package]]
57
57
  name = "protobuf"
58
- version = "6.31.1"
58
+ version = "6.32.0"
59
59
  source = { registry = "https://pypi.org/simple" }
60
- sdist = { url = "https://files.pythonhosted.org/packages/52/f3/b9655a711b32c19720253f6f06326faf90580834e2e83f840472d752bc8b/protobuf-6.31.1.tar.gz", hash = "sha256:d8cac4c982f0b957a4dc73a80e2ea24fab08e679c0de9deb835f4a12d69aca9a", size = 441797, upload-time = "2025-05-28T19:25:54.947Z" }
60
+ sdist = { url = "https://files.pythonhosted.org/packages/c0/df/fb4a8eeea482eca989b51cffd274aac2ee24e825f0bf3cbce5281fa1567b/protobuf-6.32.0.tar.gz", hash = "sha256:a81439049127067fc49ec1d36e25c6ee1d1a2b7be930675f919258d03c04e7d2", size = 440614, upload-time = "2025-08-14T21:21:25.015Z" }
61
61
  wheels = [
62
- { url = "https://files.pythonhosted.org/packages/f3/6f/6ab8e4bf962fd5570d3deaa2d5c38f0a363f57b4501047b5ebeb83ab1125/protobuf-6.31.1-cp310-abi3-win32.whl", hash = "sha256:7fa17d5a29c2e04b7d90e5e32388b8bfd0e7107cd8e616feef7ed3fa6bdab5c9", size = 423603, upload-time = "2025-05-28T19:25:41.198Z" },
63
- { url = "https://files.pythonhosted.org/packages/44/3a/b15c4347dd4bf3a1b0ee882f384623e2063bb5cf9fa9d57990a4f7df2fb6/protobuf-6.31.1-cp310-abi3-win_amd64.whl", hash = "sha256:426f59d2964864a1a366254fa703b8632dcec0790d8862d30034d8245e1cd447", size = 435283, upload-time = "2025-05-28T19:25:44.275Z" },
64
- { url = "https://files.pythonhosted.org/packages/6a/c9/b9689a2a250264a84e66c46d8862ba788ee7a641cdca39bccf64f59284b7/protobuf-6.31.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:6f1227473dc43d44ed644425268eb7c2e488ae245d51c6866d19fe158e207402", size = 425604, upload-time = "2025-05-28T19:25:45.702Z" },
65
- { url = "https://files.pythonhosted.org/packages/76/a1/7a5a94032c83375e4fe7e7f56e3976ea6ac90c5e85fac8576409e25c39c3/protobuf-6.31.1-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:a40fc12b84c154884d7d4c4ebd675d5b3b5283e155f324049ae396b95ddebc39", size = 322115, upload-time = "2025-05-28T19:25:47.128Z" },
66
- { url = "https://files.pythonhosted.org/packages/fa/b1/b59d405d64d31999244643d88c45c8241c58f17cc887e73bcb90602327f8/protobuf-6.31.1-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:4ee898bf66f7a8b0bd21bce523814e6fbd8c6add948045ce958b73af7e8878c6", size = 321070, upload-time = "2025-05-28T19:25:50.036Z" },
67
- { url = "https://files.pythonhosted.org/packages/f7/af/ab3c51ab7507a7325e98ffe691d9495ee3d3aa5f589afad65ec920d39821/protobuf-6.31.1-py3-none-any.whl", hash = "sha256:720a6c7e6b77288b85063569baae8536671b39f15cc22037ec7045658d80489e", size = 168724, upload-time = "2025-05-28T19:25:53.926Z" },
62
+ { url = "https://files.pythonhosted.org/packages/33/18/df8c87da2e47f4f1dcc5153a81cd6bca4e429803f4069a299e236e4dd510/protobuf-6.32.0-cp310-abi3-win32.whl", hash = "sha256:84f9e3c1ff6fb0308dbacb0950d8aa90694b0d0ee68e75719cb044b7078fe741", size = 424409, upload-time = "2025-08-14T21:21:12.366Z" },
63
+ { url = "https://files.pythonhosted.org/packages/e1/59/0a820b7310f8139bd8d5a9388e6a38e1786d179d6f33998448609296c229/protobuf-6.32.0-cp310-abi3-win_amd64.whl", hash = "sha256:a8bdbb2f009cfc22a36d031f22a625a38b615b5e19e558a7b756b3279723e68e", size = 435735, upload-time = "2025-08-14T21:21:15.046Z" },
64
+ { url = "https://files.pythonhosted.org/packages/cc/5b/0d421533c59c789e9c9894683efac582c06246bf24bb26b753b149bd88e4/protobuf-6.32.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d52691e5bee6c860fff9a1c86ad26a13afbeb4b168cd4445c922b7e2cf85aaf0", size = 426449, upload-time = "2025-08-14T21:21:16.687Z" },
65
+ { url = "https://files.pythonhosted.org/packages/ec/7b/607764ebe6c7a23dcee06e054fd1de3d5841b7648a90fd6def9a3bb58c5e/protobuf-6.32.0-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:501fe6372fd1c8ea2a30b4d9be8f87955a64d6be9c88a973996cef5ef6f0abf1", size = 322869, upload-time = "2025-08-14T21:21:18.282Z" },
66
+ { url = "https://files.pythonhosted.org/packages/40/01/2e730bd1c25392fc32e3268e02446f0d77cb51a2c3a8486b1798e34d5805/protobuf-6.32.0-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:75a2aab2bd1aeb1f5dc7c5f33bcb11d82ea8c055c9becbb41c26a8c43fd7092c", size = 322009, upload-time = "2025-08-14T21:21:19.893Z" },
67
+ { url = "https://files.pythonhosted.org/packages/9c/f2/80ffc4677aac1bc3519b26bc7f7f5de7fce0ee2f7e36e59e27d8beb32dd1/protobuf-6.32.0-py3-none-any.whl", hash = "sha256:ba377e5b67b908c8f3072a57b63e2c6a4cbd18aea4ed98d2584350dbf46f2783", size = 169287, upload-time = "2025-08-14T21:21:23.515Z" },
68
68
  ]
69
69
 
70
70
  [[package]]