sift-stack-py 0.17.0.dev0__tar.gz → 0.17.0.dev1__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 (578) hide show
  1. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/PKG-INFO +1 -1
  2. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/grpc_transport/transport.py +5 -20
  3. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/rest.py +2 -2
  4. sift_stack_py-0.17.0.dev1/lib/sift_client/_internal/urls.py +55 -0
  5. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/client.py +27 -0
  6. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/pytest_plugin.py +340 -0
  7. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/test_report.py +32 -0
  8. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/transport/base_connection.py +6 -0
  9. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/util/test_results/context_manager.py +56 -4
  10. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_stack_py.egg-info/PKG-INFO +1 -1
  11. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_stack_py.egg-info/SOURCES.txt +1 -0
  12. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/pyproject.toml +1 -1
  13. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/LICENSE +0 -0
  14. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/README.md +0 -0
  15. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/__init__.py +0 -0
  16. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/annotation_logs/__init__.py +0 -0
  17. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/annotation_logs/v1/__init__.py +0 -0
  18. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/annotation_logs/v1/annotation_logs_pb2.py +0 -0
  19. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/annotation_logs/v1/annotation_logs_pb2.pyi +0 -0
  20. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/annotation_logs/v1/annotation_logs_pb2_grpc.py +0 -0
  21. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/annotation_logs/v1/annotation_logs_pb2_grpc.pyi +0 -0
  22. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/annotations/__init__.py +0 -0
  23. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/annotations/v1/__init__.py +0 -0
  24. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/annotations/v1/annotations_pb2.py +0 -0
  25. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/annotations/v1/annotations_pb2.pyi +0 -0
  26. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/annotations/v1/annotations_pb2_grpc.py +0 -0
  27. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/annotations/v1/annotations_pb2_grpc.pyi +0 -0
  28. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/api_keys/__init__.py +0 -0
  29. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/api_keys/v2/__init__.py +0 -0
  30. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/api_keys/v2/api_keys_pb2.py +0 -0
  31. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/api_keys/v2/api_keys_pb2.pyi +0 -0
  32. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/api_keys/v2/api_keys_pb2_grpc.py +0 -0
  33. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/api_keys/v2/api_keys_pb2_grpc.pyi +0 -0
  34. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/assets/__init__.py +0 -0
  35. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/assets/v1/__init__.py +0 -0
  36. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/assets/v1/assets_pb2.py +0 -0
  37. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/assets/v1/assets_pb2.pyi +0 -0
  38. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/assets/v1/assets_pb2_grpc.py +0 -0
  39. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/assets/v1/assets_pb2_grpc.pyi +0 -0
  40. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/calculated_channels/__init__.py +0 -0
  41. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/calculated_channels/v1/__init__.py +0 -0
  42. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/calculated_channels/v1/calculated_channels_pb2.py +0 -0
  43. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/calculated_channels/v1/calculated_channels_pb2.pyi +0 -0
  44. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/calculated_channels/v1/calculated_channels_pb2_grpc.py +0 -0
  45. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/calculated_channels/v1/calculated_channels_pb2_grpc.pyi +0 -0
  46. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/calculated_channels/v2/__init__.py +0 -0
  47. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/calculated_channels/v2/calculated_channels_pb2.py +0 -0
  48. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/calculated_channels/v2/calculated_channels_pb2.pyi +0 -0
  49. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/calculated_channels/v2/calculated_channels_pb2_grpc.py +0 -0
  50. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/calculated_channels/v2/calculated_channels_pb2_grpc.pyi +0 -0
  51. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/campaigns/__init__.py +0 -0
  52. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/campaigns/v1/__init__.py +0 -0
  53. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/campaigns/v1/campaigns_pb2.py +0 -0
  54. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/campaigns/v1/campaigns_pb2.pyi +0 -0
  55. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/campaigns/v1/campaigns_pb2_grpc.py +0 -0
  56. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/campaigns/v1/campaigns_pb2_grpc.pyi +0 -0
  57. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channel_schemas/__init__.py +0 -0
  58. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channel_schemas/v1/__init__.py +0 -0
  59. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channel_schemas/v1/channel_schemas_pb2.py +0 -0
  60. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channel_schemas/v1/channel_schemas_pb2.pyi +0 -0
  61. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channel_schemas/v1/channel_schemas_pb2_grpc.py +0 -0
  62. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channel_schemas/v1/channel_schemas_pb2_grpc.pyi +0 -0
  63. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channel_schemas/v2/__init__.py +0 -0
  64. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channel_schemas/v2/channel_schemas_pb2.py +0 -0
  65. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channel_schemas/v2/channel_schemas_pb2.pyi +0 -0
  66. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channel_schemas/v2/channel_schemas_pb2_grpc.py +0 -0
  67. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channel_schemas/v2/channel_schemas_pb2_grpc.pyi +0 -0
  68. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channels/__init__.py +0 -0
  69. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channels/v2/__init__.py +0 -0
  70. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channels/v2/channels_pb2.py +0 -0
  71. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channels/v2/channels_pb2.pyi +0 -0
  72. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channels/v2/channels_pb2_grpc.py +0 -0
  73. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channels/v2/channels_pb2_grpc.pyi +0 -0
  74. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channels/v3/__init__.py +0 -0
  75. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channels/v3/channels_pb2.py +0 -0
  76. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channels/v3/channels_pb2.pyi +0 -0
  77. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channels/v3/channels_pb2_grpc.py +0 -0
  78. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/channels/v3/channels_pb2_grpc.pyi +0 -0
  79. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/comment/__init__.py +0 -0
  80. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/comment/v1/__init__.py +0 -0
  81. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/comment/v1/comment_pb2.py +0 -0
  82. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/comment/v1/comment_pb2.pyi +0 -0
  83. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/comment/v1/comment_pb2_grpc.py +0 -0
  84. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/comment/v1/comment_pb2_grpc.pyi +0 -0
  85. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/__init__.py +0 -0
  86. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/__init__.py +0 -0
  87. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/__init__.py +0 -0
  88. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/calculated_channels_pb2.py +0 -0
  89. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/calculated_channels_pb2.pyi +0 -0
  90. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/calculated_channels_pb2_grpc.py +0 -0
  91. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/calculated_channels_pb2_grpc.pyi +0 -0
  92. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_bit_field_element_pb2.py +0 -0
  93. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_bit_field_element_pb2.pyi +0 -0
  94. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_bit_field_element_pb2_grpc.py +0 -0
  95. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_bit_field_element_pb2_grpc.pyi +0 -0
  96. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_config_pb2.py +0 -0
  97. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_config_pb2.pyi +0 -0
  98. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_config_pb2_grpc.py +0 -0
  99. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_config_pb2_grpc.pyi +0 -0
  100. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_data_type_pb2.py +0 -0
  101. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_data_type_pb2.pyi +0 -0
  102. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_data_type_pb2_grpc.py +0 -0
  103. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_data_type_pb2_grpc.pyi +0 -0
  104. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_enum_type_pb2.py +0 -0
  105. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_enum_type_pb2.pyi +0 -0
  106. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_enum_type_pb2_grpc.py +0 -0
  107. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/channel_enum_type_pb2_grpc.pyi +0 -0
  108. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/organization_pb2.py +0 -0
  109. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/organization_pb2.pyi +0 -0
  110. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/organization_pb2_grpc.py +0 -0
  111. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/organization_pb2_grpc.pyi +0 -0
  112. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/resource_identifier_pb2.py +0 -0
  113. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/resource_identifier_pb2.pyi +0 -0
  114. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/resource_identifier_pb2_grpc.py +0 -0
  115. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/resource_identifier_pb2_grpc.pyi +0 -0
  116. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/resource_ref_pb2.py +0 -0
  117. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/resource_ref_pb2.pyi +0 -0
  118. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/resource_ref_pb2_grpc.py +0 -0
  119. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/resource_ref_pb2_grpc.pyi +0 -0
  120. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/user_defined_functions_pb2.py +0 -0
  121. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/user_defined_functions_pb2.pyi +0 -0
  122. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/user_defined_functions_pb2_grpc.py +0 -0
  123. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/user_defined_functions_pb2_grpc.pyi +0 -0
  124. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/user_pb2.py +0 -0
  125. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/user_pb2.pyi +0 -0
  126. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/user_pb2_grpc.py +0 -0
  127. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/type/v1/user_pb2_grpc.pyi +0 -0
  128. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/v1/__init__.py +0 -0
  129. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/v1/action_type_pb2.py +0 -0
  130. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/v1/action_type_pb2.pyi +0 -0
  131. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/v1/action_type_pb2_grpc.py +0 -0
  132. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/v1/action_type_pb2_grpc.pyi +0 -0
  133. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/v1/filter_field_pb2.py +0 -0
  134. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/v1/filter_field_pb2.pyi +0 -0
  135. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/v1/filter_field_pb2_grpc.py +0 -0
  136. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/v1/filter_field_pb2_grpc.pyi +0 -0
  137. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/v1/resource_type_pb2.py +0 -0
  138. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/v1/resource_type_pb2.pyi +0 -0
  139. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/v1/resource_type_pb2_grpc.py +0 -0
  140. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/common/v1/resource_type_pb2_grpc.pyi +0 -0
  141. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data/__init__.py +0 -0
  142. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data/v1/__init__.py +0 -0
  143. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data/v1/data_pb2.py +0 -0
  144. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data/v1/data_pb2.pyi +0 -0
  145. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data/v1/data_pb2_grpc.py +0 -0
  146. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data/v1/data_pb2_grpc.pyi +0 -0
  147. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data/v2/__init__.py +0 -0
  148. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data/v2/data_pb2.py +0 -0
  149. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data/v2/data_pb2.pyi +0 -0
  150. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data/v2/data_pb2_grpc.py +0 -0
  151. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data/v2/data_pb2_grpc.pyi +0 -0
  152. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data_imports/__init__.py +0 -0
  153. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data_imports/v2/__init__.py +0 -0
  154. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data_imports/v2/data_imports_pb2.py +0 -0
  155. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data_imports/v2/data_imports_pb2.pyi +0 -0
  156. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data_imports/v2/data_imports_pb2_grpc.py +0 -0
  157. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/data_imports/v2/data_imports_pb2_grpc.pyi +0 -0
  158. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/dlq_errors/__init__.py +0 -0
  159. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/dlq_errors/v2/__init__.py +0 -0
  160. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/dlq_errors/v2/dlq_errors_pb2.py +0 -0
  161. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/dlq_errors/v2/dlq_errors_pb2.pyi +0 -0
  162. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/dlq_errors/v2/dlq_errors_pb2_grpc.py +0 -0
  163. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/dlq_errors/v2/dlq_errors_pb2_grpc.pyi +0 -0
  164. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/exports/__init__.py +0 -0
  165. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/exports/v1/__init__.py +0 -0
  166. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/exports/v1/exports_pb2.py +0 -0
  167. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/exports/v1/exports_pb2.pyi +0 -0
  168. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/exports/v1/exports_pb2_grpc.py +0 -0
  169. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/exports/v1/exports_pb2_grpc.pyi +0 -0
  170. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/external_sync/__init__.py +0 -0
  171. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/external_sync/v1/__init__.py +0 -0
  172. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/external_sync/v1/external_sync_pb2.py +0 -0
  173. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/external_sync/v1/external_sync_pb2.pyi +0 -0
  174. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/external_sync/v1/external_sync_pb2_grpc.py +0 -0
  175. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/external_sync/v1/external_sync_pb2_grpc.pyi +0 -0
  176. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingest/__init__.py +0 -0
  177. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingest/v1/__init__.py +0 -0
  178. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingest/v1/ingest_pb2.py +0 -0
  179. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingest/v1/ingest_pb2.pyi +0 -0
  180. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingest/v1/ingest_pb2_grpc.py +0 -0
  181. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingest/v1/ingest_pb2_grpc.pyi +0 -0
  182. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingestion_configs/__init__.py +0 -0
  183. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingestion_configs/v1/__init__.py +0 -0
  184. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingestion_configs/v1/ingestion_configs_pb2.py +0 -0
  185. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingestion_configs/v1/ingestion_configs_pb2.pyi +0 -0
  186. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingestion_configs/v1/ingestion_configs_pb2_grpc.py +0 -0
  187. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingestion_configs/v1/ingestion_configs_pb2_grpc.pyi +0 -0
  188. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingestion_configs/v2/__init__.py +0 -0
  189. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingestion_configs/v2/ingestion_configs_pb2.py +0 -0
  190. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingestion_configs/v2/ingestion_configs_pb2.pyi +0 -0
  191. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingestion_configs/v2/ingestion_configs_pb2_grpc.py +0 -0
  192. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ingestion_configs/v2/ingestion_configs_pb2_grpc.pyi +0 -0
  193. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/jobs/__init__.py +0 -0
  194. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/jobs/v1/__init__.py +0 -0
  195. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/jobs/v1/jobs_pb2.py +0 -0
  196. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/jobs/v1/jobs_pb2.pyi +0 -0
  197. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/jobs/v1/jobs_pb2_grpc.py +0 -0
  198. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/jobs/v1/jobs_pb2_grpc.pyi +0 -0
  199. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/me/__init__.py +0 -0
  200. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/me/v2/__init__.py +0 -0
  201. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/me/v2/me_pb2.py +0 -0
  202. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/me/v2/me_pb2.pyi +0 -0
  203. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/me/v2/me_pb2_grpc.py +0 -0
  204. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/me/v2/me_pb2_grpc.pyi +0 -0
  205. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/metadata/__init__.py +0 -0
  206. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/metadata/v1/__init__.py +0 -0
  207. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/metadata/v1/metadata_pb2.py +0 -0
  208. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/metadata/v1/metadata_pb2.pyi +0 -0
  209. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/metadata/v1/metadata_pb2_grpc.py +0 -0
  210. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/metadata/v1/metadata_pb2_grpc.pyi +0 -0
  211. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/notifications/__init__.py +0 -0
  212. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/notifications/v1/__init__.py +0 -0
  213. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/notifications/v1/notifications_pb2.py +0 -0
  214. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/notifications/v1/notifications_pb2.pyi +0 -0
  215. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/notifications/v1/notifications_pb2_grpc.py +0 -0
  216. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/notifications/v1/notifications_pb2_grpc.pyi +0 -0
  217. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/panel_configurations/__init__.py +0 -0
  218. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/panel_configurations/v1/__init__.py +0 -0
  219. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/panel_configurations/v1/panel_configuration_pb2.py +0 -0
  220. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/panel_configurations/v1/panel_configuration_pb2.pyi +0 -0
  221. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/panel_configurations/v1/panel_configuration_pb2_grpc.py +0 -0
  222. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/panel_configurations/v1/panel_configuration_pb2_grpc.pyi +0 -0
  223. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ping/__init__.py +0 -0
  224. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ping/v1/__init__.py +0 -0
  225. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ping/v1/ping_pb2.py +0 -0
  226. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ping/v1/ping_pb2.pyi +0 -0
  227. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ping/v1/ping_pb2_grpc.py +0 -0
  228. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/ping/v1/ping_pb2_grpc.pyi +0 -0
  229. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/protobuf_descriptors/__init__.py +0 -0
  230. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/protobuf_descriptors/v2/__init__.py +0 -0
  231. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/protobuf_descriptors/v2/channel_parsing_options_pb2.py +0 -0
  232. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/protobuf_descriptors/v2/channel_parsing_options_pb2.pyi +0 -0
  233. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/protobuf_descriptors/v2/channel_parsing_options_pb2_grpc.py +0 -0
  234. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/protobuf_descriptors/v2/channel_parsing_options_pb2_grpc.pyi +0 -0
  235. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/protobuf_descriptors/v2/protobuf_descriptors_pb2.py +0 -0
  236. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/protobuf_descriptors/v2/protobuf_descriptors_pb2.pyi +0 -0
  237. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/protobuf_descriptors/v2/protobuf_descriptors_pb2_grpc.py +0 -0
  238. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/protobuf_descriptors/v2/protobuf_descriptors_pb2_grpc.pyi +0 -0
  239. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/py.typed +0 -0
  240. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/remote_files/__init__.py +0 -0
  241. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/remote_files/v1/__init__.py +0 -0
  242. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/remote_files/v1/remote_files_pb2.py +0 -0
  243. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/remote_files/v1/remote_files_pb2.pyi +0 -0
  244. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/remote_files/v1/remote_files_pb2_grpc.py +0 -0
  245. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/remote_files/v1/remote_files_pb2_grpc.pyi +0 -0
  246. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/report_templates/__init__.py +0 -0
  247. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/report_templates/v1/__init__.py +0 -0
  248. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/report_templates/v1/report_templates_pb2.py +0 -0
  249. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/report_templates/v1/report_templates_pb2.pyi +0 -0
  250. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/report_templates/v1/report_templates_pb2_grpc.py +0 -0
  251. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/report_templates/v1/report_templates_pb2_grpc.pyi +0 -0
  252. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/reports/__init__.py +0 -0
  253. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/reports/v1/__init__.py +0 -0
  254. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/reports/v1/reports_pb2.py +0 -0
  255. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/reports/v1/reports_pb2.pyi +0 -0
  256. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/reports/v1/reports_pb2_grpc.py +0 -0
  257. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/reports/v1/reports_pb2_grpc.pyi +0 -0
  258. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/roles/__init__.py +0 -0
  259. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/roles/v2/__init__.py +0 -0
  260. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/roles/v2/roles_pb2.py +0 -0
  261. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/roles/v2/roles_pb2.pyi +0 -0
  262. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/roles/v2/roles_pb2_grpc.py +0 -0
  263. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/roles/v2/roles_pb2_grpc.pyi +0 -0
  264. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/rule_evaluation/__init__.py +0 -0
  265. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/rule_evaluation/v1/__init__.py +0 -0
  266. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/rule_evaluation/v1/rule_evaluation_pb2.py +0 -0
  267. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/rule_evaluation/v1/rule_evaluation_pb2.pyi +0 -0
  268. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/rule_evaluation/v1/rule_evaluation_pb2_grpc.py +0 -0
  269. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/rule_evaluation/v1/rule_evaluation_pb2_grpc.pyi +0 -0
  270. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/rules/__init__.py +0 -0
  271. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/rules/v1/__init__.py +0 -0
  272. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/rules/v1/rules_pb2.py +0 -0
  273. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/rules/v1/rules_pb2.pyi +0 -0
  274. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/rules/v1/rules_pb2_grpc.py +0 -0
  275. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/rules/v1/rules_pb2_grpc.pyi +0 -0
  276. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/runs/__init__.py +0 -0
  277. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/runs/v2/__init__.py +0 -0
  278. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/runs/v2/runs_pb2.py +0 -0
  279. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/runs/v2/runs_pb2.pyi +0 -0
  280. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/runs/v2/runs_pb2_grpc.py +0 -0
  281. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/runs/v2/runs_pb2_grpc.pyi +0 -0
  282. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/saved_searches/__init__.py +0 -0
  283. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/saved_searches/v1/__init__.py +0 -0
  284. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/saved_searches/v1/saved_searches_pb2.py +0 -0
  285. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/saved_searches/v1/saved_searches_pb2.pyi +0 -0
  286. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/saved_searches/v1/saved_searches_pb2_grpc.py +0 -0
  287. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/saved_searches/v1/saved_searches_pb2_grpc.pyi +0 -0
  288. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/tags/__init__.py +0 -0
  289. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/tags/v1/__init__.py +0 -0
  290. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/tags/v1/tags_pb2.py +0 -0
  291. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/tags/v1/tags_pb2.pyi +0 -0
  292. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/tags/v1/tags_pb2_grpc.py +0 -0
  293. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/tags/v1/tags_pb2_grpc.pyi +0 -0
  294. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/tags/v2/__init__.py +0 -0
  295. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/tags/v2/tags_pb2.py +0 -0
  296. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/tags/v2/tags_pb2.pyi +0 -0
  297. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/tags/v2/tags_pb2_grpc.py +0 -0
  298. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/tags/v2/tags_pb2_grpc.pyi +0 -0
  299. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/test_reports/__init__.py +0 -0
  300. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/test_reports/v1/__init__.py +0 -0
  301. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/test_reports/v1/test_reports_pb2.py +0 -0
  302. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/test_reports/v1/test_reports_pb2.pyi +0 -0
  303. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/test_reports/v1/test_reports_pb2_grpc.py +0 -0
  304. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/test_reports/v1/test_reports_pb2_grpc.pyi +0 -0
  305. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/unit/__init__.py +0 -0
  306. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/unit/v2/__init__.py +0 -0
  307. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/unit/v2/unit_pb2.py +0 -0
  308. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/unit/v2/unit_pb2.pyi +0 -0
  309. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/unit/v2/unit_pb2_grpc.py +0 -0
  310. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/unit/v2/unit_pb2_grpc.pyi +0 -0
  311. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/user_defined_functions/__init__.py +0 -0
  312. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/user_defined_functions/v1/__init__.py +0 -0
  313. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/user_defined_functions/v1/user_defined_functions_pb2.py +0 -0
  314. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/user_defined_functions/v1/user_defined_functions_pb2.pyi +0 -0
  315. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/user_defined_functions/v1/user_defined_functions_pb2_grpc.py +0 -0
  316. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/user_defined_functions/v1/user_defined_functions_pb2_grpc.pyi +0 -0
  317. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/user_groups/__init__.py +0 -0
  318. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/user_groups/v2/__init__.py +0 -0
  319. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/user_groups/v2/user_groups_pb2.py +0 -0
  320. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/user_groups/v2/user_groups_pb2.pyi +0 -0
  321. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/user_groups/v2/user_groups_pb2_grpc.py +0 -0
  322. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/user_groups/v2/user_groups_pb2_grpc.pyi +0 -0
  323. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/users/__init__.py +0 -0
  324. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/users/v2/__init__.py +0 -0
  325. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/users/v2/users_pb2.py +0 -0
  326. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/users/v2/users_pb2.pyi +0 -0
  327. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/users/v2/users_pb2_grpc.py +0 -0
  328. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/users/v2/users_pb2_grpc.pyi +0 -0
  329. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/views/__init__.py +0 -0
  330. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/views/v1/__init__.py +0 -0
  331. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/views/v1/views_pb2.py +0 -0
  332. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/views/v1/views_pb2.pyi +0 -0
  333. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/views/v1/views_pb2_grpc.py +0 -0
  334. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/views/v1/views_pb2_grpc.pyi +0 -0
  335. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/views/v2/__init__.py +0 -0
  336. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/views/v2/views_pb2.py +0 -0
  337. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/views/v2/views_pb2.pyi +0 -0
  338. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/views/v2/views_pb2_grpc.py +0 -0
  339. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/views/v2/views_pb2_grpc.pyi +0 -0
  340. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/webhooks/__init__.py +0 -0
  341. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/webhooks/v1/__init__.py +0 -0
  342. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/webhooks/v1/webhooks_pb2.py +0 -0
  343. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/webhooks/v1/webhooks_pb2.pyi +0 -0
  344. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/webhooks/v1/webhooks_pb2_grpc.py +0 -0
  345. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift/webhooks/v1/webhooks_pb2_grpc.pyi +0 -0
  346. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/__init__.py +0 -0
  347. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/__init__.py +0 -0
  348. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/gen_pyi.py +0 -0
  349. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/grpc_transport/__init__.py +0 -0
  350. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/grpc_transport/_async_interceptors/__init__.py +0 -0
  351. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/grpc_transport/_async_interceptors/base.py +0 -0
  352. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/grpc_transport/_async_interceptors/metadata.py +0 -0
  353. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/grpc_transport/_interceptors/__init__.py +0 -0
  354. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/grpc_transport/_interceptors/base.py +0 -0
  355. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/grpc_transport/_interceptors/context.py +0 -0
  356. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/grpc_transport/_interceptors/metadata.py +0 -0
  357. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/grpc_transport/_retry.py +0 -0
  358. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/grpc_transport/keepalive.py +0 -0
  359. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/grpc_transport/server_interceptors/__init__.py +0 -0
  360. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/grpc_transport/server_interceptors/server_interceptor.py +0 -0
  361. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/grpc_transport/transport_test.py +0 -0
  362. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/__init__.py +0 -0
  363. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/_test_results_log.py +0 -0
  364. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/assets.py +0 -0
  365. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/base.py +0 -0
  366. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/calculated_channels.py +0 -0
  367. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/channels.py +0 -0
  368. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/data.py +0 -0
  369. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/data_imports.py +0 -0
  370. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/exports.py +0 -0
  371. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/ingestion.py +0 -0
  372. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/jobs.py +0 -0
  373. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/ping.py +0 -0
  374. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/remote_files.py +0 -0
  375. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/reports.py +0 -0
  376. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/rules.py +0 -0
  377. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/runs.py +0 -0
  378. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/tags.py +0 -0
  379. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/test_results.py +0 -0
  380. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/low_level_wrappers/upload.py +0 -0
  381. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/sync_wrapper.py +0 -0
  382. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/time.py +0 -0
  383. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/util/__init__.py +0 -0
  384. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/util/channels.py +0 -0
  385. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/util/executor.py +0 -0
  386. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/util/file.py +0 -0
  387. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/util/hdf5.py +0 -0
  388. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/util/numpy_types.py +0 -0
  389. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/util/tdms.py +0 -0
  390. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/util/timestamp.py +0 -0
  391. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/_internal/util/util.py +0 -0
  392. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/config.py +0 -0
  393. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/errors.py +0 -0
  394. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/py.typed +0 -0
  395. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/__init__.py +0 -0
  396. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/_base.py +0 -0
  397. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/assets.py +0 -0
  398. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/calculated_channels.py +0 -0
  399. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/channels.py +0 -0
  400. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/data_imports.py +0 -0
  401. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/exports.py +0 -0
  402. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/file_attachments.py +0 -0
  403. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/ingestion.py +0 -0
  404. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/jobs.py +0 -0
  405. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/ping.py +0 -0
  406. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/py.typed +0 -0
  407. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/reports.py +0 -0
  408. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/rules.py +0 -0
  409. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/runs.py +0 -0
  410. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/sync_stubs/__init__.py +0 -0
  411. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/sync_stubs/__init__.pyi +0 -0
  412. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/sync_stubs/py.typed +0 -0
  413. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/tags.py +0 -0
  414. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/resources/test_results.py +0 -0
  415. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/scripts/__init__.py +0 -0
  416. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/scripts/import_test_result_log.py +0 -0
  417. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/__init__.py +0 -0
  418. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/_base.py +0 -0
  419. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/_mixins/__init__.py +0 -0
  420. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/_mixins/file_attachments.py +0 -0
  421. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/_mixins/simulated.py +0 -0
  422. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/asset.py +0 -0
  423. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/calculated_channel.py +0 -0
  424. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/channel.py +0 -0
  425. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/data_import.py +0 -0
  426. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/export.py +0 -0
  427. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/file_attachment.py +0 -0
  428. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/ingestion.py +0 -0
  429. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/job.py +0 -0
  430. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/report.py +0 -0
  431. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/rule.py +0 -0
  432. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/run.py +0 -0
  433. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/sift_types/tag.py +0 -0
  434. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/transport/__init__.py +0 -0
  435. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/transport/grpc_transport.py +0 -0
  436. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/transport/rest_transport.py +0 -0
  437. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/util/__init__.py +0 -0
  438. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/util/cel_utils.py +0 -0
  439. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/util/metadata.py +0 -0
  440. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/util/test_results/__init__.py +0 -0
  441. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/util/test_results/bounds.py +0 -0
  442. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_client/util/util.py +0 -0
  443. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/__init__.py +0 -0
  444. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_internal/__init__.py +0 -0
  445. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_internal/cel.py +0 -0
  446. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_internal/channel.py +0 -0
  447. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_internal/convert/__init__.py +0 -0
  448. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_internal/convert/json.py +0 -0
  449. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_internal/convert/protobuf.py +0 -0
  450. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_internal/convert/timestamp.py +0 -0
  451. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_internal/metadata.py +0 -0
  452. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_internal/metadata_test.py +0 -0
  453. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_internal/test_util/__init__.py +0 -0
  454. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_internal/test_util/channel.py +0 -0
  455. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_internal/test_util/fn.py +0 -0
  456. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_internal/test_util/server_interceptor.py +0 -0
  457. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_internal/time.py +0 -0
  458. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_internal/user.py +0 -0
  459. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/_rest_test.py +0 -0
  460. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/asset/__init__.py +0 -0
  461. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/asset/_config_test.py +0 -0
  462. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/asset/_internal/shared.py +0 -0
  463. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/asset/_service_test.py +0 -0
  464. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/asset/config.py +0 -0
  465. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/asset/service.py +0 -0
  466. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/calculated_channels/__init__.py +0 -0
  467. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/calculated_channels/_service_test.py +0 -0
  468. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/calculated_channels/config.py +0 -0
  469. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/calculated_channels/service.py +0 -0
  470. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data/__init__.py +0 -0
  471. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data/_channel.py +0 -0
  472. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data/_deserialize.py +0 -0
  473. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data/_deserialize_test.py +0 -0
  474. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data/_service_test.py +0 -0
  475. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data/_validate.py +0 -0
  476. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data/error.py +0 -0
  477. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data/query.py +0 -0
  478. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data/service.py +0 -0
  479. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/__init__.py +0 -0
  480. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/_config.py +0 -0
  481. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/_config_test.py +0 -0
  482. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/_csv_test.py +0 -0
  483. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/_hdf5_test.py +0 -0
  484. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/_parquet_test.py +0 -0
  485. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/_ros_channel.py +0 -0
  486. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/_rosbag_test.py +0 -0
  487. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/_status_test.py +0 -0
  488. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/_tdms_test.py +0 -0
  489. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/_utils.py +0 -0
  490. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/_utils_test.py +0 -0
  491. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/ch10.py +0 -0
  492. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/config.py +0 -0
  493. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/csv.py +0 -0
  494. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/hdf5.py +0 -0
  495. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/parquet.py +0 -0
  496. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/parquet_complex_types.py +0 -0
  497. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/rosbags.py +0 -0
  498. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/status.py +0 -0
  499. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/tdms.py +0 -0
  500. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/tempfile.py +0 -0
  501. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/data_import/time_format.py +0 -0
  502. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/error.py +0 -0
  503. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/file_attachment/__init__.py +0 -0
  504. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/file_attachment/_internal/__init__.py +0 -0
  505. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/file_attachment/_internal/download.py +0 -0
  506. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/file_attachment/_internal/upload.py +0 -0
  507. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/file_attachment/_service_test.py +0 -0
  508. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/file_attachment/entity.py +0 -0
  509. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/file_attachment/metadata.py +0 -0
  510. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/file_attachment/service.py +0 -0
  511. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/grpc/__init__.py +0 -0
  512. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/grpc/_async_interceptors/__init__.py +0 -0
  513. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/grpc/_async_interceptors/base.py +0 -0
  514. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/grpc/_async_interceptors/metadata.py +0 -0
  515. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/grpc/_interceptors/__init__.py +0 -0
  516. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/grpc/_interceptors/base.py +0 -0
  517. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/grpc/_interceptors/context.py +0 -0
  518. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/grpc/_interceptors/metadata.py +0 -0
  519. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/grpc/_retry.py +0 -0
  520. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/grpc/keepalive.py +0 -0
  521. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/grpc/transport.py +0 -0
  522. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/grpc/transport_test.py +0 -0
  523. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/__init__.py +0 -0
  524. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/_internal/__init__.py +0 -0
  525. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/_internal/channel.py +0 -0
  526. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/_internal/error.py +0 -0
  527. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/_internal/ingest.py +0 -0
  528. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/_internal/ingest_test.py +0 -0
  529. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/_internal/ingestion_config.py +0 -0
  530. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/_internal/run.py +0 -0
  531. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/_service_test.py +0 -0
  532. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/buffer.py +0 -0
  533. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/channel.py +0 -0
  534. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/config/__init__.py +0 -0
  535. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/config/_telemetry_test.py +0 -0
  536. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/config/telemetry.py +0 -0
  537. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/config/yaml/__init__.py +0 -0
  538. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/config/yaml/error.py +0 -0
  539. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/config/yaml/load.py +0 -0
  540. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/config/yaml/spec.py +0 -0
  541. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/config/yaml/test_load.py +0 -0
  542. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/flow.py +0 -0
  543. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/manager.py +0 -0
  544. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/rule/__init__.py +0 -0
  545. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/rule/config.py +0 -0
  546. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/ingestion/service.py +0 -0
  547. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/py.typed +0 -0
  548. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/report/_report_test.py +0 -0
  549. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/report/service.py +0 -0
  550. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/report_templates/__init__.py +0 -0
  551. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/report_templates/_config_test.py +0 -0
  552. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/report_templates/_service_test.py +0 -0
  553. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/report_templates/config.py +0 -0
  554. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/report_templates/service.py +0 -0
  555. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/rest.py +0 -0
  556. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/rule/__init__.py +0 -0
  557. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/rule/_config_test.py +0 -0
  558. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/rule/_service_test.py +0 -0
  559. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/rule/config.py +0 -0
  560. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/rule/service.py +0 -0
  561. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/rule_evaluation/_service_test.py +0 -0
  562. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/rule_evaluation/service.py +0 -0
  563. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/tag/_internal/shared.py +0 -0
  564. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/yaml/__init__.py +0 -0
  565. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/yaml/_channel_test.py +0 -0
  566. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/yaml/_rule_test.py +0 -0
  567. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/yaml/_utils_test.py +0 -0
  568. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/yaml/calculated_channels.py +0 -0
  569. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/yaml/channel.py +0 -0
  570. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/yaml/report_templates.py +0 -0
  571. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/yaml/rule.py +0 -0
  572. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_py/yaml/utils.py +0 -0
  573. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_stack_py.egg-info/dependency_links.txt +0 -0
  574. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_stack_py.egg-info/entry_points.txt +0 -0
  575. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_stack_py.egg-info/requires.txt +0 -0
  576. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/lib/sift_stack_py.egg-info/top_level.txt +0 -0
  577. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/setup.cfg +0 -0
  578. {sift_stack_py-0.17.0.dev0 → sift_stack_py-0.17.0.dev1}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sift_stack_py
