floe-python 0.4.0__tar.gz → 0.4.1__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 (226) hide show
  1. {floe_python-0.4.0 → floe_python-0.4.1}/Cargo.lock +3 -3
  2. {floe_python-0.4.0 → floe_python-0.4.1}/PKG-INFO +1 -1
  3. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/Cargo.toml +2 -2
  4. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/config/mod.rs +4 -1
  5. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/config/parse.rs +2 -2
  6. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/config/storage.rs +1 -1
  7. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/config/validate.rs +7 -0
  8. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/iceberg.rs +35 -1
  9. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/lib.rs +26 -0
  10. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/profile/parse.rs +14 -0
  11. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/profile/types.rs +3 -1
  12. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/profile/validate.rs +102 -0
  13. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/run/context.rs +14 -0
  14. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/run/mod.rs +8 -0
  15. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/config/config_validation.rs +32 -0
  16. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-python/Cargo.toml +2 -2
  17. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-python/src/functions.rs +5 -1
  18. {floe_python-0.4.0 → floe_python-0.4.1}/pyproject.toml +1 -1
  19. {floe_python-0.4.0 → floe_python-0.4.1}/Cargo.toml +0 -0
  20. {floe_python-0.4.0 → floe_python-0.4.1}/README.md +0 -0
  21. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/README.md +0 -0
  22. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/add_entity.rs +0 -0
  23. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/checks/cast.rs +0 -0
  24. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/checks/mismatch.rs +0 -0
  25. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/checks/mod.rs +0 -0
  26. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/checks/normalize.rs +0 -0
  27. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/checks/not_null.rs +0 -0
  28. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/checks/unique.rs +0 -0
  29. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/config/catalog.rs +0 -0
  30. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/config/location.rs +0 -0
  31. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/config/template.rs +0 -0
  32. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/config/types.rs +0 -0
  33. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/config/yaml_decode.rs +0 -0
  34. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/errors.rs +0 -0
  35. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/format.rs +0 -0
  36. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/mod.rs +0 -0
  37. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/read/avro.rs +0 -0
  38. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/read/csv.rs +0 -0
  39. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/read/fixed_width.rs +0 -0
  40. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/read/json.rs +0 -0
  41. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/read/json_selector.rs +0 -0
  42. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/read/mod.rs +0 -0
  43. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/read/orc.rs +0 -0
  44. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/read/parquet.rs +0 -0
  45. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/read/xlsx.rs +0 -0
  46. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/read/xml.rs +0 -0
  47. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/read/xml_selector.rs +0 -0
  48. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/core/extensions.rs +0 -0
  49. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/core/mod.rs +0 -0
  50. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/core/paths.rs +0 -0
  51. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/core/placement.rs +0 -0
  52. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/core/planner.rs +0 -0
  53. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/core/uri.rs +0 -0
  54. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/core/validation.rs +0 -0
  55. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/mod.rs +0 -0
  56. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/object_store.rs +0 -0
  57. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/ops/archive.rs +0 -0
  58. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/ops/inputs.rs +0 -0
  59. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/ops/mod.rs +0 -0
  60. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/ops/output.rs +0 -0
  61. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/providers/adls.rs +0 -0
  62. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/providers/gcs.rs +0 -0
  63. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/providers/local.rs +0 -0
  64. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/providers/mod.rs +0 -0
  65. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/providers/s3.rs +0 -0
  66. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/storage/target.rs +0 -0
  67. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/unique_seed/mod.rs +0 -0
  68. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/accepted.rs +0 -0
  69. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/arrow_convert.rs +0 -0
  70. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/csv.rs +0 -0
  71. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/delta/commit_metrics.rs +0 -0
  72. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/delta/options.rs +0 -0
  73. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/delta/record_batch.rs +0 -0
  74. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/delta/unity.rs +0 -0
  75. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/delta/unity_tests.rs +0 -0
  76. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/delta.rs +0 -0
  77. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/iceberg/context.rs +0 -0
  78. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/iceberg/data_files.rs +0 -0
  79. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/iceberg/glue.rs +0 -0
  80. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/iceberg/metadata.rs +0 -0
  81. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/iceberg/rest.rs +0 -0
  82. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/iceberg/schema.rs +0 -0
  83. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/metrics.rs +0 -0
  84. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/mod.rs +0 -0
  85. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/parquet.rs +0 -0
  86. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/parts.rs +0 -0
  87. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/sink_format.rs +0 -0
  88. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/strategy/append.rs +0 -0
  89. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/strategy/merge/mod.rs +0 -0
  90. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/strategy/merge/scd1.rs +0 -0
  91. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/strategy/merge/scd2.rs +0 -0
  92. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/strategy/merge/shared.rs +0 -0
  93. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/strategy/mod.rs +0 -0
  94. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/io/write/strategy/overwrite.rs +0 -0
  95. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/lineage/mod.rs +0 -0
  96. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/log.rs +0 -0
  97. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/manifest/builder.rs +0 -0
  98. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/manifest/mod.rs +0 -0
  99. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/manifest/model.rs +0 -0
  100. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/profile/mod.rs +0 -0
  101. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/report/build.rs +0 -0
  102. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/report/entity.rs +0 -0
  103. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/report/mod.rs +0 -0
  104. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/report/output.rs +0 -0
  105. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/run/entity/accepted_write.rs +0 -0
  106. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/run/entity/incremental.rs +0 -0
  107. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/run/entity/mod.rs +0 -0
  108. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/run/entity/pii.rs +0 -0
  109. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/run/entity/precheck.rs +0 -0
  110. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/run/entity/process.rs +0 -0
  111. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/run/entity/resolve.rs +0 -0
  112. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/run/entity/validate_split.rs +0 -0
  113. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/run/events.rs +0 -0
  114. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/run/file.rs +0 -0
  115. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/run/output.rs +0 -0
  116. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/run/perf.rs +0 -0
  117. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/runner/mod.rs +0 -0
  118. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/runner/outcome.rs +0 -0
  119. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/runtime.rs +0 -0
  120. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/state/mod.rs +0 -0
  121. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/vars/mod.rs +0 -0
  122. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/vars/resolve.rs +0 -0
  123. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/src/warnings.rs +0 -0
  124. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/integration/archive_run.rs +0 -0
  125. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/integration/composite_unique.rs +0 -0
  126. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/integration/delta_run.rs +0 -0
  127. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/integration/dry_run.rs +0 -0
  128. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/integration/fixed_width.rs +0 -0
  129. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/integration/iceberg_gcs_run.rs +0 -0
  130. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/integration/iceberg_glue_run.rs +0 -0
  131. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/integration/iceberg_run.rs +0 -0
  132. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/integration/iceberg_s3_run.rs +0 -0
  133. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/integration/json_selectors.rs +0 -0
  134. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/integration/local_run.rs +0 -0
  135. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/integration/mod.rs +0 -0
  136. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/integration/path_normalization.rs +0 -0
  137. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/integration/run_entities_filter.rs +0 -0
  138. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/integration.rs +0 -0
  139. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/common.rs +0 -0
  140. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/config/add_entity.rs +0 -0
  141. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/config/adls_storage.rs +0 -0
  142. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/config/adls_validation.rs +0 -0
  143. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/config/catalogs.rs +0 -0
  144. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/config/gcs_storage.rs +0 -0
  145. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/config/gcs_validation.rs +0 -0
  146. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/config/lineage_validation.rs +0 -0
  147. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/config/local_storage.rs +0 -0
  148. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/config/mod.rs +0 -0
  149. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/config/parse.rs +0 -0
  150. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/config/pii_validation.rs +0 -0
  151. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/config/remote_base.rs +0 -0
  152. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/config/templating.rs +0 -0
  153. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/format.rs +0 -0
  154. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/mod.rs +0 -0
  155. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/read/avro_input.rs +0 -0
  156. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/read/csv_nulls.rs +0 -0
  157. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/read/json_array.rs +0 -0
  158. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/read/json_ndjson.rs +0 -0
  159. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/read/json_selector.rs +0 -0
  160. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/read/mod.rs +0 -0
  161. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/read/orc_input.rs +0 -0
  162. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/read/parquet_input.rs +0 -0
  163. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/read/tsv.rs +0 -0
  164. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/read/xlsx_input.rs +0 -0
  165. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/read/xml.rs +0 -0
  166. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/read/xml_selector.rs +0 -0
  167. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/storage/adls.rs +0 -0
  168. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/storage/adls_integration.rs +0 -0
  169. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/storage/gcs.rs +0 -0
  170. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/storage/inputs.rs +0 -0
  171. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/storage/local.rs +0 -0
  172. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/storage/mod.rs +0 -0
  173. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/storage/paths.rs +0 -0
  174. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/storage/planner.rs +0 -0
  175. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/storage/s3.rs +0 -0
  176. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/storage/target.rs +0 -0
  177. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/write/delta_merge.rs +0 -0
  178. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/write/delta_write.rs +0 -0
  179. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/write/iceberg_write.rs +0 -0
  180. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/write/metrics.rs +0 -0
  181. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/write/mod.rs +0 -0
  182. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/write/object_store.rs +0 -0
  183. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/write/parquet_write.rs +0 -0
  184. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/write/parts.rs +0 -0
  185. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/io/write/rejected_csv.rs +0 -0
  186. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/manifest/mod.rs +0 -0
  187. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/mod.rs +0 -0
  188. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/profile/mod.rs +0 -0
  189. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/profile/parse.rs +0 -0
  190. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/profile/validate.rs +0 -0
  191. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/report/accepted_output.rs +0 -0
  192. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/report/mod.rs +0 -0
  193. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/report/storage.rs +0 -0
  194. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/run/check_order.rs +0 -0
  195. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/run/checks.rs +0 -0
  196. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/run/entity/accepted_output.rs +0 -0
  197. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/run/entity/incremental.rs +0 -0
  198. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/run/entity/mod.rs +0 -0
  199. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/run/lineage.rs +0 -0
  200. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/run/mod.rs +0 -0
  201. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/run/normalize.rs +0 -0
  202. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/run/pii.rs +0 -0
  203. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/run/report.rs +0 -0
  204. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/run/schema_mismatch.rs +0 -0
  205. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/runner/adapter.rs +0 -0
  206. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/runner/mod.rs +0 -0
  207. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/state/mod.rs +0 -0
  208. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/vars/mod.rs +0 -0
  209. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit/vars/resolve.rs +0 -0
  210. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-core/tests/unit.rs +0 -0
  211. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-python/.gitignore +0 -0
  212. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-python/README.md +0 -0
  213. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-python/src/lib.rs +0 -0
  214. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-python/src/observer.rs +0 -0
  215. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-python/src/types/config.rs +0 -0
  216. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-python/src/types/errors.rs +0 -0
  217. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-python/src/types/mod.rs +0 -0
  218. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-python/src/types/outcome.rs +0 -0
  219. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-python/tests/fixtures/config.yml +0 -0
  220. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-python/tests/fixtures/in/customer/customers_valid.csv +0 -0
  221. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-python/tests/fixtures/invalid_config.yml +0 -0
  222. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-python/tests/fixtures/profile.yml +0 -0
  223. {floe_python-0.4.0 → floe_python-0.4.1}/crates/floe-python/tests/test_floe.py +0 -0
  224. {floe_python-0.4.0 → floe_python-0.4.1}/python/floe/__init__.py +0 -0
  225. {floe_python-0.4.0 → floe_python-0.4.1}/python/floe/_floe.pyi +0 -0
  226. {floe_python-0.4.0 → floe_python-0.4.1}/python/floe/py.typed +0 -0
