matchbox-db 0.7.14.dev45__tar.gz → 0.7.14.dev51__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 (245) hide show
  1. {matchbox_db-0.7.14.dev45/src/matchbox_db.egg-info → matchbox_db-0.7.14.dev51}/PKG-INFO +1 -1
  2. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/_handler.py +4 -4
  3. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/_settings.py +1 -1
  4. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/cli/eval/app.py +5 -7
  5. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/eval/samples.py +8 -6
  6. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/common/arrow.py +1 -1
  7. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/common/dtos.py +59 -52
  8. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/common/eval.py +1 -1
  9. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/common/exceptions.py +22 -4
  10. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/api/routers/auth.py +1 -3
  11. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/api/routers/eval.py +2 -2
  12. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/base.py +173 -5
  13. matchbox_db-0.7.14.dev51/src/matchbox/server/postgresql/adapter/admin.py +570 -0
  14. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/adapter/eval.py +2 -2
  15. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/utils/evaluation.py +14 -10
  16. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51/src/matchbox_db.egg-info}/PKG-INFO +1 -1
  17. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/cli/eval/test_app.py +0 -1
  18. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/test_eval.py +6 -6
  19. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/test_handler.py +1 -1
  20. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/common/test_eval.py +3 -3
  21. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/e2e/test_e2e_evaluation.py +1 -1
  22. matchbox_db-0.7.14.dev51/test/server/adapter/test_adapter_admin.py +782 -0
  23. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/adapter/test_adapter_eval.py +24 -21
  24. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/api/routes/test_routes_auth.py +2 -3
  25. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/api/routes/test_routes_eval.py +7 -7
  26. matchbox_db-0.7.14.dev45/src/matchbox/server/postgresql/adapter/admin.py +0 -139
  27. matchbox_db-0.7.14.dev45/test/server/adapter/test_adapter_admin.py +0 -169
  28. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/.github/pull_request_template.md +0 -0
  29. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/.github/workflows/ci.yml +0 -0
  30. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/.github/workflows/codeql.yml +0 -0
  31. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/.github/workflows/prerelease.yml +0 -0
  32. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/.github/workflows/release.yml +0 -0
  33. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/.gitignore +0 -0
  34. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/.pre-commit-config.yaml +0 -0
  35. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/.vscode/launch.json +0 -0
  36. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/.vscode/settings.json +0 -0
  37. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/CODEOWNERS +0 -0
  38. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/LICENSE +0 -0
  39. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/README.md +0 -0
  40. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docker-compose.yml +0 -0
  41. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/client/dags.md +0 -0
  42. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/client/eval.md +0 -0
  43. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/client/index.md +0 -0
  44. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/client/locations.md +0 -0
  45. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/client/models.md +0 -0
  46. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/client/queries.md +0 -0
  47. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/client/results.md +0 -0
  48. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/client/sources.md +0 -0
  49. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/common/arrow.md +0 -0
  50. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/common/db.md +0 -0
  51. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/common/dtos.md +0 -0
  52. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/common/eval.md +0 -0
  53. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/common/exceptions.md +0 -0
  54. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/common/factories/entities.md +0 -0
  55. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/common/factories/index.md +0 -0
  56. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/common/factories/models.md +0 -0
  57. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/common/factories/scenarios.md +0 -0
  58. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/common/factories/sources.md +0 -0
  59. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/common/hash.md +0 -0
  60. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/common/index.md +0 -0
  61. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/common/logging.md +0 -0
  62. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/common/transform.md +0 -0
  63. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/server/api.md +0 -0
  64. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/server/backends/postgresql.md +0 -0
  65. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/server/index.md +0 -0
  66. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/api/server/uploads.md +0 -0
  67. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/assets/matchbox-icon-dark.png +0 -0
  68. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/assets/matchbox-icon.svg +0 -0
  69. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/assets/matchbox-logo-dark.svg +0 -0
  70. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/assets/matchbox-logo-light.svg +0 -0
  71. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/client/cli.md +0 -0
  72. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/client/evaluation.md +0 -0
  73. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/client/explore-dags.md +0 -0
  74. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/client/install.md +0 -0
  75. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/client/link-data.md +0 -0
  76. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/client/look-up.md +0 -0
  77. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/contributing.md +0 -0
  78. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/index.md +0 -0
  79. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/server/concepts.md +0 -0
  80. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/server/install.md +0 -0
  81. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/server/risks.md +0 -0
  82. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/stylesheets/extra.css +0 -0
  83. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/docs/use-cases.md +0 -0
  84. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/environments/containers.env +0 -0
  85. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/environments/development.env +0 -0
  86. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/environments/sample_client.env +0 -0
  87. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/environments/sample_server.env +0 -0
  88. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/justfile +0 -0
  89. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/mkdocs.yml +0 -0
  90. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/pyproject.toml +0 -0
  91. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/setup.cfg +0 -0
  92. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/__init__.py +0 -0
  93. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/__init__.py +0 -0
  94. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/cli/__init__.py +0 -0
  95. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/cli/auth.py +0 -0
  96. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/cli/eval/__init__.py +0 -0
  97. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/cli/eval/modals.py +0 -0
  98. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/cli/eval/run.py +0 -0
  99. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/cli/eval/styles.tcss +0 -0
  100. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/cli/eval/widgets/__init__.py +0 -0
  101. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/cli/eval/widgets/assignment.py +0 -0
  102. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/cli/eval/widgets/styling.py +0 -0
  103. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/cli/eval/widgets/table.py +0 -0
  104. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/cli/main.py +0 -0
  105. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/cli/server.py +0 -0
  106. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/dags.py +0 -0
  107. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/eval/__init__.py +0 -0
  108. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/locations.py +0 -0
  109. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/models/__init__.py +0 -0
  110. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/models/comparison.py +0 -0
  111. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/models/dedupers/__init__.py +0 -0
  112. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/models/dedupers/base.py +0 -0
  113. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/models/dedupers/naive.py +0 -0
  114. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/models/linkers/__init__.py +0 -0
  115. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/models/linkers/base.py +0 -0
  116. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/models/linkers/deterministic.py +0 -0
  117. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/models/linkers/splinklinker.py +0 -0
  118. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/models/linkers/weighteddeterministic.py +0 -0
  119. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/models/models.py +0 -0
  120. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/queries.py +0 -0
  121. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/results.py +0 -0
  122. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/client/sources.py +0 -0
  123. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/common/__init__.py +0 -0
  124. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/common/db.py +0 -0
  125. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/common/factories/__init__.py +0 -0
  126. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/common/factories/dags.py +0 -0
  127. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/common/factories/entities.py +0 -0
  128. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/common/factories/models.py +0 -0
  129. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/common/factories/scenarios.py +0 -0
  130. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/common/factories/sources.py +0 -0
  131. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/common/hash.py +0 -0
  132. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/common/logging.py +0 -0
  133. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/common/transform.py +0 -0
  134. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/Dockerfile +0 -0
  135. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/__init__.py +0 -0
  136. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/api/__init__.py +0 -0
  137. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/api/dependencies.py +0 -0
  138. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/api/main.py +0 -0
  139. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/api/routers/__init__.py +0 -0
  140. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/api/routers/collection.py +0 -0
  141. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/api/static/favicon.png +0 -0
  142. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/api/static/swagger-ui-bundle.js +0 -0
  143. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/api/static/swagger-ui.css +0 -0
  144. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/.gitkeep +0 -0
  145. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/__init__.py +0 -0
  146. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/adapter/__init__.py +0 -0
  147. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/adapter/collections.py +0 -0
  148. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/adapter/main.py +0 -0
  149. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/adapter/query.py +0 -0
  150. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/env.py +0 -0
  151. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/script.py.mako +0 -0
  152. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/05cc4181a0ad_removed_source_key_reference_and_added_.py +0 -0
  153. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/13095b44ff09_add_user_model_groups_and_permissions_.py +0 -0
  154. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/1907c34cfa1f_create_tables_given_schema.py +0 -0
  155. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/3754ae042254_move_orm_to_root_leaf_contains_structure.py +0 -0
  156. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/40a8e5ed48f2_create_schema_without_tables.py +0 -0
  157. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/4a7c35f86405_move_sourceconfigs_from_sourceaddress_.py +0 -0
  158. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/7a2d1b10ac0f_switch_from_location_uri_to_name.py +0 -0
  159. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/83b134a86713_simplify_resolution_naming_and_hashing.py +0 -0
  160. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/8c7f757b1046_remove_human_resolution_type.py +0 -0
  161. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/95c0b5c23446_renaming_sources_to_source_config.py +0 -0
  162. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/ae63f79f6b39_renamed_sourcecolumns_to_sourcefields.py +0 -0
  163. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/b38d61ab11cc_add_index_to_the_clustersourcekey_table.py +0 -0
  164. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/b694eb292dea_add_an_index_to_the_probabilities_.py +0 -0
  165. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/beba75a24962_add_pkspace_table.py +0 -0
  166. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/c4cb937d00f4_add_modelconfigs.py +0 -0
  167. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/c774fd4b69f8_add_upload_stage_to_resolutions.py +0 -0
  168. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/dd0c3a9ecdf9_add_migrations_for_first_eval_tables.py +0 -0
  169. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/e4122bdf9b0d_renamed_primary_keys_to_just_keys.py +0 -0
  170. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/f3c9279437f4_add_content_hash_to_resolutions.py +0 -0
  171. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic/versions/f500f7d832fe_adds_collections_and_versions_to_scope_.py +0 -0
  172. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/alembic.ini +0 -0
  173. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/db.py +0 -0
  174. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/justfile +0 -0
  175. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/mixin.py +0 -0
  176. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/orm.py +0 -0
  177. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/utils/__init__.py +0 -0
  178. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/utils/db.py +0 -0
  179. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/utils/insert.py +0 -0
  180. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/utils/query.py +0 -0
  181. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/postgresql/utils/results.py +0 -0
  182. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox/server/uploads.py +0 -0
  183. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox_db.egg-info/SOURCES.txt +0 -0
  184. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox_db.egg-info/dependency_links.txt +0 -0
  185. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox_db.egg-info/entry_points.txt +0 -0
  186. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox_db.egg-info/requires.txt +0 -0
  187. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/src/matchbox_db.egg-info/top_level.txt +0 -0
  188. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/__init__.py +0 -0
  189. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/__init__.py +0 -0
  190. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/cli/__init__.py +0 -0
  191. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/cli/eval/__init__.py +0 -0
  192. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/cli/eval/test_widgets.py +0 -0
  193. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/cli/test_main.py +0 -0
  194. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/models/__init__.py +0 -0
  195. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/models/methodologies/__init__.py +0 -0
  196. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/models/methodologies/test_dedupers_deterministic.py +0 -0
  197. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/models/methodologies/test_linkers_deterministic.py +0 -0
  198. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/models/methodologies/test_linkers_probabilistic.py +0 -0
  199. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/models/test_comparison.py +0 -0
  200. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/test_dags.py +0 -0
  201. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/test_locations.py +0 -0
  202. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/test_models.py +0 -0
  203. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/test_queries.py +0 -0
  204. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/test_results.py +0 -0
  205. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/client/test_sources.py +0 -0
  206. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/common/__init__.py +0 -0
  207. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/common/factories/__init__.py +0 -0
  208. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/common/factories/test_entity_factory.py +0 -0
  209. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/common/factories/test_linked_factory.py +0 -0
  210. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/common/factories/test_model_factory.py +0 -0
  211. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/common/factories/test_probability_generation.py +0 -0
  212. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/common/factories/test_scenarios.py +0 -0
  213. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/common/factories/test_source_factory.py +0 -0
  214. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/common/factories/test_testkit_dag.py +0 -0
  215. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/common/test_dto.py +0 -0
  216. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/common/test_hash.py +0 -0
  217. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/common/test_results.py +0 -0
  218. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/common/test_transform.py +0 -0
  219. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/conftest.py +0 -0
  220. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/data/all_companies.csv +0 -0
  221. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/e2e/test_e2e_dag.py +0 -0
  222. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/e2e/test_e2e_methodologies.py +0 -0
  223. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/fixtures/__init__.py +0 -0
  224. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/fixtures/client.py +0 -0
  225. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/fixtures/db.py +0 -0
  226. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/justfile +0 -0
  227. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/scripts/authorisation.py +0 -0
  228. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/scripts/eval.py +0 -0
  229. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/__init__.py +0 -0
  230. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/adapter/test_adapter_collections.py +0 -0
  231. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/adapter/test_adapter_main.py +0 -0
  232. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/adapter/test_adapter_query.py +0 -0
  233. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/api/__init__.py +0 -0
  234. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/api/routes/__init__.py +0 -0
  235. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/api/routes/test_routes_collection.py +0 -0
  236. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/api/routes/test_routes_main.py +0 -0
  237. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/api/routes/test_routes_resolution.py +0 -0
  238. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/postgresql/__init__.py +0 -0
  239. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/postgresql/test_pg_core.py +0 -0
  240. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/postgresql/test_pg_migrations.py +0 -0
  241. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/postgresql/test_pg_sql.py +0 -0
  242. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/server/test_uploads.py +0 -0
  243. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/test/utils.py +0 -0
  244. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/trufflehog-exclude.txt +0 -0
  245. {matchbox_db-0.7.14.dev45 → matchbox_db-0.7.14.dev51}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: matchbox-db
