sift-stack-py 0.16.0__tar.gz → 0.16.2__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 (622) hide show
  1. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/PKG-INFO +2 -1
  2. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/_test_results_log.py +40 -33
  3. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/exports.py +16 -7
  4. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/rules.py +12 -2
  5. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/util/channels.py +3 -0
  6. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/_internal/test_channels.py +19 -0
  7. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/resources/test_data_imports.py +153 -1
  8. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/sift_types/test_calculated_channel.py +63 -0
  9. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/sift_types/test_channel.py +95 -1
  10. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/sift_types/test_rule.py +73 -0
  11. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/data_imports.py +42 -2
  12. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/calculated_channel.py +29 -5
  13. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/channel.py +46 -5
  14. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/rule.py +6 -1
  15. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_stack_py.egg-info/PKG-INFO +2 -1
  16. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_stack_py.egg-info/requires.txt +1 -0
  17. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/pyproject.toml +2 -1
  18. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/LICENSE +0 -0
  19. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/README.md +0 -0
  20. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/__init__.py +0 -0
  21. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/annotation_logs/__init__.py +0 -0
  22. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/annotation_logs/v1/__init__.py +0 -0
  23. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/annotation_logs/v1/annotation_logs_pb2.py +0 -0
  24. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/annotation_logs/v1/annotation_logs_pb2.pyi +0 -0
  25. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/annotation_logs/v1/annotation_logs_pb2_grpc.py +0 -0
  26. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/annotation_logs/v1/annotation_logs_pb2_grpc.pyi +0 -0
  27. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/annotations/__init__.py +0 -0
  28. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/annotations/v1/__init__.py +0 -0
  29. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/annotations/v1/annotations_pb2.py +0 -0
  30. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/annotations/v1/annotations_pb2.pyi +0 -0
  31. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/annotations/v1/annotations_pb2_grpc.py +0 -0
  32. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/annotations/v1/annotations_pb2_grpc.pyi +0 -0
  33. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/api_keys/__init__.py +0 -0
  34. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/api_keys/v2/__init__.py +0 -0
  35. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/api_keys/v2/api_keys_pb2.py +0 -0
  36. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/api_keys/v2/api_keys_pb2.pyi +0 -0
  37. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/api_keys/v2/api_keys_pb2_grpc.py +0 -0
  38. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/api_keys/v2/api_keys_pb2_grpc.pyi +0 -0
  39. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/assets/__init__.py +0 -0
  40. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/assets/v1/__init__.py +0 -0
  41. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/assets/v1/assets_pb2.py +0 -0
  42. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/assets/v1/assets_pb2.pyi +0 -0
  43. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/assets/v1/assets_pb2_grpc.py +0 -0
  44. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/assets/v1/assets_pb2_grpc.pyi +0 -0
  45. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/calculated_channels/__init__.py +0 -0
  46. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/calculated_channels/v1/__init__.py +0 -0
  47. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/calculated_channels/v1/calculated_channels_pb2.py +0 -0
  48. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/calculated_channels/v1/calculated_channels_pb2.pyi +0 -0
  49. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/calculated_channels/v1/calculated_channels_pb2_grpc.py +0 -0
  50. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/calculated_channels/v1/calculated_channels_pb2_grpc.pyi +0 -0
  51. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/calculated_channels/v2/__init__.py +0 -0
  52. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/calculated_channels/v2/calculated_channels_pb2.py +0 -0
  53. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/calculated_channels/v2/calculated_channels_pb2.pyi +0 -0
  54. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/calculated_channels/v2/calculated_channels_pb2_grpc.py +0 -0
  55. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/calculated_channels/v2/calculated_channels_pb2_grpc.pyi +0 -0
  56. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/campaigns/__init__.py +0 -0
  57. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/campaigns/v1/__init__.py +0 -0
  58. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/campaigns/v1/campaigns_pb2.py +0 -0
  59. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/campaigns/v1/campaigns_pb2.pyi +0 -0
  60. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/campaigns/v1/campaigns_pb2_grpc.py +0 -0
  61. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/campaigns/v1/campaigns_pb2_grpc.pyi +0 -0
  62. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channel_schemas/__init__.py +0 -0
  63. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channel_schemas/v1/__init__.py +0 -0
  64. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channel_schemas/v1/channel_schemas_pb2.py +0 -0
  65. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channel_schemas/v1/channel_schemas_pb2.pyi +0 -0
  66. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channel_schemas/v1/channel_schemas_pb2_grpc.py +0 -0
  67. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channel_schemas/v1/channel_schemas_pb2_grpc.pyi +0 -0
  68. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channel_schemas/v2/__init__.py +0 -0
  69. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channel_schemas/v2/channel_schemas_pb2.py +0 -0
  70. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channel_schemas/v2/channel_schemas_pb2.pyi +0 -0
  71. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channel_schemas/v2/channel_schemas_pb2_grpc.py +0 -0
  72. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channel_schemas/v2/channel_schemas_pb2_grpc.pyi +0 -0
  73. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channels/__init__.py +0 -0
  74. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channels/v2/__init__.py +0 -0
  75. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channels/v2/channels_pb2.py +0 -0
  76. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channels/v2/channels_pb2.pyi +0 -0
  77. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channels/v2/channels_pb2_grpc.py +0 -0
  78. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channels/v2/channels_pb2_grpc.pyi +0 -0
  79. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channels/v3/__init__.py +0 -0
  80. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channels/v3/channels_pb2.py +0 -0
  81. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channels/v3/channels_pb2.pyi +0 -0
  82. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channels/v3/channels_pb2_grpc.py +0 -0
  83. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/channels/v3/channels_pb2_grpc.pyi +0 -0
  84. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/comment/__init__.py +0 -0
  85. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/comment/v1/__init__.py +0 -0
  86. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/comment/v1/comment_pb2.py +0 -0
  87. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/comment/v1/comment_pb2.pyi +0 -0
  88. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/comment/v1/comment_pb2_grpc.py +0 -0
  89. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/comment/v1/comment_pb2_grpc.pyi +0 -0
  90. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/__init__.py +0 -0
  91. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/__init__.py +0 -0
  92. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/__init__.py +0 -0
  93. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/calculated_channels_pb2.py +0 -0
  94. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/calculated_channels_pb2.pyi +0 -0
  95. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/calculated_channels_pb2_grpc.py +0 -0
  96. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/calculated_channels_pb2_grpc.pyi +0 -0
  97. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_bit_field_element_pb2.py +0 -0
  98. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_bit_field_element_pb2.pyi +0 -0
  99. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_bit_field_element_pb2_grpc.py +0 -0
  100. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_bit_field_element_pb2_grpc.pyi +0 -0
  101. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_config_pb2.py +0 -0
  102. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_config_pb2.pyi +0 -0
  103. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_config_pb2_grpc.py +0 -0
  104. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_config_pb2_grpc.pyi +0 -0
  105. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_data_type_pb2.py +0 -0
  106. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_data_type_pb2.pyi +0 -0
  107. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_data_type_pb2_grpc.py +0 -0
  108. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_data_type_pb2_grpc.pyi +0 -0
  109. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_enum_type_pb2.py +0 -0
  110. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_enum_type_pb2.pyi +0 -0
  111. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_enum_type_pb2_grpc.py +0 -0
  112. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/channel_enum_type_pb2_grpc.pyi +0 -0
  113. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/organization_pb2.py +0 -0
  114. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/organization_pb2.pyi +0 -0
  115. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/organization_pb2_grpc.py +0 -0
  116. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/organization_pb2_grpc.pyi +0 -0
  117. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/resource_identifier_pb2.py +0 -0
  118. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/resource_identifier_pb2.pyi +0 -0
  119. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/resource_identifier_pb2_grpc.py +0 -0
  120. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/resource_identifier_pb2_grpc.pyi +0 -0
  121. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/resource_ref_pb2.py +0 -0
  122. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/resource_ref_pb2.pyi +0 -0
  123. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/resource_ref_pb2_grpc.py +0 -0
  124. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/resource_ref_pb2_grpc.pyi +0 -0
  125. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/user_defined_functions_pb2.py +0 -0
  126. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/user_defined_functions_pb2.pyi +0 -0
  127. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/user_defined_functions_pb2_grpc.py +0 -0
  128. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/user_defined_functions_pb2_grpc.pyi +0 -0
  129. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/user_pb2.py +0 -0
  130. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/user_pb2.pyi +0 -0
  131. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/user_pb2_grpc.py +0 -0
  132. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/type/v1/user_pb2_grpc.pyi +0 -0
  133. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/v1/__init__.py +0 -0
  134. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/v1/action_type_pb2.py +0 -0
  135. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/v1/action_type_pb2.pyi +0 -0
  136. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/v1/action_type_pb2_grpc.py +0 -0
  137. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/v1/action_type_pb2_grpc.pyi +0 -0
  138. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/v1/filter_field_pb2.py +0 -0
  139. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/v1/filter_field_pb2.pyi +0 -0
  140. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/v1/filter_field_pb2_grpc.py +0 -0
  141. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/v1/filter_field_pb2_grpc.pyi +0 -0
  142. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/v1/resource_type_pb2.py +0 -0
  143. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/v1/resource_type_pb2.pyi +0 -0
  144. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/v1/resource_type_pb2_grpc.py +0 -0
  145. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/common/v1/resource_type_pb2_grpc.pyi +0 -0
  146. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data/__init__.py +0 -0
  147. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data/v1/__init__.py +0 -0
  148. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data/v1/data_pb2.py +0 -0
  149. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data/v1/data_pb2.pyi +0 -0
  150. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data/v1/data_pb2_grpc.py +0 -0
  151. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data/v1/data_pb2_grpc.pyi +0 -0
  152. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data/v2/__init__.py +0 -0
  153. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data/v2/data_pb2.py +0 -0
  154. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data/v2/data_pb2.pyi +0 -0
  155. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data/v2/data_pb2_grpc.py +0 -0
  156. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data/v2/data_pb2_grpc.pyi +0 -0
  157. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data_imports/__init__.py +0 -0
  158. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data_imports/v2/__init__.py +0 -0
  159. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data_imports/v2/data_imports_pb2.py +0 -0
  160. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data_imports/v2/data_imports_pb2.pyi +0 -0
  161. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data_imports/v2/data_imports_pb2_grpc.py +0 -0
  162. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/data_imports/v2/data_imports_pb2_grpc.pyi +0 -0
  163. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/dlq_errors/__init__.py +0 -0
  164. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/dlq_errors/v2/__init__.py +0 -0
  165. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/dlq_errors/v2/dlq_errors_pb2.py +0 -0
  166. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/dlq_errors/v2/dlq_errors_pb2.pyi +0 -0
  167. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/dlq_errors/v2/dlq_errors_pb2_grpc.py +0 -0
  168. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/dlq_errors/v2/dlq_errors_pb2_grpc.pyi +0 -0
  169. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/exports/__init__.py +0 -0
  170. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/exports/v1/__init__.py +0 -0
  171. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/exports/v1/exports_pb2.py +0 -0
  172. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/exports/v1/exports_pb2.pyi +0 -0
  173. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/exports/v1/exports_pb2_grpc.py +0 -0
  174. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/exports/v1/exports_pb2_grpc.pyi +0 -0
  175. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/external_sync/__init__.py +0 -0
  176. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/external_sync/v1/__init__.py +0 -0
  177. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/external_sync/v1/external_sync_pb2.py +0 -0
  178. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/external_sync/v1/external_sync_pb2.pyi +0 -0
  179. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/external_sync/v1/external_sync_pb2_grpc.py +0 -0
  180. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/external_sync/v1/external_sync_pb2_grpc.pyi +0 -0
  181. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingest/__init__.py +0 -0
  182. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingest/v1/__init__.py +0 -0
  183. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingest/v1/ingest_pb2.py +0 -0
  184. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingest/v1/ingest_pb2.pyi +0 -0
  185. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingest/v1/ingest_pb2_grpc.py +0 -0
  186. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingest/v1/ingest_pb2_grpc.pyi +0 -0
  187. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingestion_configs/__init__.py +0 -0
  188. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingestion_configs/v1/__init__.py +0 -0
  189. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingestion_configs/v1/ingestion_configs_pb2.py +0 -0
  190. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingestion_configs/v1/ingestion_configs_pb2.pyi +0 -0
  191. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingestion_configs/v1/ingestion_configs_pb2_grpc.py +0 -0
  192. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingestion_configs/v1/ingestion_configs_pb2_grpc.pyi +0 -0
  193. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingestion_configs/v2/__init__.py +0 -0
  194. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingestion_configs/v2/ingestion_configs_pb2.py +0 -0
  195. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingestion_configs/v2/ingestion_configs_pb2.pyi +0 -0
  196. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingestion_configs/v2/ingestion_configs_pb2_grpc.py +0 -0
  197. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ingestion_configs/v2/ingestion_configs_pb2_grpc.pyi +0 -0
  198. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/jobs/__init__.py +0 -0
  199. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/jobs/v1/__init__.py +0 -0
  200. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/jobs/v1/jobs_pb2.py +0 -0
  201. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/jobs/v1/jobs_pb2.pyi +0 -0
  202. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/jobs/v1/jobs_pb2_grpc.py +0 -0
  203. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/jobs/v1/jobs_pb2_grpc.pyi +0 -0
  204. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/me/__init__.py +0 -0
  205. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/me/v2/__init__.py +0 -0
  206. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/me/v2/me_pb2.py +0 -0
  207. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/me/v2/me_pb2.pyi +0 -0
  208. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/me/v2/me_pb2_grpc.py +0 -0
  209. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/me/v2/me_pb2_grpc.pyi +0 -0
  210. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/metadata/__init__.py +0 -0
  211. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/metadata/v1/__init__.py +0 -0
  212. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/metadata/v1/metadata_pb2.py +0 -0
  213. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/metadata/v1/metadata_pb2.pyi +0 -0
  214. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/metadata/v1/metadata_pb2_grpc.py +0 -0
  215. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/metadata/v1/metadata_pb2_grpc.pyi +0 -0
  216. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/notifications/__init__.py +0 -0
  217. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/notifications/v1/__init__.py +0 -0
  218. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/notifications/v1/notifications_pb2.py +0 -0
  219. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/notifications/v1/notifications_pb2.pyi +0 -0
  220. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/notifications/v1/notifications_pb2_grpc.py +0 -0
  221. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/notifications/v1/notifications_pb2_grpc.pyi +0 -0
  222. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/panel_configurations/__init__.py +0 -0
  223. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/panel_configurations/v1/__init__.py +0 -0
  224. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/panel_configurations/v1/panel_configuration_pb2.py +0 -0
  225. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/panel_configurations/v1/panel_configuration_pb2.pyi +0 -0
  226. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/panel_configurations/v1/panel_configuration_pb2_grpc.py +0 -0
  227. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/panel_configurations/v1/panel_configuration_pb2_grpc.pyi +0 -0
  228. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ping/__init__.py +0 -0
  229. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ping/v1/__init__.py +0 -0
  230. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ping/v1/ping_pb2.py +0 -0
  231. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ping/v1/ping_pb2.pyi +0 -0
  232. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ping/v1/ping_pb2_grpc.py +0 -0
  233. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/ping/v1/ping_pb2_grpc.pyi +0 -0
  234. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/protobuf_descriptors/__init__.py +0 -0
  235. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/protobuf_descriptors/v2/__init__.py +0 -0
  236. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/protobuf_descriptors/v2/channel_parsing_options_pb2.py +0 -0
  237. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/protobuf_descriptors/v2/channel_parsing_options_pb2.pyi +0 -0
  238. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/protobuf_descriptors/v2/channel_parsing_options_pb2_grpc.py +0 -0
  239. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/protobuf_descriptors/v2/channel_parsing_options_pb2_grpc.pyi +0 -0
  240. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/protobuf_descriptors/v2/protobuf_descriptors_pb2.py +0 -0
  241. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/protobuf_descriptors/v2/protobuf_descriptors_pb2.pyi +0 -0
  242. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/protobuf_descriptors/v2/protobuf_descriptors_pb2_grpc.py +0 -0
  243. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/protobuf_descriptors/v2/protobuf_descriptors_pb2_grpc.pyi +0 -0
  244. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/py.typed +0 -0
  245. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/remote_files/__init__.py +0 -0
  246. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/remote_files/v1/__init__.py +0 -0
  247. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/remote_files/v1/remote_files_pb2.py +0 -0
  248. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/remote_files/v1/remote_files_pb2.pyi +0 -0
  249. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/remote_files/v1/remote_files_pb2_grpc.py +0 -0
  250. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/remote_files/v1/remote_files_pb2_grpc.pyi +0 -0
  251. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/report_templates/__init__.py +0 -0
  252. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/report_templates/v1/__init__.py +0 -0
  253. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/report_templates/v1/report_templates_pb2.py +0 -0
  254. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/report_templates/v1/report_templates_pb2.pyi +0 -0
  255. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/report_templates/v1/report_templates_pb2_grpc.py +0 -0
  256. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/report_templates/v1/report_templates_pb2_grpc.pyi +0 -0
  257. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/reports/__init__.py +0 -0
  258. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/reports/v1/__init__.py +0 -0
  259. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/reports/v1/reports_pb2.py +0 -0
  260. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/reports/v1/reports_pb2.pyi +0 -0
  261. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/reports/v1/reports_pb2_grpc.py +0 -0
  262. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/reports/v1/reports_pb2_grpc.pyi +0 -0
  263. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/roles/__init__.py +0 -0
  264. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/roles/v2/__init__.py +0 -0
  265. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/roles/v2/roles_pb2.py +0 -0
  266. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/roles/v2/roles_pb2.pyi +0 -0
  267. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/roles/v2/roles_pb2_grpc.py +0 -0
  268. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/roles/v2/roles_pb2_grpc.pyi +0 -0
  269. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/rule_evaluation/__init__.py +0 -0
  270. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/rule_evaluation/v1/__init__.py +0 -0
  271. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/rule_evaluation/v1/rule_evaluation_pb2.py +0 -0
  272. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/rule_evaluation/v1/rule_evaluation_pb2.pyi +0 -0
  273. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/rule_evaluation/v1/rule_evaluation_pb2_grpc.py +0 -0
  274. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/rule_evaluation/v1/rule_evaluation_pb2_grpc.pyi +0 -0
  275. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/rules/__init__.py +0 -0
  276. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/rules/v1/__init__.py +0 -0
  277. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/rules/v1/rules_pb2.py +0 -0
  278. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/rules/v1/rules_pb2.pyi +0 -0
  279. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/rules/v1/rules_pb2_grpc.py +0 -0
  280. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/rules/v1/rules_pb2_grpc.pyi +0 -0
  281. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/runs/__init__.py +0 -0
  282. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/runs/v2/__init__.py +0 -0
  283. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/runs/v2/runs_pb2.py +0 -0
  284. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/runs/v2/runs_pb2.pyi +0 -0
  285. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/runs/v2/runs_pb2_grpc.py +0 -0
  286. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/runs/v2/runs_pb2_grpc.pyi +0 -0
  287. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/saved_searches/__init__.py +0 -0
  288. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/saved_searches/v1/__init__.py +0 -0
  289. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/saved_searches/v1/saved_searches_pb2.py +0 -0
  290. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/saved_searches/v1/saved_searches_pb2.pyi +0 -0
  291. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/saved_searches/v1/saved_searches_pb2_grpc.py +0 -0
  292. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/saved_searches/v1/saved_searches_pb2_grpc.pyi +0 -0
  293. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/tags/__init__.py +0 -0
  294. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/tags/v1/__init__.py +0 -0
  295. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/tags/v1/tags_pb2.py +0 -0
  296. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/tags/v1/tags_pb2.pyi +0 -0
  297. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/tags/v1/tags_pb2_grpc.py +0 -0
  298. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/tags/v1/tags_pb2_grpc.pyi +0 -0
  299. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/tags/v2/__init__.py +0 -0
  300. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/tags/v2/tags_pb2.py +0 -0
  301. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/tags/v2/tags_pb2.pyi +0 -0
  302. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/tags/v2/tags_pb2_grpc.py +0 -0
  303. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/tags/v2/tags_pb2_grpc.pyi +0 -0
  304. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/test_reports/__init__.py +0 -0
  305. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/test_reports/v1/__init__.py +0 -0
  306. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/test_reports/v1/test_reports_pb2.py +0 -0
  307. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/test_reports/v1/test_reports_pb2.pyi +0 -0
  308. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/test_reports/v1/test_reports_pb2_grpc.py +0 -0
  309. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/test_reports/v1/test_reports_pb2_grpc.pyi +0 -0
  310. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/unit/__init__.py +0 -0
  311. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/unit/v2/__init__.py +0 -0
  312. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/unit/v2/unit_pb2.py +0 -0
  313. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/unit/v2/unit_pb2.pyi +0 -0
  314. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/unit/v2/unit_pb2_grpc.py +0 -0
  315. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/unit/v2/unit_pb2_grpc.pyi +0 -0
  316. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/user_defined_functions/__init__.py +0 -0
  317. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/user_defined_functions/v1/__init__.py +0 -0
  318. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/user_defined_functions/v1/user_defined_functions_pb2.py +0 -0
  319. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/user_defined_functions/v1/user_defined_functions_pb2.pyi +0 -0
  320. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/user_defined_functions/v1/user_defined_functions_pb2_grpc.py +0 -0
  321. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/user_defined_functions/v1/user_defined_functions_pb2_grpc.pyi +0 -0
  322. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/user_groups/__init__.py +0 -0
  323. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/user_groups/v2/__init__.py +0 -0
  324. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/user_groups/v2/user_groups_pb2.py +0 -0
  325. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/user_groups/v2/user_groups_pb2.pyi +0 -0
  326. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/user_groups/v2/user_groups_pb2_grpc.py +0 -0
  327. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/user_groups/v2/user_groups_pb2_grpc.pyi +0 -0
  328. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/users/__init__.py +0 -0
  329. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/users/v2/__init__.py +0 -0
  330. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/users/v2/users_pb2.py +0 -0
  331. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/users/v2/users_pb2.pyi +0 -0
  332. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/users/v2/users_pb2_grpc.py +0 -0
  333. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/users/v2/users_pb2_grpc.pyi +0 -0
  334. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/views/__init__.py +0 -0
  335. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/views/v1/__init__.py +0 -0
  336. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/views/v1/views_pb2.py +0 -0
  337. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/views/v1/views_pb2.pyi +0 -0
  338. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/views/v1/views_pb2_grpc.py +0 -0
  339. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/views/v1/views_pb2_grpc.pyi +0 -0
  340. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/views/v2/__init__.py +0 -0
  341. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/views/v2/views_pb2.py +0 -0
  342. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/views/v2/views_pb2.pyi +0 -0
  343. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/views/v2/views_pb2_grpc.py +0 -0
  344. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/views/v2/views_pb2_grpc.pyi +0 -0
  345. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/webhooks/__init__.py +0 -0
  346. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/webhooks/v1/__init__.py +0 -0
  347. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/webhooks/v1/webhooks_pb2.py +0 -0
  348. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/webhooks/v1/webhooks_pb2.pyi +0 -0
  349. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/webhooks/v1/webhooks_pb2_grpc.py +0 -0
  350. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift/webhooks/v1/webhooks_pb2_grpc.pyi +0 -0
  351. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/__init__.py +0 -0
  352. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/__init__.py +0 -0
  353. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/gen_pyi.py +0 -0
  354. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/grpc_transport/__init__.py +0 -0
  355. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/grpc_transport/_async_interceptors/__init__.py +0 -0
  356. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/grpc_transport/_async_interceptors/base.py +0 -0
  357. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/grpc_transport/_async_interceptors/metadata.py +0 -0
  358. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/grpc_transport/_interceptors/__init__.py +0 -0
  359. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/grpc_transport/_interceptors/base.py +0 -0
  360. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/grpc_transport/_interceptors/context.py +0 -0
  361. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/grpc_transport/_interceptors/metadata.py +0 -0
  362. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/grpc_transport/_retry.py +0 -0
  363. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/grpc_transport/keepalive.py +0 -0
  364. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/grpc_transport/server_interceptors/__init__.py +0 -0
  365. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/grpc_transport/server_interceptors/server_interceptor.py +0 -0
  366. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/grpc_transport/transport.py +0 -0
  367. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/grpc_transport/transport_test.py +0 -0
  368. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/__init__.py +0 -0
  369. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/assets.py +0 -0
  370. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/base.py +0 -0
  371. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/calculated_channels.py +0 -0
  372. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/channels.py +0 -0
  373. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/data.py +0 -0
  374. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/data_imports.py +0 -0
  375. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/ingestion.py +0 -0
  376. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/jobs.py +0 -0
  377. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/ping.py +0 -0
  378. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/remote_files.py +0 -0
  379. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/reports.py +0 -0
  380. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/runs.py +0 -0
  381. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/tags.py +0 -0
  382. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/test_results.py +0 -0
  383. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/low_level_wrappers/upload.py +0 -0
  384. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/rest.py +0 -0
  385. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/sync_wrapper.py +0 -0
  386. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/time.py +0 -0
  387. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/util/__init__.py +0 -0
  388. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/util/executor.py +0 -0
  389. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/util/file.py +0 -0
  390. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/util/hdf5.py +0 -0
  391. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/util/numpy_types.py +0 -0
  392. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/util/tdms.py +0 -0
  393. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/util/timestamp.py +0 -0
  394. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_internal/util/util.py +0 -0
  395. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/__init__.py +0 -0
  396. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/_internal/__init__.py +0 -0
  397. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/_internal/low_level_wrappers/__init__.py +0 -0
  398. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/_internal/low_level_wrappers/test_base.py +0 -0
  399. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/_internal/low_level_wrappers/test_ingestion.py +0 -0
  400. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/_internal/low_level_wrappers/test_upload.py +0 -0
  401. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/_internal/test_gen_pyi.py +0 -0
  402. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/_internal/test_hdf5.py +0 -0
  403. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/_internal/test_stub_module/__init__.py +0 -0
  404. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/_internal/test_stub_module/test_py.py +0 -0
  405. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/_internal/test_sync_wrapper.py +0 -0
  406. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/_internal/test_tdms.py +0 -0
  407. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/_internal/test_transport.py +0 -0
  408. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/conftest.py +0 -0
  409. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/resources/__init__.py +0 -0
  410. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/resources/test_assets.py +0 -0
  411. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/resources/test_calculated_channels.py +0 -0
  412. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/resources/test_channels.py +0 -0
  413. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/resources/test_exports.py +0 -0
  414. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/resources/test_file_attachments.py +0 -0
  415. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/resources/test_jobs.py +0 -0
  416. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/resources/test_ping.py +0 -0
  417. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/resources/test_reports.py +0 -0
  418. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/resources/test_rules.py +0 -0
  419. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/resources/test_runs.py +0 -0
  420. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/resources/test_tags.py +0 -0
  421. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/resources/test_test_results.py +0 -0
  422. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/sift_types/__init__.py +0 -0
  423. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/sift_types/test_asset.py +0 -0
  424. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/sift_types/test_base.py +0 -0
  425. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/sift_types/test_ingestion.py +0 -0
  426. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/sift_types/test_job.py +0 -0
  427. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/sift_types/test_report.py +0 -0
  428. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/sift_types/test_results.py +0 -0
  429. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/sift_types/test_run.py +0 -0
  430. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/sift_types/test_tag.py +0 -0
  431. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/test_client.py +0 -0
  432. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/util/__init__.py +0 -0
  433. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/util/conftest.py +0 -0
  434. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/util/test_cel_utils.py +0 -0
  435. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/_tests/util/test_test_results_utils.py +0 -0
  436. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/client.py +0 -0
  437. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/config.py +0 -0
  438. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/errors.py +0 -0
  439. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/py.typed +0 -0
  440. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/__init__.py +0 -0
  441. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/_base.py +0 -0
  442. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/assets.py +0 -0
  443. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/calculated_channels.py +0 -0
  444. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/channels.py +0 -0
  445. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/exports.py +0 -0
  446. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/file_attachments.py +0 -0
  447. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/ingestion.py +0 -0
  448. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/jobs.py +0 -0
  449. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/ping.py +0 -0
  450. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/py.typed +0 -0
  451. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/reports.py +0 -0
  452. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/rules.py +0 -0
  453. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/runs.py +0 -0
  454. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/sync_stubs/__init__.py +0 -0
  455. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/sync_stubs/__init__.pyi +0 -0
  456. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/sync_stubs/py.typed +0 -0
  457. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/tags.py +0 -0
  458. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/resources/test_results.py +0 -0
  459. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/scripts/__init__.py +0 -0
  460. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/scripts/import_test_result_log.py +0 -0
  461. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/__init__.py +0 -0
  462. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/_base.py +0 -0
  463. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/_mixins/__init__.py +0 -0
  464. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/_mixins/file_attachments.py +0 -0
  465. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/asset.py +0 -0
  466. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/data_import.py +0 -0
  467. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/export.py +0 -0
  468. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/file_attachment.py +0 -0
  469. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/ingestion.py +0 -0
  470. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/job.py +0 -0
  471. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/report.py +0 -0
  472. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/run.py +0 -0
  473. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/tag.py +0 -0
  474. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/sift_types/test_report.py +0 -0
  475. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/transport/__init__.py +0 -0
  476. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/transport/base_connection.py +0 -0
  477. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/transport/grpc_transport.py +0 -0
  478. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/transport/rest_transport.py +0 -0
  479. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/util/__init__.py +0 -0
  480. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/util/cel_utils.py +0 -0
  481. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/util/metadata.py +0 -0
  482. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/util/test_results/__init__.py +0 -0
  483. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/util/test_results/bounds.py +0 -0
  484. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/util/test_results/context_manager.py +0 -0
  485. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/util/test_results/pytest_util.py +0 -0
  486. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_client/util/util.py +0 -0
  487. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/__init__.py +0 -0
  488. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_internal/__init__.py +0 -0
  489. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_internal/cel.py +0 -0
  490. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_internal/channel.py +0 -0
  491. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_internal/convert/__init__.py +0 -0
  492. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_internal/convert/json.py +0 -0
  493. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_internal/convert/protobuf.py +0 -0
  494. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_internal/convert/timestamp.py +0 -0
  495. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_internal/metadata.py +0 -0
  496. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_internal/metadata_test.py +0 -0
  497. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_internal/test_util/__init__.py +0 -0
  498. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_internal/test_util/channel.py +0 -0
  499. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_internal/test_util/fn.py +0 -0
  500. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_internal/test_util/server_interceptor.py +0 -0
  501. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_internal/time.py +0 -0
  502. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_internal/user.py +0 -0
  503. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/_rest_test.py +0 -0
  504. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/asset/__init__.py +0 -0
  505. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/asset/_config_test.py +0 -0
  506. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/asset/_internal/shared.py +0 -0
  507. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/asset/_service_test.py +0 -0
  508. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/asset/config.py +0 -0
  509. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/asset/service.py +0 -0
  510. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/calculated_channels/__init__.py +0 -0
  511. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/calculated_channels/_service_test.py +0 -0
  512. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/calculated_channels/config.py +0 -0
  513. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/calculated_channels/service.py +0 -0
  514. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data/__init__.py +0 -0
  515. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data/_channel.py +0 -0
  516. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data/_deserialize.py +0 -0
  517. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data/_deserialize_test.py +0 -0
  518. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data/_service_test.py +0 -0
  519. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data/_validate.py +0 -0
  520. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data/error.py +0 -0
  521. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data/query.py +0 -0
  522. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data/service.py +0 -0
  523. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/__init__.py +0 -0
  524. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/_config.py +0 -0
  525. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/_config_test.py +0 -0
  526. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/_csv_test.py +0 -0
  527. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/_hdf5_test.py +0 -0
  528. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/_parquet_test.py +0 -0
  529. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/_ros_channel.py +0 -0
  530. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/_rosbag_test.py +0 -0
  531. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/_status_test.py +0 -0
  532. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/_tdms_test.py +0 -0
  533. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/_utils.py +0 -0
  534. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/_utils_test.py +0 -0
  535. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/ch10.py +0 -0
  536. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/config.py +0 -0
  537. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/csv.py +0 -0
  538. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/hdf5.py +0 -0
  539. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/parquet.py +0 -0
  540. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/parquet_complex_types.py +0 -0
  541. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/rosbags.py +0 -0
  542. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/status.py +0 -0
  543. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/tdms.py +0 -0
  544. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/tempfile.py +0 -0
  545. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/data_import/time_format.py +0 -0
  546. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/error.py +0 -0
  547. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/file_attachment/__init__.py +0 -0
  548. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/file_attachment/_internal/__init__.py +0 -0
  549. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/file_attachment/_internal/download.py +0 -0
  550. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/file_attachment/_internal/upload.py +0 -0
  551. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/file_attachment/_service_test.py +0 -0
  552. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/file_attachment/entity.py +0 -0
  553. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/file_attachment/metadata.py +0 -0
  554. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/file_attachment/service.py +0 -0
  555. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/grpc/__init__.py +0 -0
  556. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/grpc/_async_interceptors/__init__.py +0 -0
  557. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/grpc/_async_interceptors/base.py +0 -0
  558. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/grpc/_async_interceptors/metadata.py +0 -0
  559. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/grpc/_interceptors/__init__.py +0 -0
  560. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/grpc/_interceptors/base.py +0 -0
  561. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/grpc/_interceptors/context.py +0 -0
  562. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/grpc/_interceptors/metadata.py +0 -0
  563. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/grpc/_retry.py +0 -0
  564. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/grpc/keepalive.py +0 -0
  565. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/grpc/transport.py +0 -0
  566. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/grpc/transport_test.py +0 -0
  567. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/__init__.py +0 -0
  568. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/_internal/__init__.py +0 -0
  569. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/_internal/channel.py +0 -0
  570. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/_internal/error.py +0 -0
  571. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/_internal/ingest.py +0 -0
  572. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/_internal/ingest_test.py +0 -0
  573. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/_internal/ingestion_config.py +0 -0
  574. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/_internal/run.py +0 -0
  575. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/_service_test.py +0 -0
  576. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/buffer.py +0 -0
  577. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/channel.py +0 -0
  578. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/config/__init__.py +0 -0
  579. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/config/_telemetry_test.py +0 -0
  580. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/config/telemetry.py +0 -0
  581. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/config/yaml/__init__.py +0 -0
  582. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/config/yaml/error.py +0 -0
  583. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/config/yaml/load.py +0 -0
  584. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/config/yaml/spec.py +0 -0
  585. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/config/yaml/test_load.py +0 -0
  586. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/flow.py +0 -0
  587. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/manager.py +0 -0
  588. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/rule/__init__.py +0 -0
  589. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/rule/config.py +0 -0
  590. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/ingestion/service.py +0 -0
  591. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/py.typed +0 -0
  592. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/report/_report_test.py +0 -0
  593. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/report/service.py +0 -0
  594. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/report_templates/__init__.py +0 -0
  595. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/report_templates/_config_test.py +0 -0
  596. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/report_templates/_service_test.py +0 -0
  597. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/report_templates/config.py +0 -0
  598. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/report_templates/service.py +0 -0
  599. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/rest.py +0 -0
  600. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/rule/__init__.py +0 -0
  601. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/rule/_config_test.py +0 -0
  602. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/rule/_service_test.py +0 -0
  603. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/rule/config.py +0 -0
  604. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/rule/service.py +0 -0
  605. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/rule_evaluation/_service_test.py +0 -0
  606. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/rule_evaluation/service.py +0 -0
  607. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/tag/_internal/shared.py +0 -0
  608. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/yaml/__init__.py +0 -0
  609. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/yaml/_channel_test.py +0 -0
  610. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/yaml/_rule_test.py +0 -0
  611. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/yaml/_utils_test.py +0 -0
  612. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/yaml/calculated_channels.py +0 -0
  613. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/yaml/channel.py +0 -0
  614. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/yaml/report_templates.py +0 -0
  615. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/yaml/rule.py +0 -0
  616. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_py/yaml/utils.py +0 -0
  617. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_stack_py.egg-info/SOURCES.txt +0 -0
  618. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_stack_py.egg-info/dependency_links.txt +0 -0
  619. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_stack_py.egg-info/entry_points.txt +0 -0
  620. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/lib/sift_stack_py.egg-info/top_level.txt +0 -0
  621. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/setup.cfg +0 -0
  622. {sift_stack_py-0.16.0 → sift_stack_py-0.16.2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sift_stack_py
3
- Version: 0.16.0
3
+ Version: 0.16.2
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.
@@ -45,6 +45,7 @@ Requires-Dist: typing-extensions~=4.6
45
45
  Requires-Dist: types-requests~=2.25
46
46
  Requires-Dist: googleapis-common-protos>=1.60
47
47
  Requires-Dist: protoc-gen-openapiv2>=0.0.1
48
+ Requires-Dist: filelock~=3.13
48
49
  Provides-Extra: all
49
50
  Requires-Dist: cffi~=1.14; extra == "all"
50
51
  Requires-Dist: h5py~=3.11; extra == "all"
@@ -1,11 +1,15 @@
1
1
  """Internal log-format primitives for test-result simulation logs.
2
2
 
3
- Two files per run:
3
+ Three files per run:
4
4
 
5
5
  * **Log file** (e.g. ``foo.jsonl``) - append-only record of each logged API call,
6
6
  one line per call. Written by :func:`log_request_to_file` in the test process
7
7
  and read by :func:`iter_log_data_lines` / the replay subprocess. Has no header:
8
8
  every line is a data line.
9
+ * **Lock sidecar** (``foo.jsonl.lock``) - empty file used by :class:`filelock.FileLock`
10
+ to coordinate appends and snapshot reads across processes. Created on demand;
11
+ ``filelock`` unlinks it on release on Unix, and on Windows it may linger but is
12
+ harmless to leave or delete after the run.
9
13
  * **Tracking sidecar** (``foo.jsonl.tracking``) - small JSON file holding the
10
14
  incremental replay cursor (``lastUploadedLine``) and the simulated-to-real ID
11
15
  map. Written only by the replay subprocess via :meth:`LogTracking.save` using
@@ -15,26 +19,26 @@ Two files per run:
15
19
 
16
20
  # Concurrency
17
21
 
18
- With tracking moved out of the main log, the log file becomes strictly
19
- append-only and has exactly one in-place mutator (the writer) and one scanner
20
- (the replay subprocess). POSIX guarantees that an ``O_APPEND`` write atomically
21
- bumps the EOF, so parallel writers can't lose data. To keep a concurrent reader
22
- from observing a mid-append partial final line we still take ``LOCK_EX`` on the
23
- writer's single append and ``LOCK_SH`` on the reader's ``readlines()``; there
24
- is never any exclusive-vs-exclusive contention because nothing rewrites the
25
- file any more.
26
-
27
- The sidecar has a single writer (the replay subprocess) and no live reader, so
28
- it needs no locking. Atomic rename is still used to keep the on-disk contents
29
- valid across crashes.
30
-
31
- ``flock`` is advisory, so this contract only holds for processes that use these
32
- helpers; ad-hoc writers are not protected.
22
+ With tracking moved out of the main log, the log file is strictly append-only
23
+ and has exactly one in-place mutator (the writer) and one scanner (the replay
24
+ subprocess). Both serialize through a cross-platform exclusive ``FileLock`` on
25
+ the lock sidecar: the writer holds it across a single append, the reader holds
26
+ it across the snapshot ``readlines()``. That keeps a concurrent reader from
27
+ observing a mid-append partial final line on any OS, including Windows where
28
+ POSIX advisory ``flock`` is unavailable. The exclusive-only lock means a hot
29
+ reader briefly blocks the writer (and vice versa), which is acceptable because
30
+ writes are tiny and we only have one reader.
31
+
32
+ The tracking sidecar has a single writer (the replay subprocess) and no live
33
+ reader, so it needs no locking. Atomic rename is still used to keep the on-disk
34
+ contents valid across crashes.
35
+
36
+ The lock is advisory: it only protects callers that go through these helpers.
37
+ Ad-hoc writers to the same path are not protected.
33
38
  """
34
39
 
35
40
  from __future__ import annotations
36
41
 
37
- import fcntl
38
42
  import json
39
43
  import os
40
44
  import re
@@ -42,6 +46,7 @@ from dataclasses import dataclass, field
42
46
  from pathlib import Path
43
47
  from typing import TYPE_CHECKING, Any, Generator
44
48
 
49
+ from filelock import FileLock
45
50
  from google.protobuf import json_format
46
51
 
47
52
  if TYPE_CHECKING:
@@ -153,9 +158,10 @@ def log_request_to_file(
153
158
  ) -> None:
154
159
  """Append a request as a JSON-encoded line to ``log_file``.
155
160
 
156
- Takes ``LOCK_EX`` across the append so a concurrent reader holding
157
- ``LOCK_SH`` in :func:`iter_log_data_lines` can't see a mid-write partial
158
- final line. See the module docstring for the full concurrency model.
161
+ Holds an exclusive :class:`filelock.FileLock` on the sidecar across the
162
+ append so a concurrent reader in :func:`iter_log_data_lines` can't see a
163
+ mid-write partial final line. See the module docstring for the full
164
+ concurrency model.
159
165
 
160
166
  Args:
161
167
  log_file: Path to the log file.
@@ -171,15 +177,15 @@ def log_request_to_file(
171
177
  request_dict = json_format.MessageToDict(request)
172
178
  request_json = json.dumps(request_dict, separators=(",", ":"))
173
179
  line = f"[{tag}] {request_json}\n"
174
- with open(log_path, "a") as f:
175
- fcntl.flock(f, fcntl.LOCK_EX)
176
- # Closing the file flushes and releases the flock atomically; no
177
- # explicit unlock needed here.
178
- f.write(line)
180
+ with FileLock(str(log_path.with_name(log_path.name + ".lock"))):
181
+ with open(log_path, "a") as f:
182
+ # The inner ``with`` flushes and closes the file before the
183
+ # FileLock is released, so no reader sees a partial line.
184
+ f.write(line)
179
185
 
180
186
 
181
187
  def iter_log_data_lines(
182
- log_path: Path,
188
+ log_path: str | Path,
183
189
  start_line: int = 0,
184
190
  ) -> Generator[tuple[str, str | None, str], None, None]:
185
191
  """Parse data lines from a log file.
@@ -191,15 +197,16 @@ def iter_log_data_lines(
191
197
  iterator skips the first ``start_line`` lines and yields the rest. Pass 0
192
198
  to read all data lines.
193
199
 
194
- Acquires ``LOCK_SH`` only while snapshotting the file into memory, then
195
- releases before yielding. Lines appended by a concurrent
196
- :func:`log_request_to_file` after the snapshot are not visible this call --
197
- they will be picked up on the next invocation.
200
+ Holds the sidecar :class:`filelock.FileLock` only while snapshotting the
201
+ file into memory, then releases before yielding. Lines appended by a
202
+ concurrent :func:`log_request_to_file` after the snapshot are not visible
203
+ this call -- they will be picked up on the next invocation.
198
204
  """
199
205
  line_pattern = re.compile(r"^\[(\w+)(?::([^\]]+))?\]\s*(.+)$")
200
- with open(log_path) as f:
201
- fcntl.flock(f, fcntl.LOCK_SH)
202
- raw_lines = f.readlines()
206
+ log_path = Path(log_path)
207
+ with FileLock(str(log_path.with_name(log_path.name + ".lock"))):
208
+ with open(log_path) as f:
209
+ raw_lines = f.readlines()
203
210
 
204
211
  data_line_count = 0
205
212
  for raw_line in raw_lines:
@@ -26,10 +26,25 @@ from sift_client.transport import WithGrpcClient
26
26
  if TYPE_CHECKING:
27
27
  from datetime import datetime
28
28
 
29
+ from sift_client.sift_types.channel import ChannelReference
29
30
  from sift_client.sift_types.export import ExportOutputFormat
30
31
  from sift_client.transport.grpc_transport import GrpcClient
31
32
 
32
33
 
34
+ def _abstract_ref_to_proto(ref: ChannelReference) -> CalculatedChannelAbstractChannelReference:
35
+ # After ChannelReference validation, calculated_channel is always a version_id string.
36
+ if ref.calculated_channel:
37
+ assert isinstance(ref.calculated_channel, str)
38
+ return CalculatedChannelAbstractChannelReference(
39
+ channel_reference=ref.channel_reference,
40
+ calculated_channel_version_id=ref.calculated_channel,
41
+ )
42
+ return CalculatedChannelAbstractChannelReference(
43
+ channel_reference=ref.channel_reference,
44
+ channel_identifier=ref.channel_identifier or "",
45
+ )
46
+
47
+
33
48
  def _build_calc_channel_configs(
34
49
  calculated_channels: list[CalculatedChannel | CalculatedChannelCreate] | None,
35
50
  ) -> list[CalculatedChannelConfig]:
@@ -46,13 +61,7 @@ def _build_calc_channel_configs(
46
61
  CalculatedChannelConfig(
47
62
  name=cc.name,
48
63
  expression=cc.expression or "",
49
- channel_references=[
50
- CalculatedChannelAbstractChannelReference(
51
- channel_reference=ref.channel_reference,
52
- channel_identifier=ref.channel_identifier,
53
- )
54
- for ref in refs
55
- ],
64
+ channel_references=[_abstract_ref_to_proto(ref) for ref in refs],
56
65
  units=cc.units,
57
66
  )
58
67
  )
@@ -75,6 +75,16 @@ if TYPE_CHECKING:
75
75
  logger = logging.getLogger(__name__)
76
76
 
77
77
 
78
+ def _channel_reference_to_proto(ref: ChannelReference) -> ChannelReferenceProto:
79
+ # ChannelReference's validator normalizes calculated_channel to a version_id str
80
+ # and guarantees exactly one of calculated_channel / channel_identifier is set.
81
+ if ref.calculated_channel:
82
+ return ChannelReferenceProto(
83
+ calculated_channel_version_id=cast("str", ref.calculated_channel)
84
+ )
85
+ return ChannelReferenceProto(name=cast("str", ref.channel_identifier))
86
+
87
+
78
88
  class RulesLowLevelClient(LowLevelClientBase, WithGrpcClient):
79
89
  """Low-level client for the RulesAPI.
80
90
 
@@ -126,7 +136,7 @@ class RulesLowLevelClient(LowLevelClientBase, WithGrpcClient):
126
136
  calculated_channel=CalculatedChannelConfig(
127
137
  expression=create.expression,
128
138
  channel_references={
129
- c.channel_reference: ChannelReferenceProto(name=c.channel_identifier)
139
+ c.channel_reference: _channel_reference_to_proto(c)
130
140
  for c in create.channel_references
131
141
  },
132
142
  )
@@ -259,7 +269,7 @@ class RulesLowLevelClient(LowLevelClientBase, WithGrpcClient):
259
269
  CalculatedChannelConfig(
260
270
  expression=expression,
261
271
  channel_references={
262
- c.channel_reference: ChannelReferenceProto(name=c.channel_identifier)
272
+ c.channel_reference: _channel_reference_to_proto(c)
263
273
  for c in channel_references
264
274
  },
265
275
  )
@@ -32,6 +32,9 @@ async def resolve_calculated_channels(
32
32
 
33
33
  resolved_refs: list[ChannelReference] = []
34
34
  for ref in refs:
35
+ if ref.calculated_channel:
36
+ resolved_refs.append(ref)
37
+ continue
35
38
  channel = await channels_api.find(
36
39
  name=ref.channel_identifier,
37
40
  assets=cc.asset_ids,
@@ -41,6 +41,25 @@ class TestResolveCalculatedChannels:
41
41
  assert refs is not None
42
42
  assert refs[0].channel_identifier == "resolved-uuid"
43
43
 
44
+ @pytest.mark.asyncio
45
+ async def test_skips_lookup_for_calculated_channel_version_id(self):
46
+ api = MagicMock()
47
+ api.find = AsyncMock()
48
+ cc = CalculatedChannelCreate(
49
+ name="nested",
50
+ expression="$1 + 1",
51
+ expression_channel_references=[
52
+ ChannelReference(channel_reference="$1", calculated_channel="v-nested")
53
+ ],
54
+ )
55
+ result = await resolve_calculated_channels([cc], channels_api=api)
56
+ api.find.assert_not_awaited()
57
+ assert result is not None
58
+ refs = result[0].expression_channel_references
59
+ assert refs is not None
60
+ assert refs[0].calculated_channel == "v-nested"
61
+ assert refs[0].channel_identifier is None
62
+
44
63
  @pytest.mark.asyncio
45
64
  async def test_keeps_identifier_when_not_found(self):
46
65
  api = MagicMock()
@@ -1,11 +1,31 @@
1
1
  """Unit tests for data import config models and helpers."""
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  from datetime import datetime, timezone
6
+ from typing import TYPE_CHECKING, cast
4
7
 
5
8
  import pytest
9
+ from sift.common.type.v1.channel_config_pb2 import ChannelConfig as ChannelConfigProto
10
+ from sift.data_imports.v2.data_imports_pb2 import (
11
+ ParquetColumn,
12
+ ParquetConfig,
13
+ ParquetFlatDatasetConfig,
14
+ ParquetSingleChannelPerRowConfig,
15
+ )
16
+ from sift.data_imports.v2.data_imports_pb2 import (
17
+ ParquetDataColumn as ParquetDataColumnProto,
18
+ )
19
+ from sift.data_imports.v2.data_imports_pb2 import (
20
+ ParquetTimeColumn as ParquetTimeColumnProto,
21
+ )
6
22
 
7
23
  from sift_client.resources import DataImportAPI, DataImportAPIAsync
8
- from sift_client.resources.data_imports import _resolve_data_type_key
24
+ from sift_client.resources.data_imports import (
25
+ _infer_time_column,
26
+ _parse_parquet_detect_response,
27
+ _resolve_data_type_key,
28
+ )
9
29
  from sift_client.sift_types.channel import ChannelDataType
10
30
  from sift_client.sift_types.data_import import (
11
31
  CsvDataColumn,
@@ -22,6 +42,11 @@ from sift_client.sift_types.data_import import (
22
42
  TimeFormat,
23
43
  )
24
44
 
45
+ if TYPE_CHECKING:
46
+ from sift.common.type.v1.channel_data_type_pb2 import (
47
+ ChannelDataType as ChannelDataTypeProto,
48
+ )
49
+
25
50
 
26
51
  @pytest.mark.integration
27
52
  def test_client_binding(sift_client):
@@ -362,3 +387,130 @@ class TestResolveDataTypeKey:
362
387
  def test_unknown_extension_raises(self):
363
388
  with pytest.raises(ValueError, match="Unsupported file extension"):
364
389
  _resolve_data_type_key(".xyz", None)
390
+
391
+
392
+ class TestInferTimeColumn:
393
+ def test_picks_canonical_skips_other_columns(self):
394
+ path = _infer_time_column(
395
+ [
396
+ ("delta_time", ChannelDataType.INT_64, "delta_time"),
397
+ ("voltage", ChannelDataType.DOUBLE, "voltage"),
398
+ ("timestamp", ChannelDataType.INT_64, "timestamp"),
399
+ ]
400
+ )
401
+ assert path == "timestamp"
402
+
403
+ def test_accepts_uint64(self):
404
+ path = _infer_time_column([("time", ChannelDataType.UINT_64, "time")])
405
+ assert path == "time"
406
+
407
+ def test_case_insensitive(self):
408
+ path = _infer_time_column([("TimeStamp", ChannelDataType.INT_64, "TimeStamp")])
409
+ assert path == "TimeStamp"
410
+
411
+ def test_multiple_candidates_sorted_alphabetically(self):
412
+ path = _infer_time_column(
413
+ [
414
+ ("timestamp", ChannelDataType.INT_64, "timestamp"),
415
+ ("time", ChannelDataType.INT_64, "time"),
416
+ ("ts", ChannelDataType.INT_64, "ts"),
417
+ ]
418
+ )
419
+ assert path == "time"
420
+
421
+ def test_returns_none_when_no_canonical_int_column(self):
422
+ path = _infer_time_column(
423
+ [
424
+ ("timestamp", ChannelDataType.DOUBLE, "timestamp"),
425
+ ("event_time", ChannelDataType.INT_64, "event_time"),
426
+ ]
427
+ )
428
+ assert path is None
429
+
430
+
431
+ def _make_flat_dataset_response(
432
+ time_path: str, data_columns: list[tuple[str, int]]
433
+ ) -> ParquetConfig:
434
+ return ParquetConfig(
435
+ flat_dataset=ParquetFlatDatasetConfig(
436
+ time_column=ParquetTimeColumnProto(path=time_path),
437
+ data_columns=[
438
+ ParquetDataColumnProto(
439
+ path=path,
440
+ channel_config=ChannelConfigProto(
441
+ name=path,
442
+ data_type=cast("ChannelDataTypeProto.ValueType", data_type),
443
+ ),
444
+ )
445
+ for path, data_type in data_columns
446
+ ],
447
+ )
448
+ )
449
+
450
+
451
+ def _make_scpr_response(time_path: str, columns: list[tuple[str, int]]) -> ParquetConfig:
452
+ return ParquetConfig(
453
+ single_channel_per_row=ParquetSingleChannelPerRowConfig(
454
+ time_column=ParquetTimeColumnProto(path=time_path),
455
+ columns=[
456
+ ParquetColumn(
457
+ path=path,
458
+ column_config=ChannelConfigProto(
459
+ name=path,
460
+ data_type=cast("ChannelDataTypeProto.ValueType", data_type),
461
+ ),
462
+ )
463
+ for path, data_type in columns
464
+ ],
465
+ )
466
+ )
467
+
468
+
469
+ class TestParseParquetDetectResponseTimeFallback:
470
+ def test_flat_dataset_infers_int64_time_column(self):
471
+ proto = _make_flat_dataset_response(
472
+ time_path="",
473
+ data_columns=[
474
+ ("voltage", ChannelDataType.DOUBLE.value),
475
+ ("timestamp", ChannelDataType.INT_64.value),
476
+ ("status", ChannelDataType.INT_32.value),
477
+ ],
478
+ )
479
+ config = _parse_parquet_detect_response(proto, "file.parquet", 0, 0)
480
+ assert isinstance(config, ParquetFlatDatasetImportConfig)
481
+ assert config.time_column.path == "timestamp"
482
+ assert [dc.path for dc in config.data_columns] == ["voltage", "status"]
483
+
484
+ def test_flat_dataset_keeps_server_time_column_when_set(self):
485
+ proto = _make_flat_dataset_response(
486
+ time_path="server_ts",
487
+ data_columns=[
488
+ ("server_ts", ChannelDataType.INT_64.value),
489
+ ("timestamp", ChannelDataType.INT_64.value),
490
+ ("voltage", ChannelDataType.DOUBLE.value),
491
+ ],
492
+ )
493
+ config = _parse_parquet_detect_response(proto, "file.parquet", 0, 0)
494
+ assert config.time_column.path == "server_ts"
495
+ assert [dc.path for dc in config.data_columns] == ["timestamp", "voltage"]
496
+
497
+ def test_flat_dataset_no_int64_match_leaves_time_empty(self):
498
+ proto = _make_flat_dataset_response(
499
+ time_path="",
500
+ data_columns=[("voltage", ChannelDataType.DOUBLE.value)],
501
+ )
502
+ config = _parse_parquet_detect_response(proto, "file.parquet", 0, 0)
503
+ assert config.time_column.path == ""
504
+ assert [dc.path for dc in config.data_columns] == ["voltage"]
505
+
506
+ def test_scpr_infers_int64_time_column(self):
507
+ proto = _make_scpr_response(
508
+ time_path="",
509
+ columns=[
510
+ ("voltage", ChannelDataType.DOUBLE.value),
511
+ ("timestamp", ChannelDataType.INT_64.value),
512
+ ],
513
+ )
514
+ config = _parse_parquet_detect_response(proto, "file.parquet", 0, 0)
515
+ assert isinstance(config, ParquetSingleChannelPerRowImportConfig)
516
+ assert config.time_column.path == "timestamp"
@@ -7,6 +7,7 @@ import pytest
7
7
 
8
8
  from sift_client.sift_types import CalculatedChannel
9
9
  from sift_client.sift_types.calculated_channel import (
10
+ CalculatedChannelCreate,
10
11
  CalculatedChannelUpdate,
11
12
  )
12
13
  from sift_client.sift_types.channel import ChannelReference
@@ -151,6 +152,68 @@ class TestCalculatedChannelBase:
151
152
  ],
152
153
  )
153
154
 
155
+ def test_nested_calculated_channel_reference_serialized_to_version_id_oneof(self):
156
+ """A ChannelReference with calculated_channel set routes to the proto oneof."""
157
+ update = CalculatedChannelUpdate(
158
+ expression="$1 + $2",
159
+ expression_channel_references=[
160
+ ChannelReference(channel_reference="$1", channel_identifier="channel1"),
161
+ ChannelReference(channel_reference="$2", calculated_channel="v-nested"),
162
+ ],
163
+ )
164
+ update.resource_id = "test_calc_channel_id"
165
+
166
+ proto, _ = update.to_proto_with_mask()
167
+
168
+ refs = proto.calculated_channel_configuration.query_configuration.sel.expression_channel_references
169
+ assert len(refs) == 2
170
+ assert refs[0].channel_identifier == "channel1"
171
+ assert refs[0].WhichOneof("calculated_channel_reference") is None
172
+ assert refs[1].WhichOneof("calculated_channel_reference") == "calculated_channel_version_id"
173
+ assert refs[1].calculated_channel_version_id == "v-nested"
174
+ assert refs[1].channel_identifier == ""
175
+
176
+ def test_create_serializes_nested_calculated_channel_reference(self):
177
+ """CalculatedChannelCreate.to_proto routes the version_id into the proto oneof."""
178
+ create = CalculatedChannelCreate(
179
+ name="nested-cc",
180
+ expression="$1 * 2",
181
+ expression_channel_references=[
182
+ ChannelReference(channel_reference="$1", calculated_channel="v-nested"),
183
+ ],
184
+ all_assets=True,
185
+ )
186
+
187
+ proto = create.to_proto()
188
+
189
+ refs = proto.calculated_channel_configuration.query_configuration.sel.expression_channel_references
190
+ assert len(refs) == 1
191
+ assert refs[0].WhichOneof("calculated_channel_reference") == "calculated_channel_version_id"
192
+ assert refs[0].calculated_channel_version_id == "v-nested"
193
+
194
+ def test_create_serializes_nested_reference_from_calculated_channel_object(
195
+ self, mock_calculated_channel
196
+ ):
197
+ """Passing a CalculatedChannel object to ChannelReference also serializes correctly."""
198
+ create = CalculatedChannelCreate(
199
+ name="nested-cc",
200
+ expression="$1 * 2",
201
+ expression_channel_references=[
202
+ ChannelReference(
203
+ channel_reference="$1", calculated_channel=mock_calculated_channel
204
+ ),
205
+ ],
206
+ all_assets=True,
207
+ )
208
+
209
+ proto = create.to_proto()
210
+
211
+ refs = proto.calculated_channel_configuration.query_configuration.sel.expression_channel_references
212
+ assert len(refs) == 1
213
+ assert refs[0].WhichOneof("calculated_channel_reference") == "calculated_channel_version_id"
214
+ # mock_calculated_channel fixture has version_id="v1"
215
+ assert refs[0].calculated_channel_version_id == "v1"
216
+
154
217
  def test_expression_validator_accepts_both_set(self):
155
218
  """Test validator accepts expression and channel references together."""
156
219
  # Should not raise
@@ -6,7 +6,7 @@ from unittest.mock import MagicMock
6
6
  import pytest
7
7
 
8
8
  from sift_client.sift_types import Channel
9
- from sift_client.sift_types.channel import ChannelDataType
9
+ from sift_client.sift_types.channel import ChannelDataType, ChannelReference
10
10
 
11
11
 
12
12
  @pytest.fixture
@@ -104,6 +104,100 @@ class TestChannel:
104
104
  mock_client.channels.get_data.assert_not_called()
105
105
  assert result == mock_data
106
106
 
107
+ def test_channel_reference_requires_one_target(self):
108
+ """ChannelReference must specify exactly one of identifier or calculated_channel."""
109
+ with pytest.raises(ValueError, match="exactly one"):
110
+ ChannelReference(channel_reference="$1")
111
+ with pytest.raises(ValueError, match="exactly one"):
112
+ ChannelReference(
113
+ channel_reference="$1",
114
+ channel_identifier="ch",
115
+ calculated_channel="v-id",
116
+ )
117
+
118
+ def test_channel_reference_accepts_version_id_string(self):
119
+ """A plain version_id string is stored as-is."""
120
+ ref = ChannelReference(channel_reference="$1", calculated_channel="v-abc")
121
+ assert ref.calculated_channel == "v-abc"
122
+ assert ref.channel_identifier is None
123
+
124
+ def test_channel_reference_accepts_calculated_channel_object(self):
125
+ """Passing a CalculatedChannel normalizes to its version_id string."""
126
+ from sift_client.sift_types.calculated_channel import CalculatedChannel
127
+
128
+ cc = CalculatedChannel(
129
+ proto=MagicMock(),
130
+ id_="cc-id",
131
+ name="parent",
132
+ description="",
133
+ expression="$1",
134
+ channel_references=[],
135
+ is_archived=False,
136
+ units=None,
137
+ asset_ids=["asset-1"],
138
+ tag_ids=None,
139
+ all_assets=False,
140
+ organization_id=None,
141
+ client_key=None,
142
+ archived_date=None,
143
+ version_id="v-abc",
144
+ version=1,
145
+ change_message=None,
146
+ user_notes=None,
147
+ created_date=datetime.now(timezone.utc),
148
+ modified_date=datetime.now(timezone.utc),
149
+ created_by_user_id="u",
150
+ modified_by_user_id="u",
151
+ )
152
+
153
+ ref = ChannelReference(channel_reference="$1", calculated_channel=cc)
154
+ assert ref.calculated_channel == "v-abc"
155
+
156
+ def test_channel_reference_rejects_calculated_channel_without_version_id(self):
157
+ """A CalculatedChannel missing version_id is unusable as a reference."""
158
+ from sift_client.sift_types.calculated_channel import CalculatedChannel
159
+
160
+ cc = CalculatedChannel(
161
+ proto=MagicMock(),
162
+ id_="cc-id",
163
+ name="parent",
164
+ description="",
165
+ expression="$1",
166
+ channel_references=[],
167
+ is_archived=False,
168
+ units=None,
169
+ asset_ids=["asset-1"],
170
+ tag_ids=None,
171
+ all_assets=False,
172
+ organization_id=None,
173
+ client_key=None,
174
+ archived_date=None,
175
+ version_id=None,
176
+ version=None,
177
+ change_message=None,
178
+ user_notes=None,
179
+ created_date=datetime.now(timezone.utc),
180
+ modified_date=datetime.now(timezone.utc),
181
+ created_by_user_id="u",
182
+ modified_by_user_id="u",
183
+ )
184
+
185
+ with pytest.raises(ValueError, match="no version_id"):
186
+ ChannelReference(channel_reference="$1", calculated_channel=cc)
187
+
188
+ def test_channel_reference_from_proto_reads_version_id_oneof(self):
189
+ """_from_proto picks calculated_channel when the proto oneof selects it."""
190
+ from sift.calculated_channels.v2.calculated_channels_pb2 import (
191
+ CalculatedChannelAbstractChannelReference,
192
+ )
193
+
194
+ proto = CalculatedChannelAbstractChannelReference(
195
+ channel_reference="$1", calculated_channel_version_id="v-abc"
196
+ )
197
+ ref = ChannelReference._from_proto(proto)
198
+ assert ref.calculated_channel == "v-abc"
199
+ assert ref.channel_identifier is None
200
+
107
201
  def test_data_method_with_minimal_params(self, mock_channel, mock_client):
108
202
  """Test that data() method works with minimal parameters."""
109
203
  mock_data = {"test_channel": MagicMock()}