@@ -3399,7 +3399,7 @@ dependencies = [
3399
3399
 
3400
3400
  [[package]]
3401
3401
  name = "floe-cli"
3402
- version = "0.4.0"
3402
+ version = "0.4.1"
3403
3403
  dependencies = [
3404
3404
  "assert_cmd",
3405
3405
  "clap",
@@ -3412,7 +3412,7 @@ dependencies = [
3412
3412
 
3413
3413
  [[package]]
3414
3414
  name = "floe-core"
3415
- version = "0.4.0"
3415
+ version = "0.4.1"
3416
3416
  dependencies = [
3417
3417
  "apache-avro 0.16.0",
3418
3418
  "arrow",
@@ -3455,7 +3455,7 @@ dependencies = [
3455
3455
 
3456
3456
  [[package]]
3457
3457
  name = "floe-python"
3458
- version = "0.4.0"
3458
+ version = "0.4.1"
3459
3459
  dependencies = [
3460
3460
  "floe-core",
3461
3461
  "pyo3",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: floe-python
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: Intended Audience :: Science/Research
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "floe-core"
3
- version = "0.4.0"
3
+ version = "0.4.1"
4
4
  edition = "2021"
5
5
  description = "Core library for Floe, a YAML-driven technical ingestion tool."
6
6
  license = "MIT"
@@ -41,7 +41,7 @@ uuid = "1"
41
41
  arrow = "57"
42
42
  iceberg = "0.9.0"
43
43
  iceberg-catalog-rest = "0.9.0"
44
- iceberg-storage-opendal = { version = "0.9.1", features = ["opendal-gcs"] }
44
+ iceberg-storage-opendal = { version = "0.9.1", features = ["opendal-s3", "opendal-gcs"] }
45
45
  df-interchange = { version = "0.3.2", features = ["arrow_57", "polars_0_52"] }
46
46
  orc-rust = "0.7.1"
47
47
 
@@ -13,6 +13,9 @@ pub use storage::{resolve_local_path, ConfigBase, ResolvedPath, StorageResolver}
13
13
  pub use types::*;
14
14
 
15
15
  pub use parse::extract_raw_env_vars;
16
- pub(crate) use parse::{parse_catalogs_with_context, parse_config, parse_config_with_vars};
16
+ pub(crate) use parse::{
17
+ parse_catalogs_with_context, parse_config, parse_config_with_vars, parse_lineage_config,
18
+ parse_storages,
19
+ };
17
20
  pub(crate) use template::apply_templates_with_vars;
18
21
  pub(crate) use validate::{extract_first_n, extract_last_n, validate_config};
@@ -658,7 +658,7 @@ fn parse_sink_delta_options(value: &Yaml, ctx: &str) -> FloeResult<DeltaSinkTarg
658
658
  })
659
659
  }
660
660
 
661
- fn parse_storages(value: &Yaml) -> FloeResult<StoragesConfig> {
661
+ pub(crate) fn parse_storages(value: &Yaml) -> FloeResult<StoragesConfig> {
662
662
  let hash = yaml_hash(value, "storages")?;
663
663
  validate_known_keys(hash, "storages", &["default", "definitions"])?;
664
664
  let definitions_yaml = match hash_get(hash, "definitions") {
@@ -1129,7 +1129,7 @@ fn parse_pii_column(value: &Yaml) -> FloeResult<PiiColumnConfig> {
1129
1129
  })
1130
1130
  }
1131
1131
 
1132
- fn parse_lineage_config(value: &Yaml) -> FloeResult<LineageConfig> {
1132
+ pub(crate) fn parse_lineage_config(value: &Yaml) -> FloeResult<LineageConfig> {
1133
1133
  let hash = yaml_hash(value, "lineage")?;
1134
1134
  validate_known_keys(
1135
1135
  hash,
@@ -615,7 +615,7 @@ fn parent_prefix(key: &str) -> String {
615
615
  }
616
616
  }
617
617
 
618
- fn is_remote_uri(value: &str) -> bool {
618
+ pub(crate) fn is_remote_uri(value: &str) -> bool {
619
619
  value.starts_with("s3://") || value.starts_with("gs://") || value.starts_with("abfs://")
620
620
  }
621
621
 
@@ -1,5 +1,6 @@
1
1
  use std::collections::HashSet;
2
2
 
3
+ use crate::config::storage::is_remote_uri;
3
4
  use crate::config::{
4
5
  CatalogDefinition, CatalogTypeConfig, EntityConfig, IncrementalMode, PolicySeverity,
5
6
  RootConfig, SourceOptions, StorageDefinition,
@@ -128,6 +129,12 @@ fn validate_report(
128
129
  ) -> FloeResult<()> {
129
130
  let storage_name = storages.resolve_report_name(report.storage.as_deref())?;
130
131
  storages.validate_report_reference("report.storage", &storage_name)?;
132
+ if storages.definition_type(&storage_name) == Some("local") && is_remote_uri(&report.path) {
133
+ return Err(Box::new(ConfigError(format!(
134
+ "report.path must be a local path (got {})",
135
+ report.path
136
+ ))));
137
+ }
131
138
  Ok(())
132
139
  }
133
140
 
@@ -8,6 +8,7 @@ use iceberg::memory::{MemoryCatalogBuilder, MEMORY_CATALOG_WAREHOUSE};
8
8
  use iceberg::spec::{Schema, UnboundPartitionSpec};
9
9
  use iceberg::transaction::{ApplyTransactionAction, Transaction};
10
10
  use iceberg::{Catalog, CatalogBuilder, NamespaceIdent, TableIdent};
11
+ use iceberg_storage_opendal::OpenDalStorageFactory;
11
12
  use polars::prelude::DataFrame;
12
13
 
13
14
  use crate::errors::RunError;
@@ -375,6 +376,7 @@ async fn write_iceberg_table_async(
375
376
  catalog_props.insert(MEMORY_CATALOG_WAREHOUSE.to_string(), table_root_uri.clone());
376
377
 
377
378
  let is_local = !table_root_uri.starts_with("s3://")
379
+ && !table_root_uri.starts_with("s3a://")
378
380
  && !table_root_uri.starts_with("gs://")
379
381
  && !table_root_uri.starts_with("az://")
380
382
  && !table_root_uri.starts_with("abfss://");
@@ -382,6 +384,20 @@ async fn write_iceberg_table_async(
382
384
  if is_local {
383
385
  catalog_builder =
384
386
  catalog_builder.with_storage_factory(std::sync::Arc::new(LocalFsStorageFactory));
387
+ } else if table_root_uri.starts_with("s3://") || table_root_uri.starts_with("s3a://") {
388
+ let scheme = table_root_uri
389
+ .split("://")
390
+ .next()
391
+ .unwrap_or("s3")
392
+ .to_string();
393
+ catalog_builder =
394
+ catalog_builder.with_storage_factory(std::sync::Arc::new(OpenDalStorageFactory::S3 {
395
+ configured_scheme: scheme,
396
+ customized_credential_load: None,
397
+ }));
398
+ } else if table_root_uri.starts_with("gs://") {
399
+ catalog_builder =
400
+ catalog_builder.with_storage_factory(std::sync::Arc::new(OpenDalStorageFactory::Gcs));
385
401
  }
386
402
  let catalog = catalog_builder
387
403
  .load(catalog_name, catalog_props)
@@ -698,17 +714,35 @@ async fn collect_iceberg_batches(
698
714
  use iceberg::{Catalog, CatalogBuilder, NamespaceIdent, TableIdent};
699
715
 
700
716
  let is_local = !warehouse_location.starts_with("s3://")
717
+ && !warehouse_location.starts_with("s3a://")
701
718
  && !warehouse_location.starts_with("gs://")
702
719
  && !warehouse_location.starts_with("az://")
703
720
  && !warehouse_location.starts_with("abfss://");
704
721
 
705
722
  let mut props = catalog_props;
706
- props.insert(MEMORY_CATALOG_WAREHOUSE.to_string(), warehouse_location);
723
+ props.insert(
724
+ MEMORY_CATALOG_WAREHOUSE.to_string(),
725
+ warehouse_location.clone(),
726
+ );
707
727
 
708
728
  let mut catalog_builder = MemoryCatalogBuilder::default();
709
729
  if is_local {
710
730
  catalog_builder =
711
731
  catalog_builder.with_storage_factory(std::sync::Arc::new(LocalFsStorageFactory));
732
+ } else if warehouse_location.starts_with("s3://") || warehouse_location.starts_with("s3a://") {
733
+ let scheme = warehouse_location
734
+ .split("://")
735
+ .next()
736
+ .unwrap_or("s3")
737
+ .to_string();
738
+ catalog_builder =
739
+ catalog_builder.with_storage_factory(std::sync::Arc::new(OpenDalStorageFactory::S3 {
740
+ configured_scheme: scheme,
741
+ customized_credential_load: None,
742
+ }));
743
+ } else if warehouse_location.starts_with("gs://") {
744
+ catalog_builder =
745
+ catalog_builder.with_storage_factory(std::sync::Arc::new(OpenDalStorageFactory::Gcs));
712
746
  }
713
747
  let catalog = catalog_builder.load(ICEBERG_CATALOG_NAME, props).await?;
714
748
 
@@ -40,6 +40,8 @@ pub struct ValidateOptions {
40
40
  pub entities: Vec<String>,
41
41
  pub profile_vars: std::collections::HashMap<String, String>,
42
42
  pub profile_catalogs: Option<config::CatalogsConfig>,
43
+ pub profile_storages: Option<config::StoragesConfig>,
44
+ pub profile_lineage: Option<config::LineageConfig>,
43
45
  }
44
46
 
45
47
  #[derive(Debug, Default)]
@@ -62,6 +64,8 @@ pub fn validate_with_base(
62
64
  ) -> FloeResult<()> {
63
65
  let mut config = config::parse_config_with_vars(config_path, &options.profile_vars)?;
64
66
  apply_profile_catalogs(&mut config, options.profile_catalogs.as_ref());
67
+ apply_profile_storages(&mut config, options.profile_storages.as_ref());
68
+ apply_profile_lineage(&mut config, options.profile_lineage.as_ref());
65
69
  config::validate_config(&config)?;
66
70
 
67
71
  if !options.entities.is_empty() {
@@ -86,9 +90,13 @@ pub fn load_config_with_profile_overrides(
86
90
  config_path: &Path,
87
91
  profile_vars: &std::collections::HashMap<String, String>,
88
92
  profile_catalogs: Option<&config::CatalogsConfig>,
93
+ profile_storages: Option<&config::StoragesConfig>,
94
+ profile_lineage: Option<&config::LineageConfig>,
89
95
  ) -> FloeResult<config::RootConfig> {
90
96
  let mut config = config::parse_config_with_vars(config_path, profile_vars)?;
91
97
  apply_profile_catalogs(&mut config, profile_catalogs);
98
+ apply_profile_storages(&mut config, profile_storages);
99
+ apply_profile_lineage(&mut config, profile_lineage);
92
100
  Ok(config)
93
101
  }
94
102
 
@@ -107,6 +115,24 @@ pub(crate) fn apply_profile_catalogs(
107
115
  }
108
116
  }
109
117
 
118
+ pub(crate) fn apply_profile_storages(
119
+ config: &mut config::RootConfig,
120
+ profile_storages: Option<&config::StoragesConfig>,
121
+ ) {
122
+ if let Some(storages) = profile_storages {
123
+ config.storages = Some(storages.clone());
124
+ }
125
+ }
126
+
127
+ pub(crate) fn apply_profile_lineage(
128
+ config: &mut config::RootConfig,
129
+ profile_lineage: Option<&config::LineageConfig>,
130
+ ) {
131
+ if let Some(lineage) = profile_lineage {
132
+ config.lineage = Some(lineage.clone());
133
+ }
134
+ }
135
+
110
136
  pub fn extract_config_env_vars(
111
137
  config_path: &Path,
112
138
  ) -> FloeResult<std::collections::HashMap<String, String>> {
@@ -56,6 +56,8 @@ fn parse_profile_doc(doc: &Yaml) -> FloeResult<ProfileConfig> {
56
56
  "execution",
57
57
  "variables",
58
58
  "catalogs",
59
+ "storages",
60
+ "lineage",
59
61
  "validation",
60
62
  ],
61
63
  )?;
@@ -98,6 +100,16 @@ fn parse_profile_doc(doc: &Yaml) -> FloeResult<ProfileConfig> {
98
100
  None => None,
99
101
  };
100
102
 
103
+ let storages = match hash_get(root, "storages") {
104
+ Some(value) => Some(crate::config::parse_storages(value)?),
105
+ None => None,
106
+ };
107
+
108
+ let lineage = match hash_get(root, "lineage") {
109
+ Some(value) => Some(crate::config::parse_lineage_config(value)?),
110
+ None => None,
111
+ };
112
+
101
113
  let validation = match hash_get(root, "validation") {
102
114
  Some(value) => Some(parse_validation(value)?),
103
115
  None => None,
@@ -110,6 +122,8 @@ fn parse_profile_doc(doc: &Yaml) -> FloeResult<ProfileConfig> {
110
122
  execution,
111
123
  variables,
112
124
  catalogs,
125
+ storages,
126
+ lineage,
113
127
  validation,
114
128
  })
115
129
  }
@@ -1,6 +1,6 @@
1
1
  use std::collections::HashMap;
2
2
 
3
- use crate::config::CatalogsConfig;
3
+ use crate::config::{CatalogsConfig, LineageConfig, StoragesConfig};
4
4
 
5
5
  /// Top-level profile document (apiVersion + kind + sections).
6
6
  #[derive(Debug, Clone)]
@@ -11,6 +11,8 @@ pub struct ProfileConfig {
11
11
  pub execution: Option<ProfileExecution>,
12
12
  pub variables: HashMap<String, String>,
13
13
  pub catalogs: Option<CatalogsConfig>,
14
+ pub storages: Option<StoragesConfig>,
15
+ pub lineage: Option<LineageConfig>,
14
16
  pub validation: Option<ProfileValidation>,
15
17
  }
16
18
 
@@ -1,5 +1,6 @@
1
1
  use std::collections::{HashMap, HashSet};
2
2
 
3
+ use crate::config::{LineageConfig, StoragesConfig};
3
4
  use crate::profile::types::{ProfileConfig, ProfileRunner};
4
5
  use crate::{ConfigError, FloeResult};
5
6
 
@@ -25,6 +26,12 @@ pub fn validate_profile(profile: &ProfileConfig) -> FloeResult<()> {
25
26
 
26
27
  validate_no_malformed_vars(&profile.variables)?;
27
28
  validate_profile_catalogs(profile)?;
29
+ if let Some(storages) = &profile.storages {
30
+ validate_profile_storages(storages)?;
31
+ }
32
+ if let Some(lineage) = &profile.lineage {
33
+ validate_profile_lineage(lineage)?;
34
+ }
28
35
 
29
36
  Ok(())
30
37
  }
@@ -66,6 +73,101 @@ fn validate_profile_catalogs(profile: &ProfileConfig) -> FloeResult<()> {
66
73
  Ok(())
67
74
  }
68
75
 
76
+ fn validate_profile_storages(storages: &StoragesConfig) -> FloeResult<()> {
77
+ if storages.definitions.is_empty() {
78
+ return Err(Box::new(ConfigError(
79
+ "profile.storages.definitions must not be empty".to_string(),
80
+ )));
81
+ }
82
+ const ALLOWED_STORAGE_TYPES: &[&str] = &["local", "s3", "adls", "gcs"];
83
+ let mut names = HashSet::new();
84
+ for definition in &storages.definitions {
85
+ if definition.name.trim().is_empty() {
86
+ return Err(Box::new(ConfigError(
87
+ "profile.storages.definitions.name must not be empty".to_string(),
88
+ )));
89
+ }
90
+ if !names.insert(definition.name.as_str()) {
91
+ return Err(Box::new(ConfigError(format!(
92
+ "profile.storages.definitions name={} is duplicated",
93
+ definition.name
94
+ ))));
95
+ }
96
+ if !ALLOWED_STORAGE_TYPES.contains(&definition.fs_type.as_str()) {
97
+ return Err(Box::new(ConfigError(format!(
98
+ "profile.storages.definitions name={} type={} is unsupported (allowed: {})",
99
+ definition.name,
100
+ definition.fs_type,
101
+ ALLOWED_STORAGE_TYPES.join(", ")
102
+ ))));
103
+ }
104
+ if definition.fs_type == "s3" {
105
+ if definition.bucket.is_none() {
106
+ return Err(Box::new(ConfigError(format!(
107
+ "profile.storages.definitions name={} requires bucket for type s3",
108
+ definition.name
109
+ ))));
110
+ }
111
+ if definition.region.is_none() {
112
+ return Err(Box::new(ConfigError(format!(
113
+ "profile.storages.definitions name={} requires region for type s3",
114
+ definition.name
115
+ ))));
116
+ }
117
+ }
118
+ if definition.fs_type == "adls" {
119
+ if definition.account.is_none() {
120
+ return Err(Box::new(ConfigError(format!(
121
+ "profile.storages.definitions name={} requires account for type adls",
122
+ definition.name
123
+ ))));
124
+ }
125
+ if definition.container.is_none() {
126
+ return Err(Box::new(ConfigError(format!(
127
+ "profile.storages.definitions name={} requires container for type adls",
128
+ definition.name
129
+ ))));
130
+ }
131
+ }
132
+ if definition.fs_type == "gcs" && definition.bucket.is_none() {
133
+ return Err(Box::new(ConfigError(format!(
134
+ "profile.storages.definitions name={} requires bucket for type gcs",
135
+ definition.name
136
+ ))));
137
+ }
138
+ }
139
+ let Some(default_name) = &storages.default else {
140
+ return Err(Box::new(ConfigError(
141
+ "profile.storages.default is required when storages is set".to_string(),
142
+ )));
143
+ };
144
+ if !names.contains(default_name.as_str()) {
145
+ return Err(Box::new(ConfigError(format!(
146
+ "profile.storages.default={default_name} does not match any definition"
147
+ ))));
148
+ }
149
+ Ok(())
150
+ }
151
+
152
+ fn validate_profile_lineage(lineage: &LineageConfig) -> FloeResult<()> {
153
+ if lineage.url.trim().is_empty() {
154
+ return Err(Box::new(ConfigError(
155
+ "profile.lineage.url must not be empty".to_string(),
156
+ )));
157
+ }
158
+ if lineage.namespace.trim().is_empty() {
159
+ return Err(Box::new(ConfigError(
160
+ "profile.lineage.namespace must not be empty".to_string(),
161
+ )));
162
+ }
163
+ if lineage.max_failures == Some(0) {
164
+ return Err(Box::new(ConfigError(
165
+ "profile.lineage.max_failures must be at least 1".to_string(),
166
+ )));
167
+ }
168
+ Ok(())
169
+ }
170
+
69
171
  /// Validate a variable map produced by merging sources in precedence order:
70
172
  ///
71
173
  /// config variables > CLI overrides > profile variables
@@ -33,6 +33,20 @@ impl RunContext {
33
33
  .as_ref()
34
34
  .and_then(|profile| profile.catalogs.as_ref()),
35
35
  );
36
+ crate::apply_profile_storages(
37
+ &mut config,
38
+ options
39
+ .profile
40
+ .as_ref()
41
+ .and_then(|profile| profile.storages.as_ref()),
42
+ );
43
+ crate::apply_profile_lineage(
44
+ &mut config,
45
+ options
46
+ .profile
47
+ .as_ref()
48
+ .and_then(|profile| profile.lineage.as_ref()),
49
+ );
36
50
  let storage_resolver = config::StorageResolver::new(&config, config_base)?;
37
51
  let catalog_resolver = config::CatalogResolver::new(&config)?;
38
52
  let config_dir =
@@ -120,6 +120,14 @@ pub fn run_with_runtime(
120
120
  .profile
121
121
  .as_ref()
122
122
  .and_then(|profile| profile.catalogs.clone()),
123
+ profile_storages: options
124
+ .profile
125
+ .as_ref()
126
+ .and_then(|profile| profile.storages.clone()),
127
+ profile_lineage: options
128
+ .profile
129
+ .as_ref()
130
+ .and_then(|profile| profile.lineage.clone()),
123
131
  };
124
132
  crate::validate_with_base(config_path, config_base.clone(), validate_options)?;
125
133
  let context = RunContext::new(config_path, config_base, &options, profile_vars)?;
@@ -109,6 +109,38 @@ entities:
109
109
  assert_validation_ok(&yaml);
110
110
  }
111
111
 
112
+ #[test]
113
+ fn remote_report_path_rejected_when_storage_is_local() {
114
+ let yaml = format!(
115
+ r#"version: "0.1"
116
+ report:
117
+ path: "s3://floe-demo-bucket/reports"
118
+ entities:
119
+ {}"#,
120
+ base_entity("customer")
121
+ );
122
+ assert_validation_error(
123
+ &yaml,
124
+ &["report.path must be a local path (got s3://floe-demo-bucket/reports)"],
125
+ );
126
+ }
127
+
128
+ #[test]
129
+ fn remote_report_path_rejected_for_gcs() {
130
+ let yaml = format!(
131
+ r#"version: "0.1"
132
+ report:
133
+ path: "gs://floe-demo-bucket/reports"
134
+ entities:
135
+ {}"#,
136
+ base_entity("customer")
137
+ );
138
+ assert_validation_error(
139
+ &yaml,
140
+ &["report.path must be a local path (got gs://floe-demo-bucket/reports)"],
141
+ );
142
+ }
143
+
112
144
  #[test]
113
145
  fn supported_config_versions_are_valid() {
114
146
  for version in &["0.2", "0.3"] {
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "floe-python"
3
- version = "0.4.0"
3
+ version = "0.4.1"
4
4
  edition = "2021"
5
5
  description = "Python bindings for floe-core (PyO3-based)"
6
6
  license = "Apache-2.0"
@@ -14,7 +14,7 @@ name = "_floe"
14
14
  crate-type = ["cdylib"]
15
15
 
16
16
  [dependencies]
17
- floe-core = { path = "../floe-core", version = "0.4.0" }
17
+ floe-core = { path = "../floe-core", version = "0.4.1" }
18
18
  pyo3 = { version = "0.22", features = ["extension-module", "abi3-py310"] }
19
19
  serde_json = "1"
20
20
 
@@ -38,6 +38,8 @@ fn load_optional_profile(
38
38
  variables: vars,
39
39
  validation: None,
40
40
  catalogs: None,
41
+ storages: None,
42
+ lineage: None,
41
43
  })),
42
44
  }
43
45
  }
@@ -59,7 +61,9 @@ pub fn validate(
59
61
  .as_ref()
60
62
  .map(|p| p.variables.clone())
61
63
  .unwrap_or_default(),
62
- profile_catalogs: profile.and_then(|p| p.catalogs),
64
+ profile_catalogs: profile.as_ref().and_then(|p| p.catalogs.clone()),
65
+ profile_storages: profile.as_ref().and_then(|p| p.storages.clone()),
66
+ profile_lineage: profile.and_then(|p| p.lineage),
63
67
  };
64
68
  py.allow_threads(|| floe_core::validate(&path, options))
65
69
  .map_err(to_py_err)
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "floe-python"
7
- version = "0.4.0"
7
+ version = "0.4.1"
8
8
  description = "Python bindings for floe-core — run floe pipelines at Rust speed from Python and notebooks"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
File without changes
File without changes