3
- Version: 0.7.14.dev45
3
+ Version: 0.7.14.dev51
4
4
  Summary: A framework for orchestrating and comparing data linking and deduplication methodologies.
5
5
  Author: Department for Business and Trade
6
6
  Project-URL: Documentation, https://uktrade.github.io/matchbox/
@@ -189,7 +189,7 @@ def login(user_name: str) -> int:
189
189
  """Log into Matchbox and return the user ID."""
190
190
  logger.debug(f"Log in attempt for {user_name}")
191
191
  response = CLIENT.post("/auth/login", json=User(user_name=user_name).model_dump())
192
- return User.model_validate(response.json()).user_id
192
+ return User.model_validate(response.json()).user_name
193
193
 
194
194
 
195
195
  @http_retry
@@ -515,7 +515,7 @@ def delete_resolution(
515
515
 
516
516
 
517
517
  @http_retry
518
- def sample_for_eval(n: int, resolution: ModelResolutionPath, user_id: int) -> Table:
518
+ def sample_for_eval(n: int, resolution: ModelResolutionPath, user_name: str) -> Table:
519
519
  """Sample model results for evaluation."""
520
520
  res = CLIENT.get(
521
521
  "/eval/samples",
@@ -525,7 +525,7 @@ def sample_for_eval(n: int, resolution: ModelResolutionPath, user_id: int) -> Ta
525
525
  "collection": resolution.collection,
526
526
  "run_id": resolution.run,
527
527
  "resolution": resolution.name,
528
- "user_id": user_id,
528
+ "user_name": user_name,
529
529
  }
530
530
  ),