3
- Version: 0.17.0.dev0
3
+ Version: 0.17.0.dev1
4
4
  Summary: Python client library for the Sift API
5
5
  Maintainer-email: Sift Software Engineers <engineering@siftstack.com>
6
6
  License: Copyright (c) 2024 Azimuth Industries Inc.
@@ -8,7 +8,6 @@ from __future__ import annotations
8
8
 
9
9
  from importlib.metadata import PackageNotFoundError, version
10
10
  from typing import TYPE_CHECKING, Any, TypedDict, cast
11
- from urllib.parse import ParseResult, urlparse
12
11
 
13
12
  import grpc
14
13
  import grpc.aio as grpc_aio
@@ -21,6 +20,7 @@ from sift_client._internal.grpc_transport._interceptors.metadata import (
21
20
  Metadata,
22
21
  MetadataInterceptor,
23
22
  )
23
+ from sift_client._internal.urls import parse_host
24
24
 
25
25
  if TYPE_CHECKING:
26
26
  from sift_client._internal.grpc_transport._async_interceptors.base import ClientAsyncInterceptor
@@ -78,7 +78,7 @@ def use_sift_channel(
78
78
 
79
79
  credentials = get_ssl_credentials(cert_via_openssl)
80
80
  options = _compute_channel_options(config)
81
- api_uri = _clean_uri(config["uri"], use_ssl)
81
+ api_uri = parse_host(config["uri"])
82
82
  channel = grpc.secure_channel(api_uri, credentials, options)
83
83
  interceptors = _compute_sift_interceptors(config, metadata)
84
84
  return grpc.intercept_channel(channel, *interceptors)
@@ -98,7 +98,7 @@ def use_sift_async_channel(
98
98
  return _use_insecure_sift_async_channel(config, metadata)
99
99
 
100
100
  return grpc_aio.secure_channel(
101
- target=_clean_uri(config["uri"], use_ssl),
101
+ target=parse_host(config["uri"]),
102
102
  credentials=get_ssl_credentials(cert_via_openssl),
103
103
  options=_compute_channel_options(config),
104
104
  interceptors=_compute_sift_async_interceptors(config, metadata),
@@ -112,7 +112,7 @@ def _use_insecure_sift_channel(
112
112
  FOR DEVELOPMENT PURPOSES ONLY
113
113
  """
114
114
  options = _compute_channel_options(config)
115
- api_uri = _clean_uri(config["uri"], False)
115
+ api_uri = parse_host(config["uri"])
116
116
  channel = grpc.insecure_channel(api_uri, options)
117
117
  interceptors = _compute_sift_interceptors(config, metadata)
118
118
  return grpc.intercept_channel(channel, *interceptors)
@@ -125,7 +125,7 @@ def _use_insecure_sift_async_channel(
125
125
  FOR DEVELOPMENT PURPOSES ONLY
126
126
  """
127
127
  return grpc_aio.insecure_channel(
128
- target=_clean_uri(config["uri"], False),
128
+ target=parse_host(config["uri"]),
129
129
  options=_compute_channel_options(config),
130
130
  interceptors=_compute_sift_async_interceptors(config, metadata),
131
131
  )
@@ -205,21 +205,6 @@ def _metadata_async_interceptor(
205
205
  return MetadataAsyncInterceptor(md)
206
206
 
207
207
 
208
- def _clean_uri(uri: str, use_ssl: bool) -> str:
209
- """
210
- This will automatically transform the URI to an acceptable form regardless of whether or not
211
- users included the scheme in the URL or included trailing slashes.
212
- """
213
-
214
- if "http://" in uri or "https://" in uri:
215
- parsed: ParseResult = urlparse(uri)
216
- return parsed.netloc
217
-
218
- full_uri = f"https://{uri}" if use_ssl else f"http://{uri}"
219
- parsed_res: ParseResult = urlparse(full_uri)
220
- return parsed_res.netloc
221
-
222
-
223
208
  def _compute_user_agent() -> str:
224
209
  try:
225
210
  return f"sift_stack_py/{version('sift_stack_py')}"
@@ -6,7 +6,7 @@ from requests.adapters import HTTPAdapter
6
6
  from typing_extensions import NotRequired
7
7
  from urllib3.util import Retry
8
8
 
9
- from sift_client._internal.grpc_transport.transport import _clean_uri
9
+ from sift_client._internal.urls import parse_host
10
10
 
11
11
  _DEFAULT_REST_RETRY = Retry(total=3, status_forcelist=[500, 502, 503, 504], backoff_factor=1)
12
12
 
@@ -33,7 +33,7 @@ class SiftRestConfig(TypedDict):
33
33
  def compute_uri(restconf: SiftRestConfig) -> str:
34
34
  uri = restconf["uri"]
35
35
  use_ssl = restconf.get("use_ssl", True)
36
- clean_uri = _clean_uri(uri, use_ssl)
36
+ clean_uri = parse_host(uri)
37
37
 
38
38
  if use_ssl:
39
39
  return f"https://{clean_uri}"
@@ -0,0 +1,55 @@
1
+ """Helpers for turning Sift API endpoints into web-app (frontend) URLs.
2
+
3
+ The Sift frontend can be hosted on several domains and the backend exposes no
4
+ field for its own URL, so the frontend origin is derived client-side from the
5
+ API host. This table mirrors the canonical mapping used by the Grafana
6
+ datasource (sift-stack/sift-grafana-datasource,
7
+ ``src/components/sharelink/getFrontendHostnameDefaults.ts``). Hosts outside the
8
+ table (on-prem and custom deployments) require an explicit override.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from urllib.parse import urlparse
14
+
15
+ # API host (host[:port], no scheme) -> frontend origin (with scheme).
16
+ _API_HOST_TO_FRONTEND_ORIGIN: dict[str, str] = {
17
+ "api.siftstack.com": "https://app.siftstack.com",
18
+ "gov.api.siftstack.com": "https://gov.siftstack.com",
19
+ }
20
+
21
+
22
+ def parse_origin(url: str) -> str:
23
+ """Normalize a URL or bare host into a ``scheme://host[:port]`` origin.
24
+
25
+ Bare hosts (no scheme) are assumed to be ``https``.
26
+ """
27
+ candidate = url if "://" in url else f"https://{url}"
28
+ parsed = urlparse(candidate)
29
+ return f"{parsed.scheme}://{parsed.netloc}".rstrip("/")
30
+
31
+
32
+ def parse_host(url: str) -> str:
33
+ """Extract ``host[:port]`` from a URL or bare host string."""
34
+ candidate = url if "://" in url else f"https://{url}"
35
+ return urlparse(candidate).netloc
36
+
37
+
38
+ def frontend_origin_for_api(api_base_url: str, override: str | None = None) -> str | None:
39
+ """Return the Sift web-app origin for a given API base URL.
40
+
41
+ Args:
42
+ api_base_url: The REST API base URL (e.g. ``https://api.siftstack.com``).
43
+ override: An explicit frontend origin (host or full URL) to use instead
44
+ of the derived value. Set this for on-prem or custom deployments
45
+ whose API host isn't in the built-in mapping.
46
+
47
+ Returns:
48
+ The frontend origin (e.g. ``https://app.siftstack.com``), or ``None``
49
+ when no override is given and the API host isn't recognized.
50
+ """
51
+ if override:
52
+ return parse_origin(override)
53
+ if not api_base_url:
54
+ return None
55
+ return _API_HOST_TO_FRONTEND_ORIGIN.get(parse_host(api_base_url))
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from sift_client._internal.urls import frontend_origin_for_api
3
4
  from sift_client.resources import (
4
5
  AssetsAPI,
5
6
  AssetsAPIAsync,
@@ -124,6 +125,7 @@ class SiftClient(
124
125
  grpc_url: str | None = None,
125
126
  rest_url: str | None = None,
126
127
  connection_config: SiftConnectionConfig | None = None,
128
+ app_url: str | None = None,
127
129
  ):
128
130
  """Initialize the SiftClient with specific connection parameters or a connection_config.
129
131
 
@@ -132,6 +134,10 @@ class SiftClient(
132
134
  grpc_url: The Sift gRPC API URL.
133
135
  rest_url: The Sift REST API URL.
134
136
  connection_config: A SiftConnectionConfig object to configure the connection behavior of the SiftClient.
137
+ app_url: The Sift web-app origin (e.g. ``https://app.siftstack.com``).
138
+ Set this for on-prem or custom deployments whose API host can't be
139
+ mapped to a frontend automatically; see the ``app_url`` property.
140
+ A value here takes precedence over ``connection_config.app_url``.
135
141
  """
136
142
  if not (api_key and grpc_url and rest_url) and not connection_config:
137
143
  raise ValueError(
@@ -152,6 +158,12 @@ class SiftClient(
152
158
  WithGrpcClient.__init__(self, grpc_client=grpc_client)
153
159
  WithRestClient.__init__(self, rest_client=rest_client)
154
160
 
161
+ # Explicit web-app origin override; falls back to the connection config's
162
+ # value, then to host-based derivation in the ``app_url`` property.
163
+ self._app_url: str | None = app_url or (
164
+ connection_config.app_url if connection_config else None
165
+ )
166
+
155
167
  # When set, test-results writes return synthesized responses without
156
168
  # contacting Sift. Read by `TestResultsAPIAsync._simulate`. Used by the
157
169
  # pytest plugin's ``--sift-disabled`` mode.
@@ -198,3 +210,18 @@ class SiftClient(
198
210
  def rest_client(self) -> RestClient:
199
211
  """The REST client used by the SiftClient for making REST API calls."""
200
212
  return self._rest_client
213
+
214
+ @property
215
+ def app_url(self) -> str | None:
216
+ """The Sift web-app origin for this client, or None if it can't be determined.
217
+
218
+ Uses the explicit override passed at construction when set, otherwise
219
+ derives the origin from the REST host for known Sift deployments (e.g.
220
+ ``https://api.siftstack.com`` -> ``https://app.siftstack.com``). Returns
221
+ None for unrecognized hosts with no override.
222
+
223
+ # TODO: Add a ``WithAppPage`` mixin on BaseType so resources (TestReport,
224
+ # Run, ...) can expose their own web-app link from ``_client.app_url`` plus
225
+ # a per-type path, instead of callers assembling paths by hand.
226
+ """
227
+ return frontend_origin_for_api(self.rest_client.base_url, override=self._app_url)
@@ -15,6 +15,7 @@ from sift_client.errors import SiftWarning
15
15
  from sift_client.sift_types.test_report import ErrorInfo, TestStatus
16
16
  from sift_client.util.test_results import ReportContext
17
17
  from sift_client.util.test_results.context_manager import (
18
+ _quiet_fork_stderr,
18
19
  format_assertion_message,
19
20
  format_truncated_traceback,
20
21
  )
@@ -42,6 +43,12 @@ if TYPE_CHECKING:
42
43
 
43
44
  REPORT_CONTEXT: Any = None
44
45
 
46
+ # Set at session end with the resolved (real) report id/URL when online and
47
+ # uploaded. Read from a project's conftest in a later hook (e.g.
48
+ # ``pytest_unconfigure``) to post the link, write a file, etc.
49
+ SIFT_REPORT_ID_STASH_KEY = pytest.StashKey[str]()
50
+ SIFT_REPORT_URL_STASH_KEY = pytest.StashKey[str]()
51
+
45
52
  _STASH_MISSING = object()
46
53
 
47
54
  _PARAMETRIZE_PATH_KEY = pytest.StashKey[Tuple[str, ...]]()
@@ -297,6 +304,33 @@ _REST_URI = _Option(
297
304
  "this ini value.",
298
305
  )
299
306
 
307
+ _REPORT_URL_BASE = _Option(
308
+ cli_flag="--sift-report-url-base",
309
+ ini_name="sift_report_url_base",
310
+ cli_help="Sift web-app origin used to build the clickable report link in the "
311
+ "terminal footer (e.g. https://app.siftstack.com). Set this for on-prem or "
312
+ "custom deployments whose API host can't be mapped to a frontend "
313
+ "automatically. Also honored via the SIFT_APP_URL env var. When unset, the "
314
+ "link is derived from the REST URI for known Sift hosts.",
315
+ ini_help="Default for --sift-report-url-base. The Sift web-app origin used to "
316
+ "build the report link in the terminal footer. Also honored via the "
317
+ "SIFT_APP_URL env var. When unset, the link is derived from the REST URI for "
318
+ "known Sift hosts.",
319
+ )
320
+
321
+ _OPEN = _Option(
322
+ cli_flag="--sift-open-report",
323
+ ini_name="sift_open_report",
324
+ action="store_true",
325
+ cli_help="Open the resulting Sift test report in a browser at session end. "
326
+ "Online mode only; no-op when the report URL can't be resolved. Intended for "
327
+ "local development.",
328
+ ini_help="When true, open the report in a browser at session end (online only). "
329
+ "Defaults to false.",
330
+ ini_type="bool",
331
+ ini_default=False,
332
+ )
333
+
300
334
  _AUTOUSE = _Option(
301
335
  ini_name="sift_autouse",
302
336
  ini_help="Default for the Sift autouse fixtures (report_context, step, "
@@ -350,6 +384,8 @@ _OPTIONS: tuple[_Option, ...] = (
350
384
  _DISABLED,
351
385
  _GRPC_URI,
352
386
  _REST_URI,
387
+ _REPORT_URL_BASE,
388
+ _OPEN,
353
389
  _AUTOUSE,
354
390
  _PACKAGE_STEP,
355
391
  _MODULE_STEP,
@@ -445,6 +481,305 @@ def _is_disabled(pytestconfig: pytest.Config | None) -> bool:
445
481
  return os.getenv("SIFT_DISABLED", "").lower() in ("1", "true", "yes")
446
482
 
447
483
 
484
+ def _sdk_version() -> str:
485
+ """Return the installed ``sift_stack_py`` version, or ``"unknown"``."""
486
+ from importlib.metadata import PackageNotFoundError, version
487
+
488
+ try:
489
+ return version("sift_stack_py")
490
+ except PackageNotFoundError:
491
+ return "unknown"
492
+
493
+
494
+ def _mode_label(config: pytest.Config) -> str:
495
+ """Resolve the active mode for the terminal header: disabled > offline > online."""
496
+ if _is_disabled(config):
497
+ return "disabled"
498
+ if _is_offline(config):
499
+ return "offline"
500
+ return "online"
501
+
502
+
503
+ def pytest_report_header(config: pytest.Config) -> str | None:
504
+ """Emit a session-start header with the SDK version and active mode.
505
+
506
+ Suppressed under ``-q`` (negative verbosity), matching how pytest hides its
507
+ own platform/plugin header.
508
+ """
509
+ if config.get_verbosity() < 0:
510
+ return None
511
+ return f"Sift: sift-stack-py {_sdk_version()} — {_mode_label(config)} mode"
512
+
513
+
514
+ def _resolve_real_report_id(context: Any) -> str | None:
515
+ """Resolve the real server-side report id for the online footer link.
516
+
517
+ In synchronous online mode (``--sift-log-file=false``) the report is created
518
+ directly against the API, so ``report.id_`` is already the real id. In the
519
+ default incremental mode the report is created through the simulate path
520
+ (a client-side UUID) and the background worker maps it to the real id on
521
+ replay, recording it in the ``<log>.tracking`` sidecar's ``id_map``. By the
522
+ time this footer runs the session-scoped report context has torn down and
523
+ the worker has drained, so the sidecar is final.
524
+
525
+ Returns ``None`` when the worker never mapped the report (e.g. it died before
526
+ replaying the create), meaning no real report exists to link.
527
+ """
528
+ report = context.report
529
+ if not report.id_:
530
+ # No id was ever assigned (unset/empty); nothing to link.
531
+ return None
532
+ sim_id = str(report.id_)
533
+ if not getattr(report, "is_simulated", False):
534
+ return sim_id
535
+ log_file = getattr(context, "log_file", None)
536
+ if log_file is None:
537
+ return None
538
+ from sift_client._internal.low_level_wrappers._test_results_log import LogTracking
539
+
540
+ return LogTracking.load(log_file).id_map.get(sim_id)
541
+
542
+
543
+ _LABEL_WIDTH = 13
544
+
545
+
546
+ def _sift_kv(terminalreporter: Any, label: str, value: str, **value_markup: bool) -> None:
547
+ """Write an indented ``label value`` row, bolding the label.
548
+
549
+ ``value_markup`` (e.g. ``green=True``, ``cyan=True``) styles only the value.
550
+ Color is dropped automatically when the terminal has no markup (not a TTY or
551
+ ``--color=no``), so captured/CI output stays plain text.
552
+ """
553
+ terminalreporter.write(" ")
554
+ terminalreporter.write(f"{label:<{_LABEL_WIDTH}}", bold=True)
555
+ terminalreporter.write_line(value, **value_markup)
556
+
557
+
558
+ # Step-count breakdown order and labels for the footer's "Steps" row.
559
+ _STEP_COUNT_ORDER: tuple[tuple[TestStatus, str], ...] = (
560
+ (TestStatus.PASSED, "passed"),
561
+ (TestStatus.FAILED, "failed"),
562
+ (TestStatus.ERROR, "error"),
563
+ (TestStatus.ABORTED, "aborted"),
564
+ (TestStatus.SKIPPED, "skipped"),
565
+ (TestStatus.IN_PROGRESS, "in progress"),
566
+ )
567
+
568
+
569
+ # Per-status color for the footer's step breakdown: green pass, red
570
+ # failure/error/abort, yellow skip; in-progress (and anything else) stays plain.
571
+ _STEP_STATUS_MARKUP: dict[TestStatus, dict[str, bool]] = {
572
+ TestStatus.PASSED: {"green": True},
573
+ TestStatus.FAILED: {"red": True},
574
+ TestStatus.ERROR: {"red": True},
575
+ TestStatus.ABORTED: {"red": True},
576
+ TestStatus.SKIPPED: {"yellow": True},
577
+ }
578
+
579
+
580
+ def _step_count_segments(counts: Any) -> list[tuple[str, dict[str, bool]]]:
581
+ """Build ``(text, markup)`` segments for a step tally, non-zero only."""
582
+ return [
583
+ (f"{counts.get(status, 0)} {label}", _STEP_STATUS_MARKUP.get(status, {}))
584
+ for status, label in _STEP_COUNT_ORDER
585
+ if counts.get(status, 0)
586
+ ]
587
+
588
+
589
+ def _measurement_segments(counts: Any) -> list[tuple[str, dict[str, bool]]]:
590
+ """Build ``(text, markup)`` segments for a measurement tally, non-zero only."""
591
+ segments: list[tuple[str, dict[str, bool]]] = []
592
+ if counts.get(True, 0):
593
+ segments.append((f"{counts[True]} passed", {"green": True}))
594
+ if counts.get(False, 0):
595
+ segments.append((f"{counts[False]} failed", {"red": True}))
596
+ return segments
597
+
598
+
599
+ def _write_count_row(
600
+ terminalreporter: Any, label: str, segments: list[tuple[str, dict[str, bool]]]
601
+ ) -> None:
602
+ """Write a ``label a · b · c`` row, applying each segment's color markup."""
603
+ terminalreporter.write(" ")
604
+ terminalreporter.write(f"{label:<{_LABEL_WIDTH}}", bold=True)
605
+ for index, (text, markup) in enumerate(segments):
606
+ if index:
607
+ terminalreporter.write(" · ")
608
+ terminalreporter.write(text, **markup)
609
+ terminalreporter.write_line("")
610
+
611
+
612
+ def _report_panel_title(report: Any, terminalreporter: Any) -> str:
613
+ """``Sift report · <name>`` for the section rule, truncated to the terminal width.
614
+
615
+ The report name embeds a timestamp (and, for invocation-based runs, the
616
+ pytest args), so a long name is truncated with an ellipsis to keep the
617
+ separator line from wrapping.
618
+ """
619
+ base = "Sift report"
620
+ name = getattr(report, "name", None)
621
+ if not name:
622
+ return base
623
+ title = f"{base} · {name}"
624
+ fullwidth = getattr(getattr(terminalreporter, "_tw", None), "fullwidth", 80)
625
+ # Reserve room for the separator characters and spaces write_sep adds.
626
+ limit = max(len(base), fullwidth - 8)
627
+ if len(title) > limit:
628
+ title = title[: limit - 1] + "…"
629
+ return title
630
+
631
+
632
+ def _maybe_open_report(url: str) -> None:
633
+ """Best-effort open the report URL in a browser (for ``--sift-open-report``).
634
+
635
+ Skipped on CI or non-interactive sessions so a committed ``sift_open_report``
636
+ setting can't spawn a browser on a headless agent; the flag is meant for
637
+ local development.
638
+ """
639
+ import sys
640
+ import webbrowser
641
+
642
+ if os.environ.get("CI") or not sys.stdout.isatty():
643
+ return
644
+ try:
645
+ # webbrowser.open forks/execs the platform opener while the gRPC client's
646
+ # background threads are live; redirect fd 2 across the fork to swallow
647
+ # gRPC's prefork notice (same treatment as the plugin's other fork sites).
648
+ with _quiet_fork_stderr():
649
+ webbrowser.open(url)
650
+ except Exception:
651
+ # Headless / no browser available: opening is a convenience, never fatal.
652
+ pass
653
+
654
+
655
+ def pytest_terminal_summary(terminalreporter: Any, exitstatus: int, config: pytest.Config) -> None:
656
+ """Emit a session-end Sift report summary, adapting per mode.
657
+
658
+ The printed panel is suppressed under ``-q``, but programmatic side effects
659
+ (stashing the report ref for ``conftest.py``, ``--sift-open-report``) still run so
660
+ other plugins and CI steps can consume the result. The panel shows the
661
+ outcome (green/red), step and measurement tallies, and a per-mode action: a
662
+ report link (online), the upload command (offline), or a disabled note.
663
+ """
664
+ quiet = config.get_verbosity() < 0
665
+
666
+ if _is_disabled(config):
667
+ if not quiet:
668
+ terminalreporter.write_sep("=", "Sift", cyan=True, bold=True)
669
+ terminalreporter.write_line("Sift disabled — no test report created.")
670
+ return
671
+
672
+ context = REPORT_CONTEXT
673
+ if context is None:
674
+ # No gated test ran, so no report context was created. Nothing to show.
675
+ return
676
+
677
+ log_file = getattr(context, "log_file", None)
678
+ offline = _is_offline(config)
679
+
680
+ # Resolve the report link first so stashing and --sift-open-report run even under
681
+ # -q (programmatic consumers don't care about verbosity). Truthiness, not
682
+ # ``is not None``: a resolved-but-empty id (degenerate sidecar mapping, unset
683
+ # proto field) must fall through to the "not uploaded" path, not produce a
684
+ # ``/test-results/`` link.
685
+ report_id = None if offline else _resolve_real_report_id(context)
686
+ report_url = (
687
+ f"{context.client.app_url}/test-results/{report_id}"
688
+ if report_id and context.client.app_url
689
+ else None
690
+ )
691
+ if report_id:
692
+ config.stash[SIFT_REPORT_ID_STASH_KEY] = report_id
693
+ if report_url is not None:
694
+ config.stash[SIFT_REPORT_URL_STASH_KEY] = report_url
695
+ if _option_or_ini(config, _OPEN):
696
+ _maybe_open_report(report_url)
697
+
698
+ if quiet:
699
+ return
700
+
701
+ failed = bool(getattr(context, "any_failures", False))
702
+ status_word, status_markup = (
703
+ ("FAILED", {"red": True, "bold": True})
704
+ if failed
705
+ else ("PASSED", {"green": True, "bold": True})
706
+ )
707
+ # Offline results live only in the local log until replayed, so the status
708
+ # row calls that out instead of repeating the version (already in the header).
709
+ status_context = (
710
+ f"{_mode_label(config)} · not uploaded"
711
+ if offline
712
+ else f"{_mode_label(config)} · sift-stack-py {_sdk_version()}"
713
+ )
714
+
715
+ report = context.report
716
+
717
+ terminalreporter.write_sep(
718
+ "=", _report_panel_title(report, terminalreporter), cyan=True, bold=True
719
+ )
720
+
721
+ # Identity row: the test case (test path or pytest invocation).
722
+ if report.test_case:
723
+ _sift_kv(terminalreporter, "Test case", str(report.test_case))
724
+
725
+ # Status row: colored outcome, then compact mode context.
726
+ terminalreporter.write(" ")
727
+ terminalreporter.write(f"{'Status':<{_LABEL_WIDTH}}", bold=True)
728
+ terminalreporter.write(status_word, **status_markup)
729
+ terminalreporter.write_line(f" {status_context}")
730
+
731
+ # Step + measurement tallies (green pass, red failure, yellow skip).
732
+ _write_count_row(
733
+ terminalreporter,
734
+ "Steps",
735
+ _step_count_segments(context.step_status_counts) or [("no steps", {})],
736
+ )
737
+ measurement_segments = _measurement_segments(context.measurement_counts)
738
+ if measurement_segments:
739
+ _write_count_row(terminalreporter, "Measurements", measurement_segments)
740
+
741
+ # Provenance row: test system and operator.
742
+ system = " · ".join(part for part in (report.test_system_name, report.system_operator) if part)
743
+ if system:
744
+ _sift_kv(terminalreporter, "System", system)
745
+
746
+ # Local log file (write-through backup online, sole sink offline).
747
+ if log_file is not None:
748
+ _sift_kv(terminalreporter, "Log file", str(log_file))
749
+
750
+ if offline:
751
+ if log_file is not None:
752
+ terminalreporter.write_sep("-", "to upload to Sift")
753
+ terminalreporter.write_line(f" >> import-test-result-log {log_file}", cyan=True)
754
+ return
755
+
756
+ if not report_id:
757
+ # Incremental upload never mapped the report (the worker died before
758
+ # replaying the create), so there's no real report to link.
759
+ _sift_kv(
760
+ terminalreporter,
761
+ "Report",
762
+ f"not uploaded — replay with: import-test-result-log {log_file}",
763
+ yellow=True,
764
+ )
765
+ elif report_url is not None:
766
+ _sift_kv(terminalreporter, "Report", report_url, cyan=True)
767
+ else:
768
+ _sift_kv(
769
+ terminalreporter,
770
+ "Report",
771
+ f"id {report_id} (set sift_report_url_base for a clickable link)",
772
+ )
773
+
774
+ if report_id and getattr(context, "replay_incomplete", False) and log_file is not None:
775
+ _sift_kv(
776
+ terminalreporter,
777
+ "",
778
+ f"may be incomplete — finish with: import-test-result-log {log_file}",
779
+ yellow=True,
780
+ )
781
+
782
+
448
783
  def _sift_enabled_for(node: pytest.Item | pytest.Collector, default: bool) -> bool:
449
784
  """Resolve the Sift gate for a node: sift_exclude > sift_include > default.
450
785
 
@@ -806,6 +1141,10 @@ def sift_client(pytestconfig: pytest.Config) -> SiftClient:
806
1141
  )
807
1142
  for env in missing:
808
1143
  resolved[env] = _OFFLINE_DEFAULTS[env]
1144
+ # Web-app origin for the report link: the sift_report_url_base CLI/ini option
1145
+ # wins, then the SIFT_APP_URL env var, else host-based derivation in
1146
+ # SiftClient.app_url.
1147
+ report_url_base = _option_or_ini(pytestconfig, _REPORT_URL_BASE) or os.getenv("SIFT_APP_URL")
809
1148
  # `or ""` is unreachable in practice since the `missing` check above guarantees
810
1149
  # non-None values
811
1150
  return SiftClient(
@@ -813,6 +1152,7 @@ def sift_client(pytestconfig: pytest.Config) -> SiftClient:
813
1152
  api_key=resolved.get("SIFT_API_KEY") or "",
814
1153
  grpc_url=resolved.get("SIFT_GRPC_URI") or "",
815
1154
  rest_url=resolved.get("SIFT_REST_URI") or "",
1155
+ app_url=report_url_base or None,
816
1156
  )
817
1157
  )
818
1158
 
@@ -410,6 +410,38 @@ class TestMeasurement(BaseType[TestMeasurementProto, "TestMeasurement"], Simulat
410
410
  # Set by the low-level wrapper when this instance came from the simulate path
411
411
  _simulated: bool = False
412
412
 
413
+ def __str__(self) -> str:
414
+ """Human-readable form: ``[STATUS] name = value [unit] (bounds)``.
415
+
416
+ Used for failure messages, logs, and the REPL. The string omits whichever
417
+ parts aren't set (no unit, no bounds), and falls back to ``?`` if no
418
+ value type is populated. The status prefix reflects ``self.passed``.
419
+ """
420
+ status = "PASSED" if self.passed else "FAILED"
421
+ if self.numeric_value is not None:
422
+ value = f"{self.numeric_value}"
423
+ if self.unit:
424
+ value += f" {self.unit}"
425
+ elif self.string_value is not None:
426
+ value = repr(self.string_value)
427
+ elif self.boolean_value is not None:
428
+ value = str(self.boolean_value).lower()
429
+ else:
430
+ value = "?"
431
+ bounds = ""
432
+ nb = self.numeric_bounds
433
+ if nb is not None:
434
+ parts: list[str] = []
435
+ if nb.min is not None:
436
+ parts.append(f"min {nb.min}")
437
+ if nb.max is not None:
438
+ parts.append(f"max {nb.max}")
439
+ if parts:
440
+ bounds = f" ({', '.join(parts)})"
441
+ elif self.string_expected_value:
442
+ bounds = f" (expected {self.string_expected_value!r})"
443
+ return f"[{status}] {self.name} = {value}{bounds}"
444
+
413
445
  @classmethod
414
446
  def _from_proto(
415
447
  cls, proto: TestMeasurementProto, sift_client: SiftClient | None = None
@@ -24,6 +24,7 @@ class SiftConnectionConfig:
24
24
  api_key: str,
25
25
  use_ssl: bool = True,
26
26
  cert_via_openssl: bool = False,
27
+ app_url: str | None = None,
27
28
  ):
28
29
  """Initialize the connection configuration.
29
30
 
@@ -33,12 +34,17 @@ class SiftConnectionConfig:
33
34
  api_key: The API key for authentication.
34
35
  use_ssl: Whether to use SSL/TLS for secure connections.
35
36
  cert_via_openssl: Whether to use OpenSSL for certificate validation.
37
+ app_url: The Sift web-app origin (e.g. ``https://app.siftstack.com``).
38
+ Set this for on-prem or custom deployments whose API host can't be
39
+ mapped to a frontend automatically. When unset, the web-app URL is
40
+ derived from ``rest_url`` for known hosts.
36
41
  """
37
42
  self.api_key = api_key
38
43
  self.grpc_url = grpc_url
39
44
  self.rest_url = rest_url
40
45
  self.use_ssl = use_ssl
41
46
  self.cert_via_openssl = cert_via_openssl
47
+ self.app_url = app_url
42
48
 
43
49
  def get_grpc_config(self):
44
50
  """Create and return a GrpcConfig with the current settings.