531
531
  )
@@ -548,7 +548,7 @@ def send_eval_judgement(judgement: Judgement) -> None:
548
548
  """Send judgements to the server."""
549
549
  logger.debug(
550
550
  f"Submitting judgement {judgement.shown}:{judgement.endorsed} "
551
- f"for {judgement.user_id}"
551
+ f"for {judgement.user_name}"
552
552
  )
553
553
  CLIENT.post("/eval/judgements", json=judgement.model_dump())
554
554
 
@@ -42,7 +42,7 @@ class ClientSettings(BaseSettings):
42
42
  # Decode header and payload
43
43
  header = json.loads(base64.urlsafe_b64decode(parts[0] + "=="))
44
44
  payload = json.loads(base64.urlsafe_b64decode(parts[1] + "=="))
45
- except Exception as e: # noqa: BLE0001
45
+ except Exception as e: # noqa: BLE001
46
46
  raise ValueError("Invalid JWT.") from e
47
47
 
48
48
  # Basic header checks
@@ -108,7 +108,6 @@ class EntityResolutionApp(App):
108
108
 
109
109
  sample_limit: int
110
110
  resolution: ModelResolutionPath
111
- user_id: int
112
111
  user_name: str
113
112
  dag: DAG
114
113
  show_help: bool
@@ -304,8 +303,7 @@ class EntityResolutionApp(App):
304
303
  if not user_name:
305
304
  raise MatchboxClientSettingsException("User name is unset.")
306
305
 
307
- self.user_name = user_name
308
- self.user_id = _handler.login(user_name=user_name)
306
+ self.user_name = _handler.login(user_name=user_name)
309
307
 
310
308
  async def load_samples(self) -> None:
311
309
  """Load evaluation samples from the server."""
@@ -326,7 +324,7 @@ class EntityResolutionApp(App):
326
324
  new_samples_dict = get_samples(
327
325
  n=needed,
328
326
  resolution=self.resolution.name,
329
- user_id=self.user_id,
327
+ user_name=self.user_name,
330
328
  dag=self.dag,
331
329
  )
332
330
  except Exception as e: # noqa: BLE001
@@ -370,10 +368,10 @@ class EntityResolutionApp(App):
370
368
  return
371
369
 
372
370
  try:
373
- if self.user_id is None:
374
- raise RuntimeError("User ID is not set")
371
+ if self.user_name is None:
372
+ raise RuntimeError("User name is not set")
375
373
  judgement = create_judgement(
376
- current.item, current.assignments, self.user_id
374
+ current.item, current.assignments, self.user_name
377
375
  )
378
376
  _handler.send_eval_judgement(judgement)
379
377
  except Exception as exc:
@@ -73,14 +73,14 @@ class EvaluationItem(BaseModel):
73
73
 
74
74
 
75
75
  def create_judgement(
76
- item: EvaluationItem, assignments: dict[int, str], user_id: int
76
+ item: EvaluationItem, assignments: dict[int, str], user_name: str
77
77
  ) -> Judgement:
78
78
  """Convert item assignments to Judgement - no default group assignment.
79
79
 
80
80
  Args:
81
81
  item: Evaluation item
82
82
  assignments: Column assignments (group_idx -> group_letter)
83
- user_id: User ID for the judgement
83
+ user_name: User name for the judgement
84
84
 
85
85
  Returns:
86
86
  Judgement with endorsed groups based on assignments
@@ -93,7 +93,7 @@ def create_judgement(
93
93
  groups.setdefault(group, []).extend(leaf_ids)
94
94
 
95
95
  endorsed = [sorted(set(leaf_ids)) for leaf_ids in groups.values()]
96
- return Judgement(user_id=user_id, shown=item.cluster_id, endorsed=endorsed)
96
+ return Judgement(user_name=user_name, shown=item.cluster_id, endorsed=endorsed)
97
97
 
98
98
 
99
99
  def create_evaluation_item(
@@ -136,7 +136,7 @@ def create_evaluation_item(
136
136
  def get_samples(
137
137
  n: int,
138
138
  dag: DAG,
139
- user_id: int,
139
+ user_name: str,
140
140
  resolution: ModelResolutionName | None = None,
141
141
  ) -> dict[int, EvaluationItem]:
142
142
  """Retrieve samples enriched with source data as EvaluationItems.
@@ -144,7 +144,7 @@ def get_samples(
144
144
  Args:
145
145
  n: Number of clusters to sample
146
146
  dag: DAG for which to retrieve samples
147
- user_id: ID of the user requesting the samples
147
+ user_name: Name of the user requesting the samples
148
148
  resolution: The optional resolution from which to sample. If not provided,
149
149
  the final step in the DAG is used
150
150
 
@@ -163,7 +163,9 @@ def get_samples(
163
163
  samples: pl.DataFrame = cast(
164
164
  pl.DataFrame,
165
165
  pl.from_arrow(
166
- _handler.sample_for_eval(n=n, resolution=resolution_path, user_id=user_id)
166
+ _handler.sample_for_eval(
167
+ n=n, resolution=resolution_path, user_name=user_name
168
+ )
167
169
  ),
168
170
  )
169
171
 
@@ -36,7 +36,7 @@ SCHEMA_RESULTS: Final[pa.Schema] = pa.schema(
36
36
 
37
37
  SCHEMA_JUDGEMENTS: Final[pa.Schema] = pa.schema(
38
38
  [
39
- ("user_id", pa.uint64()),
39
+ ("user_name", pa.large_string()),
40
40
  ("endorsed", pa.uint64()),
41
41
  ("shown", pa.uint64()),
42
42
  ]
@@ -30,6 +30,54 @@ from matchbox.common.exceptions import MatchboxNameError
30
30
  from matchbox.common.hash import base64_to_hash, hash_to_base64
31
31
 
32
32
 
33
+ class MatchboxName(str):
34
+ """Sub-class of string which validates names for the Matchbox DB."""
35
+
36
+ PATTERN = r"^[a-zA-Z0-9_.-]+$"
37
+
38
+ def __new__(cls, value: str) -> Self:
39
+ """Creates new instance of validated name."""
40
+ if not isinstance(value, str):
41
+ raise MatchboxNameError("Name must be a string")
42
+ if not re.match(cls.PATTERN, value):
43
+ raise MatchboxNameError(
44
+ f"Name '{value}' is invalid. It can only include "
45
+ "alphanumeric characters, underscores, dots or hyphens."
46
+ )
47
+
48
+ return super().__new__(cls, value)
49
+
50
+ @classmethod
51
+ def __get_pydantic_core_schema__(
52
+ cls,
53
+ source_type: Any, # noqa: ANN401
54
+ handler: GetCoreSchemaHandler,
55
+ ) -> core_schema.CoreSchema:
56
+ """Generate core schema for Pydantic compatibility."""
57
+ return core_schema.no_info_plain_validator_function(
58
+ cls,
59
+ serialization=core_schema.plain_serializer_function_ser_schema(
60
+ lambda x: x, return_schema=core_schema.str_schema()
61
+ ),
62
+ )
63
+
64
+ @classmethod
65
+ def __get_pydantic_json_schema__(
66
+ cls,
67
+ schema: core_schema.CoreSchema,
68
+ handler: GetJsonSchemaHandler,
69
+ ) -> JsonSchemaValue:
70
+ """Generate JSON schema for OpenAPI documentation."""
71
+ json_schema = handler(core_schema.str_schema())
72
+ json_schema.update(
73
+ {
74
+ "type": "string",
75
+ "pattern": cls.PATTERN,
76
+ }
77
+ )
78
+ return json_schema
79
+
80
+
33
81
  class DataTypes(StrEnum):
34
82
  """Enumeration of supported data types.
35
83
 
@@ -169,6 +217,7 @@ class BackendResourceType(StrEnum):
169
217
  CLUSTER = "cluster"
170
218
  USER = "user"
171
219
  JUDGEMENT = "judgement"
220
+ SYSTEM = "system"
172
221
 
173
222
 
174
223
  class BackendParameterType(StrEnum):
@@ -205,24 +254,30 @@ class User(BaseModel):
205
254
 
206
255
  model_config = ConfigDict(populate_by_name=True)
207
256
 
208
- user_id: int | None = None
209
257
  user_name: str = Field(alias="sub")
210
258
  email: EmailStr | None = None
211
259
 
212
260
 
261
+ GroupName: TypeAlias = MatchboxName
262
+ """Type alias for group names."""
263
+
264
+
213
265
  class Group(BaseModel):
214
266
  """Group definition."""
215
267
 
216
- name: str
268
+ name: GroupName
217
269
  description: str | None = None
218
270
  is_system: bool = False
219
271
  members: list[User] = []
220
272
 
221
273
 
222
274
  class PermissionGrant(BaseModel):
223
- """A permission on a resource. Resource context comes from URL."""
275
+ """A permission on a resource.
224
276
 
225
- group_name: str
277
+ Resource context should always be supplied.
278
+ """
279
+
280
+ group_name: GroupName
226
281
  permission: PermissionType
227
282
 
228
283
 
@@ -234,54 +289,6 @@ class AuthStatusResponse(BaseModel):
234
289
  token: str | None = None
235
290
 
236
291
 
237
- class MatchboxName(str):
238
- """Sub-class of string which validates names for the Matchbox DB."""
239
-
240
- PATTERN = r"^[a-zA-Z0-9_.-]+$"
241
-
242
- def __new__(cls, value: str) -> Self:
243
- """Creates new instance of validated name."""
244
- if not isinstance(value, str):
245
- raise MatchboxNameError("Name must be a string")
246
- if not re.match(cls.PATTERN, value):
247
- raise MatchboxNameError(
248
- f"Name '{value}' is invalid. It can only include "
249
- "alphanumeric characters, underscores, dots or hyphens."
250
- )
251
-
252
- return super().__new__(cls, value)
253
-
254
- @classmethod
255
- def __get_pydantic_core_schema__(
256
- cls,
257
- source_type: Any, # noqa: ANN401
258
- handler: GetCoreSchemaHandler,
259
- ) -> core_schema.CoreSchema:
260
- """Generate core schema for Pydantic compatibility."""
261
- return core_schema.no_info_plain_validator_function(
262
- cls,
263
- serialization=core_schema.plain_serializer_function_ser_schema(
264
- lambda x: x, return_schema=core_schema.str_schema()
265
- ),
266
- )
267
-
268
- @classmethod
269
- def __get_pydantic_json_schema__(
270
- cls,
271
- schema: core_schema.CoreSchema,
272
- handler: GetJsonSchemaHandler,
273
- ) -> JsonSchemaValue:
274
- """Generate JSON schema for OpenAPI documentation."""
275
- json_schema = handler(core_schema.str_schema())
276
- json_schema.update(
277
- {
278
- "type": "string",
279
- "pattern": cls.PATTERN,
280
- }
281
- )
282
- return json_schema
283
-
284
-
285
292
  CollectionName: TypeAlias = MatchboxName
286
293
  """Type alias for collection names."""
287
294
 
@@ -18,7 +18,7 @@ ModelComparison: TypeAlias = dict[ModelResolutionPath, PrecisionRecall]
18
18
  class Judgement(BaseModel):
19
19
  """User determination on how to group source clusters from a model cluster."""
20
20
 
21
- user_id: int
21
+ user_name: str
22
22
  shown: int = Field(description="ID of the model cluster shown to the user")
23
23
  endorsed: list[list[int]] = Field(
24
24
  description="""Groups of source cluster IDs that user thinks belong together"""
@@ -174,15 +174,17 @@ class MatchboxServerFileError(MatchboxException):
174
174
  class MatchboxUserNotFoundError(MatchboxException):
175
175
  """User not found."""
176
176
 
177
- def __init__(self, message: str | None = None, user_id: str | None = None) -> None:
177
+ def __init__(
178
+ self, message: str | None = None, user_name: str | None = None
179
+ ) -> None:
178
180
  """Initialise the exception."""
179
181
  if message is None:
180
182
  message = "User not found."
181
- if user_id is not None:
182
- message = f"User {user_id} not found."
183
+ if user_name is not None:
184
+ message = f"User {user_name} not found."
183
185
 
184
186
  super().__init__(message)
185
- self.user_id = user_id
187
+ self.user_name = user_name
186
188
 
187
189
 
188
190
  class MatchboxResolutionNotFoundError(MatchboxException):
@@ -260,6 +262,10 @@ class MatchboxConnectionError(MatchboxException):
260
262
  """Connection to Matchbox's backend database failed."""
261
263
 
262
264
 
265
+ class MatchboxPermissionDeniedError(MatchboxException):
266
+ """Raised when a user lacks permission for an action."""
267
+
268
+
263
269
  class MatchboxDeletionNotConfirmed(MatchboxException):
264
270
  """Deletion must be confirmed: if certain, rerun with certain=True."""
265
271
 
@@ -319,6 +325,18 @@ class MatchboxTooManySamplesRequested(MatchboxException):
319
325
  """Too many samples have been requested from the server."""
320
326
 
321
327
 
328
+ class MatchboxGroupNotFoundError(MatchboxException):
329
+ """Raised when a group is not found."""
330
+
331
+
332
+ class MatchboxGroupAlreadyExistsError(MatchboxException):
333
+ """Raised when attempting to create a group that already exists."""
334
+
335
+
336
+ class MatchboxSystemGroupError(MatchboxException):
337
+ """Raised when attempting to modify or delete a system group."""
338
+
339
+
322
340
  # -- Adapter DB exceptions --
323
341
 
324
342
 
@@ -48,9 +48,7 @@ def login(
48
48
  credentials: User,
49
49
  ) -> User:
50
50
  """Receive a User with a username and returns it with a user ID."""
51
- return User(
52
- user_id=backend.login(credentials.user_name), user_name=credentials.user_name
53
- )
51
+ return backend.login(credentials)
54
52
 
55
53
 
56
54
  @router.get("/status")
@@ -115,7 +115,7 @@ def sample(
115
115
  run_id: RunID,
116
116
  resolution: ModelResolutionName,
117
117
  n: int,
118
- user_id: int,
118
+ user_name: str,
119
119
  ) -> ParquetResponse:
120
120
  """Sample n cluster to validate."""
121
121
  try:
@@ -124,7 +124,7 @@ def sample(
124
124
  collection=collection, run=run_id, name=resolution
125
125
  ),
126
126
  n=n,
127
- user_id=user_id,
127
+ user_name=user_name,
128
128
  )
129
129
  buffer = table_to_buffer(sample)
130
130
  return ParquetResponse(buffer.getvalue())
@@ -12,16 +12,22 @@ from pydantic import BaseModel, Field, SecretStr, field_validator, model_validat
12
12
  from pydantic_settings import BaseSettings, SettingsConfigDict
13
13
 
14
14
  from matchbox.common.dtos import (
15
+ BackendResourceType,
15
16
  Collection,
16
17
  CollectionName,
18
+ Group,
19
+ GroupName,
17
20
  Match,
18
21
  ModelResolutionPath,
22
+ PermissionGrant,
23
+ PermissionType,
19
24
  Resolution,
20
25
  ResolutionPath,
21
26
  Run,
22
27
  RunID,
23
28
  SourceResolutionPath,
24
29
  UploadStage,
30
+ User,
25
31
  )
26
32
  from matchbox.common.eval import Judgement, ModelComparison
27
33
  from matchbox.common.logging import LogLevelType
@@ -32,6 +38,25 @@ else:
32
38
  S3Client = Any
33
39
 
34
40
 
41
+ PERMISSION_GRANTS: dict[PermissionType, list[PermissionType]] = {
42
+ PermissionType.READ: [
43
+ PermissionType.READ,
44
+ PermissionType.WRITE,
45
+ PermissionType.ADMIN,
46
+ ],
47
+ PermissionType.WRITE: [PermissionType.WRITE, PermissionType.ADMIN],
48
+ PermissionType.ADMIN: [PermissionType.ADMIN],
49
+ }
50
+ """A global variable that defines the permission hierarchy.
51
+
52
+ Keys are the permission, values are a list of permissions that would
53
+ grant the permission.
54
+
55
+ For example, only `PermissionType.ADMIN` can grant `PermissionType.ADMIN`,
56
+ but any permission implies `PermissionType.READ`.
57
+ """
58
+
59
+
35
60
  class MatchboxBackends(StrEnum):
36
61
  """The available backends for Matchbox."""
37
62
 
@@ -584,12 +609,153 @@ class MatchboxDBAdapter(ABC):
584
609
  Orphan clusters are clusters recorded in the Clusters table but that are
585
610
  not referenced in other tables.
586
611
  """
612
+ ...
613
+
614
+ # User, group and permissions management
615
+
616
+ @abstractmethod
617
+ def login(self, user: User) -> User:
618
+ """Upserts the user to the database.
619
+
620
+ Args:
621
+ user: A User with a username and optionally an email
622
+ """
623
+ ...
624
+
625
+ @abstractmethod
626
+ def get_user_groups(self, user_name: str) -> list[GroupName]:
627
+ """Get names of all groups a user belongs to.
628
+
629
+ Args:
630
+ user_name: The username to get the groups of
631
+ """
632
+ ...
633
+
634
+ @abstractmethod
635
+ def list_groups(self) -> list[Group]:
636
+ """List all groups."""
637
+ ...
638
+
639
+ @abstractmethod
640
+ def get_group(self, name: GroupName) -> Group:
641
+ """Get group details including members.
642
+
643
+ Args:
644
+ name: The name of the group to fetch.
645
+
646
+ Raises:
647
+ MatchboxGroupNotFoundError: If group doesn't exist.
648
+ """
649
+ ...
650
+
651
+ @abstractmethod
652
+ def create_group(self, group: Group) -> None:
653
+ """Create a new group.
654
+
655
+ Arg:
656
+ group: The group to create
657
+
658
+ Raises:
659
+ MatchboxGroupAlreadyExistsError: If group name taken.
660
+ """
661
+ ...
662
+
663
+ @abstractmethod
664
+ def delete_group(self, name: GroupName, certain: bool = False) -> None:
665
+ """Delete a group.
666
+
667
+ Args:
668
+ name: The name of the group to delete
669
+ certain: Whether to delete the group without confirmation.
670
+
671
+ Raises:
672
+ MatchboxGroupNotFoundError: If group doesn't exist.
673
+ MatchboxSystemGroupError: If attempting to delete a system group.
674
+ MatchboxDeletionNotConfirmed: If certain=False.
675
+ """
676
+ ...
677
+
678
+ @abstractmethod
679
+ def add_user_to_group(self, user_name: str, group_name: GroupName) -> None:
680
+ """Add a user to a group. Creates user if they don't exist.
681
+
682
+ Raises:
683
+ MatchboxGroupNotFoundError: If group doesn't exist.
684
+ """
685
+ ...
686
+
687
+ @abstractmethod
688
+ def remove_user_from_group(self, user_name: str, group_name: GroupName) -> None:
689
+ """Remove a user from a group.
690
+
691
+ Raises:
692
+ MatchboxGroupNotFoundError: If group doesn't exist.
693
+ MatchboxUserNotFoundError: If user doesn't exist.
694
+ """
695
+ ...
696
+
697
+ @abstractmethod
698
+ def check_permission(
699
+ self,
700
+ user_name: str,
701
+ permission: PermissionType,
702
+ resource: Literal[BackendResourceType.SYSTEM] | CollectionName,
703
+ ) -> bool:
704
+ """Check user permission against a resource.
705
+
706
+ Args:
707
+ user_name: The username to check.
708
+ permission: The permission type to check
709
+ resource: The resource to check. One of "system" or a collection name
710
+ """
711
+ ...
712
+
713
+ @abstractmethod
714
+ def get_permissions(
715
+ self,
716
+ resource: Literal[BackendResourceType.SYSTEM] | CollectionName,
717
+ ) -> list[PermissionGrant]:
718
+ """Get all granted permissions against a resource.
719
+
720
+ Args:
721
+ resource: The resource to get permissions for. One of "system" or a
722
+ collection name
723
+ """
724
+ ...
587
725
 
588
- # User management
726
+ @abstractmethod
727
+ def grant_permission(
728
+ self,
729
+ group_name: GroupName,
730
+ permission: PermissionType,
731
+ resource: Literal[BackendResourceType.SYSTEM] | CollectionName,
732
+ ) -> None:
733
+ """Grants a permission on a resource.
734
+
735
+ Args:
736
+ group_name: The name of the group to grant permission to
737
+ permission: The permission to grant
738
+ resource: The resource to grant permission on. One of "system" or a
739
+ collection name
740
+ """
741
+ ...
589
742
 
590
743
  @abstractmethod
591
- def login(self, user_name: str) -> int:
592
- """Receives a user name and returns user ID."""
744
+ def revoke_permission(
745
+ self,
746
+ group_name: GroupName,
747
+ permission: PermissionType,
748
+ resource: Literal[BackendResourceType.SYSTEM] | CollectionName,
749
+ ) -> None:
750
+ """Revoke permission on a resource.
751
+
752
+ Args:
753
+ group_name: The name of the group to revoke permission of
754
+ permission: The permission to revoke
755
+ resource: The resource to revoke permission from. One of "system" or a
756
+ collection name
757
+ """
758
+ ...
593
759
 
594
760
  # Evaluation management
595
761
 
@@ -625,13 +791,15 @@ class MatchboxDBAdapter(ABC):
625
791
  ...
626
792
 
627
793
  @abstractmethod
628
- def sample_for_eval(self, n: int, path: ModelResolutionPath, user_id: int) -> Table:
794
+ def sample_for_eval(
795
+ self, n: int, path: ModelResolutionPath, user_name: str
796
+ ) -> Table:
629
797
  """Sample a cluster to validate.
630
798
 
631
799
  Args:
632
800
  n: Number of clusters to sample
633
801
  path: Path of resolution from which to sample
634
- user_id: ID of user requesting the sample
802
+ user_name: Name of user requesting the sample
635
803
 
636
804
  Returns:
637
805
  An Arrow table with the same schema as returned by `query()`