pysits 2.0.0.dev8__tar.gz → 2.0.0.dev10__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 (220) hide show
  1. pysits-2.0.0.dev10/.claude/settings.local.json +7 -0
  2. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/PKG-INFO +1 -1
  3. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pyproject.toml +1 -1
  4. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/__init__.py +10 -0
  5. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/backend/functions.py +3 -0
  6. pysits-2.0.0.dev10/pysits/docs/content/sits_config_to_hf.md +46 -0
  7. pysits-2.0.0.dev10/pysits/docs/content/sits_from_hf.md +85 -0
  8. pysits-2.0.0.dev10/pysits/docs/content/sits_from_parquet.md +26 -0
  9. pysits-2.0.0.dev10/pysits/docs/content/sits_to_hf.md +76 -0
  10. pysits-2.0.0.dev10/pysits/docs/content/sits_to_parquet.md +23 -0
  11. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/exporters/__init__.py +13 -1
  12. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/exporters/files.py +30 -0
  13. pysits-2.0.0.dev10/pysits/sits/exporters/hf.py +74 -0
  14. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_exporters.py +51 -1
  15. pysits-2.0.0.dev10/tests/test_exporters_hf.py +154 -0
  16. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/uv.lock +1 -1
  17. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/.gitattributes +0 -0
  18. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/.github/actions/setup-pysits/action.yml +0 -0
  19. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/.github/workflows/ruff.yaml +0 -0
  20. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/.github/workflows/tests.yaml +0 -0
  21. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/.gitignore +0 -0
  22. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/.pre-commit-config.yaml +0 -0
  23. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/LICENSE +0 -0
  24. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/README.md +0 -0
  25. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/conda/meta.yaml +0 -0
  26. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/backend/__init__.py +0 -0
  27. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/backend/arrow.py +0 -0
  28. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/backend/loaders.py +0 -0
  29. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/backend/pkgs.py +0 -0
  30. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/backend/rinterface.py +0 -0
  31. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/conversions/__init__.py +0 -0
  32. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/conversions/clojure.py +0 -0
  33. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/conversions/common.py +0 -0
  34. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/conversions/decorators.py +0 -0
  35. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/conversions/dsl/__init__.py +0 -0
  36. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/conversions/dsl/base.py +0 -0
  37. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/conversions/dsl/mask.py +0 -0
  38. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/conversions/dsl/tuning.py +0 -0
  39. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/conversions/stac.py +0 -0
  40. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/conversions/tibble.py +0 -0
  41. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/conversions/vector.py +0 -0
  42. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/conversions/xarray.py +0 -0
  43. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/__init__.py +0 -0
  44. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/impute_linear.md +0 -0
  45. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/impute_mean.md +0 -0
  46. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/impute_mean_window.md +0 -0
  47. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/impute_median.md +0 -0
  48. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/plot.md +0 -0
  49. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_accuracy.md +0 -0
  50. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_accuracy_summary.md +0 -0
  51. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_add_base_cube.md +0 -0
  52. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_apply.md +0 -0
  53. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_as_geopandas.md +0 -0
  54. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_bands.md +0 -0
  55. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_barlow_twins.md +0 -0
  56. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_bbox.md +0 -0
  57. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_classify.md +0 -0
  58. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_clean.md +0 -0
  59. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_cluster_clean.md +0 -0
  60. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_cluster_dendro.md +0 -0
  61. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_cluster_frequency.md +0 -0
  62. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_colors.md +0 -0
  63. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_colors_qgis.md +0 -0
  64. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_colors_reset.md +0 -0
  65. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_colors_set.md +0 -0
  66. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_colors_show.md +0 -0
  67. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_combine_predictions.md +0 -0
  68. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_confidence_sampling.md +0 -0
  69. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_config.md +0 -0
  70. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_config_show.md +0 -0
  71. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_config_user_file.md +0 -0
  72. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_contrastive_learning.md +0 -0
  73. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_cube.md +0 -0
  74. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_cube_copy.md +0 -0
  75. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_encode.md +0 -0
  76. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_formula_linear.md +0 -0
  77. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_formula_logref.md +0 -0
  78. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_geo_dist.md +0 -0
  79. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_get_class.md +0 -0
  80. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_get_data.md +0 -0
  81. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_get_probs.md +0 -0
  82. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_kfold_validate.md +0 -0
  83. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_label_classification.md +0 -0
  84. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_labels.md +0 -0
  85. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_labels_summary.md +0 -0
  86. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_lightgbm.md +0 -0
  87. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_lighttae.md +0 -0
  88. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_list_collections.md +0 -0
  89. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_lstm_fcn.md +0 -0
  90. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_merge.md +0 -0
  91. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_mixture_model.md +0 -0
  92. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_mlp.md +0 -0
  93. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_model_export.md +0 -0
  94. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_mosaic.md +0 -0
  95. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_parallel.md +0 -0
  96. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_patterns.md +0 -0
  97. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_pre_train.md +0 -0
  98. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_pred_features.md +0 -0
  99. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_pred_normalize.md +0 -0
  100. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_pred_references.md +0 -0
  101. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_pred_sample.md +0 -0
  102. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_predictors.md +0 -0
  103. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_random_sampling.md +0 -0
  104. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_reclassify.md +0 -0
  105. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_reduce.md +0 -0
  106. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_reduce_imbalance.md +0 -0
  107. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_regularize.md +0 -0
  108. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_resnet.md +0 -0
  109. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_rfor.md +0 -0
  110. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_roi_to_tiles.md +0 -0
  111. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_sample.md +0 -0
  112. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_sampling_design.md +0 -0
  113. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_sankey.md +0 -0
  114. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_segment.md +0 -0
  115. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_select.md +0 -0
  116. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_show_prediction.md +0 -0
  117. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_slic.md +0 -0
  118. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_smooth.md +0 -0
  119. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_snic.md +0 -0
  120. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_som_clean_samples.md +0 -0
  121. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_som_evaluate_cluster.md +0 -0
  122. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_som_map.md +0 -0
  123. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_som_remove_samples.md +0 -0
  124. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_ssl_lejepa.md +0 -0
  125. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_ssl_mae.md +0 -0
  126. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_ssl_vicreg.md +0 -0
  127. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_stats.md +0 -0
  128. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_stratified_sampling.md +0 -0
  129. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_svm.md +0 -0
  130. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_tae.md +0 -0
  131. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_tempcnn.md +0 -0
  132. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_texture.md +0 -0
  133. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_tiles_to_roi.md +0 -0
  134. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_timeline.md +0 -0
  135. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_timeseries_to_csv.md +0 -0
  136. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_to_csv.md +0 -0
  137. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_to_xlsx.md +0 -0
  138. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_train.md +0 -0
  139. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_tuning.md +0 -0
  140. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_tuning_hparams.md +0 -0
  141. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_uncertainty.md +0 -0
  142. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_uncertainty_sampling.md +0 -0
  143. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_validate.md +0 -0
  144. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_variance.md +0 -0
  145. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_view.md +0 -0
  146. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/sits_xgboost.md +0 -0
  147. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/content/summary.md +0 -0
  148. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/docs/decorators.py +0 -0
  149. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/extras/__init__.py +0 -0
  150. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/extras/earthdatalogin.py +0 -0
  151. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/extras/torch.py +0 -0
  152. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/jinja.py +0 -0
  153. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/__init__.py +0 -0
  154. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/base.py +0 -0
  155. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/data/__init__.py +0 -0
  156. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/data/accuracy.py +0 -0
  157. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/data/base.py +0 -0
  158. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/data/cube.py +0 -0
  159. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/data/frame.py +0 -0
  160. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/data/frame_accessor.py +0 -0
  161. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/data/matrix.py +0 -0
  162. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/data/table.py +0 -0
  163. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/data/ts.py +0 -0
  164. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/data/tuning.py +0 -0
  165. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/data/vector.py +0 -0
  166. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/frame.py +0 -0
  167. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/ml.py +0 -0
  168. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/resolver.py +0 -0
  169. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/models/visual.py +0 -0
  170. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/network.py +0 -0
  171. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/settings.py +0 -0
  172. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/__init__.py +0 -0
  173. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/colors.py +0 -0
  174. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/config.py +0 -0
  175. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/context.py +0 -0
  176. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/cube.py +0 -0
  177. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/data.py +0 -0
  178. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/exporters/sf.py +0 -0
  179. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/exporters/xarray.py +0 -0
  180. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/impute.py +0 -0
  181. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/ml.py +0 -0
  182. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/segment.py +0 -0
  183. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/tiles.py +0 -0
  184. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/ts.py +0 -0
  185. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/tuning.py +0 -0
  186. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/utils.py +0 -0
  187. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/sits/visualization.py +0 -0
  188. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/templates/cube.html +0 -0
  189. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/templates/plot.html +0 -0
  190. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/templates/tuning.html +0 -0
  191. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/visualization/__init__.py +0 -0
  192. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/visualization/base.py +0 -0
  193. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/visualization/device.py +0 -0
  194. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/visualization/host.py +0 -0
  195. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/visualization/leaflet.py +0 -0
  196. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/pysits/visualization/options.py +0 -0
  197. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/conftest.py +0 -0
  198. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_backend.py +0 -0
  199. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_classification.py +0 -0
  200. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_config.py +0 -0
  201. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_conversions.py +0 -0
  202. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_cube.py +0 -0
  203. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_data.py +0 -0
  204. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_dsl.py +0 -0
  205. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_embedding.py +0 -0
  206. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_exporters_geopandas.py +0 -0
  207. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_exporters_xarray.py +0 -0
  208. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_extras.py +0 -0
  209. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_indexing.py +0 -0
  210. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_ml_models.py +0 -0
  211. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_network.py +0 -0
  212. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_resolver.py +0 -0
  213. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_rl_models.py +0 -0
  214. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_som.py +0 -0
  215. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_tiles.py +0 -0
  216. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_tuning.py +0 -0
  217. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_utils.py +0 -0
  218. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_validation.py +0 -0
  219. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_visual_models.py +0 -0
  220. {pysits-2.0.0.dev8 → pysits-2.0.0.dev10}/tests/test_visualization.py +0 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "mcp__claude_ai_SITS_MCP__sits_get_function"
5
+ ]
6
+ }
7
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pysits
3
- Version: 2.0.0.dev8
3
+ Version: 2.0.0.dev10
4
4
  Summary: Python wrapper for the sits R package
5
5
  Project-URL: Homepage, https://github.com/e-sensing/pysits
6
6
  Project-URL: Issue Tracker, https://github.com/e-sensing/pysits/issues
@@ -17,7 +17,7 @@
17
17
 
18
18
  [project]
19
19
  name = "pysits"
20
- version = "2.0.0.dev8"
20
+ version = "2.0.0.dev10"
21
21
  description = "Python wrapper for the sits R package"
22
22
  readme = "README.md"
23
23
  requires-python = ">=3.10,<4"
@@ -87,8 +87,13 @@ from .sits.data import sits_summary as summary
87
87
  from .sits.exporters import (
88
88
  sits_as_geopandas,
89
89
  sits_as_xarray,
90
+ sits_config_to_hf,
91
+ sits_from_hf,
92
+ sits_from_parquet,
90
93
  sits_timeseries_to_csv,
91
94
  sits_to_csv,
95
+ sits_to_hf,
96
+ sits_to_parquet,
92
97
  sits_to_xlsx,
93
98
  )
94
99
  from .sits.impute import (
@@ -276,6 +281,11 @@ __all__ = (
276
281
  "sits_as_geopandas",
277
282
  "sits_to_xlsx",
278
283
  "sits_timeseries_to_csv",
284
+ "sits_to_parquet",
285
+ "sits_from_parquet",
286
+ "sits_to_hf",
287
+ "sits_from_hf",
288
+ "sits_config_to_hf",
279
289
  # Tuning
280
290
  "sits_tuning_hparams",
281
291
  "sits_tuning",
@@ -58,5 +58,8 @@ r_fnc_colnames = load_function_from_package("base::colnames")
58
58
  # Base - rownames (base)
59
59
  r_fnc_rownames = load_function_from_package("base::rownames")
60
60
 
61
+ # Base - unname (base)
62
+ r_fnc_unname = load_function_from_package("base::unname")
63
+
61
64
  # sits - configuration (internal)
62
65
  r_fnc_sits_conf = load_internal_function_from_package("sits:::.conf")
@@ -0,0 +1,46 @@
1
+ Describe a collection of sits as a HuggingFace dataset
2
+
3
+ Data cubes shared on HuggingFace are described by a "sits/sits.yml" file
4
+ in the dataset repository, which sits reads to open the dataset.
5
+
6
+ This function writes that description from a collection registered in
7
+ sits (see `sits_list_collections`), which is useful when a dataset shares
8
+ images of a known collection (e.g., images of "SENTINEL-2-L2A" downloaded
9
+ from "MPC").
10
+
11
+ The description of a collection is written as the dataset needs it: the
12
+ bands are named as sits names them in the images, and the properties used
13
+ by sits to reach the provider are not written, as sits defines them when
14
+ it registers a dataset.
15
+
16
+ Args:
17
+ source (str): Data source.
18
+
19
+ collection (str): Image collection.
20
+
21
+ bands (list[str]): Bands shared in the dataset (default is all of
22
+ them).
23
+
24
+ output_dir (str | pathlib.Path): Existing directory where the file
25
+ "sits/sits.yml" is written (optional). When not informed, the
26
+ collection definition is only returned.
27
+
28
+ Returns:
29
+ SITStructureData: Collection definition of the dataset.
30
+
31
+ Note:
32
+ A dataset must describe only the bands it holds, and the resolution of
33
+ each band is the one the collection declares. If you need to describe
34
+ a regularized cube, or a cube with custom bands, use `sits_to_hf`.
35
+
36
+ Examples:
37
+ import tempfile
38
+ from pysits import *
39
+
40
+ # describe a collection as a HuggingFace dataset
41
+ sits_config_to_hf(
42
+ source="MPC",
43
+ collection="SENTINEL-2-L2A",
44
+ bands=["B02", "B03", "B04", "B08"],
45
+ output_dir=tempfile.gettempdir(),
46
+ )
@@ -0,0 +1,85 @@
1
+ Read data cubes, samples and models shared on HuggingFace
2
+
3
+ Reads data shared in a HuggingFace repository. The content of the
4
+ repository defines what is read:
5
+
6
+ - data cubes: datasets describing a collection in a "sits/sits.yml" file
7
+ (see `sits_to_hf`). The images selected are downloaded to `output_dir`
8
+ and a local data cube is returned;
9
+
10
+ - samples: time series saved as ".rds" or ".parquet" files (see
11
+ `sits_to_parquet`);
12
+
13
+ - models: models trained by `sits_train` and saved as ".rds" files.
14
+
15
+ When `file` is not informed, a repository with a "sits/sits.yml" file is
16
+ read as a data cube. Otherwise, the repository must have a single ".rds"
17
+ or ".parquet" file. When there are many, choose one using `file`.
18
+
19
+ Args:
20
+ repo (str): HuggingFace repository ("<user>/<repository>").
21
+
22
+ file (str): File to be read in the repository (optional).
23
+
24
+ type (str): Type of the repository: "dataset" (default) or "model".
25
+ Data cubes are always shared in datasets.
26
+
27
+ bands (list[str]): Bands to be selected in the data cube (optional).
28
+
29
+ tiles (list[str]): Tiles to be selected in the data cube (optional).
30
+
31
+ roi (dict | geopandas.GeoDataFrame): Region of interest to be selected
32
+ in the data cube (optional).
33
+
34
+ crs (str): The Coordinate Reference System (CRS) of the roi.
35
+
36
+ start_date (str): Start date of the data cube ("YYYY-MM-DD").
37
+
38
+ end_date (str): End date of the data cube ("YYYY-MM-DD").
39
+
40
+ output_dir (str | pathlib.Path): Existing directory where the images
41
+ of the data cube are saved (required for data cubes).
42
+
43
+ n_tries (int): Number of attempts to download the same image.
44
+
45
+ multicores (int): Number of cores for parallel downloading.
46
+
47
+ progress (bool): Show progress bar?
48
+
49
+ **kwargs: Other parameters to read data cubes: `labels` (dict) and
50
+ `version` (str) select results produced by sits (e.g.,
51
+ probabilities).
52
+
53
+ Returns:
54
+ SITSCubeModel | SITSTimeSeriesModel | SITSMachineLearningMethod: A data
55
+ cube with local images, a set of samples, or a model.
56
+
57
+ Note:
58
+ HuggingFace limits the number of files a user requests in windows of
59
+ five minutes. For this reason, the images of a data cube are
60
+ downloaded, each one requested only once, in batches that fit the
61
+ requests available. When no request is available, the download waits
62
+ the next window. Images already downloaded in `output_dir` are not
63
+ requested again, so an interrupted download is resumed by calling
64
+ `sits_from_hf` again.
65
+
66
+ To access private repositories, the HuggingFace access token must be
67
+ set in the `HF_TOKEN` environment variable.
68
+
69
+ Examples:
70
+ import tempfile
71
+ from pysits import *
72
+
73
+ # download a data cube shared in a HuggingFace dataset
74
+ cube = sits_from_hf(
75
+ repo="felipemcarlos/sits_mod13q1_sinop",
76
+ output_dir=tempfile.gettempdir(),
77
+ )
78
+
79
+ # read samples shared in a HuggingFace dataset
80
+ samples = sits_from_hf(repo="felipemcarlos/sits_samples_modis_ndvi")
81
+
82
+ # read a model shared in a HuggingFace model repository
83
+ model = sits_from_hf(
84
+ repo="felipemcarlos/sits_rfor_modis_ndvi", type="model"
85
+ )
@@ -0,0 +1,26 @@
1
+ Read sits time series from the Parquet format
2
+
3
+ Reads a file written by `sits_to_parquet` and rebuilds the time series,
4
+ with its class, column order and nested series.
5
+
6
+ Files written by other programs are also read. Their class is then
7
+ inferred from the columns, which must include "longitude", "latitude",
8
+ "start_date", "end_date" and "label".
9
+
10
+ Args:
11
+ file (str | pathlib.Path): Full path or HTTP(S) URL of the file to
12
+ read (valid file name with extension ".parquet").
13
+
14
+ Returns:
15
+ SITSTimeSeriesModel: Time series.
16
+
17
+ Raises:
18
+ httpx2.HTTPError: If a remote file cannot be downloaded.
19
+
20
+ Examples:
21
+ import tempfile
22
+ from pysits import *
23
+
24
+ parquet_file = tempfile.gettempdir() + "/samples.parquet"
25
+ sits_to_parquet(samples_modis_ndvi, file=parquet_file)
26
+ samples = sits_from_parquet(parquet_file)
@@ -0,0 +1,76 @@
1
+ Describe a data cube as a HuggingFace dataset
2
+
3
+ Data cubes shared on HuggingFace are described by files sits reads to
4
+ understand the dataset. They are kept in a "sits" directory of the
5
+ repository, so they are not mixed with the other files of the dataset:
6
+
7
+ - "sits/sits.yml": the collection definition of the dataset;
8
+
9
+ - "sits/cache.rds": the data cube of the dataset. When it is available,
10
+ sits loads it instead of reading each image of the dataset.
11
+
12
+ This function writes these files in `output_dir`, as they must be uploaded
13
+ to the repository (i.e., the "sits" directory and the images, named as
14
+ sits names them, in the root of the repository). Nothing is uploaded by
15
+ this function.
16
+
17
+ The collection definition is written from a data cube: the bands, their
18
+ resolution and, for results produced by sits (e.g., probabilities,
19
+ classified maps), the labels of the classification.
20
+
21
+ Each type of cube is described the way sits reads it:
22
+
23
+ - image raster cubes are described band by band;
24
+
25
+ - embeddings have only base satellite and sensor described;
26
+
27
+ - results produced by sits inform only their resolution and the labels
28
+ of the classification.
29
+
30
+ A dataset can share more than one result of the same classification
31
+ (e.g., probabilities and the classified map), which are described
32
+ together when they are informed as a list of cubes. A cache describes a
33
+ single cube, so it is not written for a list of cubes.
34
+
35
+ Args:
36
+ cube (SITSCubeModel | list[SITSCubeModel]): Data cube or list of cubes
37
+ to be shared as a dataset.
38
+
39
+ output_dir (str | pathlib.Path): Existing directory where the files of
40
+ the dataset are written (optional). When not informed, the
41
+ collection definition is only returned.
42
+
43
+ repo (str): HuggingFace repository where the images are uploaded
44
+ ("<user>/<dataset>"). Required to write the cache of a data cube,
45
+ unless the cube was read from HuggingFace.
46
+
47
+ Returns:
48
+ SITStructureData: Collection definition of the dataset.
49
+
50
+ Note:
51
+ Images must be named in the dataset as sits names them
52
+ (`sits_cube_copy` and `sits_regularize` do it), and only the bands
53
+ shared in the dataset must be described.
54
+
55
+ Examples:
56
+ import tempfile
57
+ from pysits import *
58
+
59
+ # create a cube
60
+ data_dir = r_package_dir("extdata/raster/mod13q1", package="sits")
61
+ cube = sits_cube(
62
+ source="BDC",
63
+ collection="MOD13Q1-6.1",
64
+ data_dir=data_dir,
65
+ )
66
+
67
+ # get the collection definition of the cube
68
+ collection_conf = sits_to_hf(cube)
69
+
70
+ # write the files describing the dataset ("sits/sits.yml" and
71
+ # "sits/cache.rds"), to be uploaded with the images of the cube
72
+ sits_to_hf(
73
+ cube,
74
+ output_dir=tempfile.gettempdir(),
75
+ repo="user/dataset",
76
+ )
@@ -0,0 +1,23 @@
1
+ Export sits time series to the Parquet format
2
+
3
+ Writes a set of time series to a Parquet file. The layout is long: one
4
+ row per sample and date, with the time series as plain columns. The
5
+ file metadata keeps what is needed to rebuild the data with
6
+ `sits_from_parquet` (class, column order and bands). It also follows
7
+ GeoParquet 1.1, so tools like GDAL and QGIS read the file as points.
8
+
9
+ Args:
10
+ data (SITSTimeSeriesModel): Time series.
11
+
12
+ file (str | pathlib.Path): Full path of the exported file (valid
13
+ file name with extension ".parquet").
14
+
15
+ Returns:
16
+ None
17
+
18
+ Examples:
19
+ import tempfile
20
+ from pysits import *
21
+
22
+ parquet_file = tempfile.gettempdir() + "/samples.parquet"
23
+ sits_to_parquet(samples_modis_ndvi, file=parquet_file)
@@ -17,7 +17,14 @@
17
17
 
18
18
  """Exporters module."""
19
19
 
20
- from .files import sits_timeseries_to_csv, sits_to_csv, sits_to_xlsx
20
+ from .files import (
21
+ sits_from_parquet,
22
+ sits_timeseries_to_csv,
23
+ sits_to_csv,
24
+ sits_to_parquet,
25
+ sits_to_xlsx,
26
+ )
27
+ from .hf import sits_config_to_hf, sits_from_hf, sits_to_hf
21
28
  from .sf import sits_as_geopandas
22
29
  from .xarray import sits_as_xarray
23
30
 
@@ -27,4 +34,9 @@ __all__ = (
27
34
  "sits_to_csv",
28
35
  "sits_to_xlsx",
29
36
  "sits_timeseries_to_csv",
37
+ "sits_to_parquet",
38
+ "sits_from_parquet",
39
+ "sits_to_hf",
40
+ "sits_from_hf",
41
+ "sits_config_to_hf",
30
42
  )
@@ -17,10 +17,15 @@
17
17
 
18
18
  """Files exporter."""
19
19
 
20
+ from pathlib import Path
21
+
20
22
  from pysits.backend.pkgs import r_pkg_sits
21
23
  from pysits.conversions.decorators import function_call
22
24
  from pysits.docs import attach_doc
23
25
  from pysits.models.data.frame import SITSFrame
26
+ from pysits.models.data.ts import SITSTimeSeriesModel
27
+ from pysits.models.resolver import resolve_and_invoke_content_class
28
+ from pysits.network import fetch_to_tempfile, is_remote
24
29
 
25
30
 
26
31
  @function_call(r_pkg_sits.sits_to_csv, SITSFrame)
@@ -41,3 +46,28 @@ def sits_to_xlsx(*args, **kwargs) -> None:
41
46
  @attach_doc("sits_timeseries_to_csv")
42
47
  def sits_timeseries_to_csv(*args, **kwargs) -> None:
43
48
  """Export a full sits timeseries to CSV format."""
49
+
50
+
51
+ @function_call(r_pkg_sits.sits_to_parquet, lambda x: None)
52
+ @attach_doc("sits_to_parquet")
53
+ def sits_to_parquet(*args, **kwargs) -> None:
54
+ """Export sits time series to the Parquet format."""
55
+
56
+
57
+ @function_call(r_pkg_sits.sits_from_parquet, resolve_and_invoke_content_class)
58
+ def _sits_from_parquet(*args, **kwargs) -> SITSTimeSeriesModel:
59
+ """Read sits time series from a local Parquet file."""
60
+
61
+
62
+ @attach_doc("sits_from_parquet")
63
+ def sits_from_parquet(file: str | Path) -> SITSTimeSeriesModel:
64
+ """Read sits time series from the Parquet format."""
65
+ # If file is remote
66
+ if is_remote(file):
67
+ # Download it to a temporary file
68
+ with fetch_to_tempfile(str(file), suffix=".parquet") as local_file:
69
+ # Read it
70
+ return _sits_from_parquet(local_file)
71
+
72
+ # Otherwise, read it directly
73
+ return _sits_from_parquet(file)
@@ -0,0 +1,74 @@
1
+ #
2
+ # Copyright (C) 2025 sits developers.
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify it
5
+ # under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, see <https://www.gnu.org/licenses/>.
16
+ #
17
+
18
+ """HuggingFace exporter."""
19
+
20
+ from pysits.backend.functions import r_fnc_unname
21
+ from pysits.backend.pkgs import r_pkg_sits
22
+ from pysits.conversions.common import convert_to_r
23
+ from pysits.conversions.decorators import function_call, rpy2_fix_type_custom
24
+ from pysits.docs import attach_doc
25
+ from pysits.models.data.base import SITStructureData
26
+ from pysits.models.data.cube import SITSCubeModel
27
+ from pysits.models.data.ts import SITSTimeSeriesModel
28
+ from pysits.models.ml import SITSMachineLearningMethod
29
+ from pysits.models.resolver import resolve_and_invoke_content_class
30
+
31
+
32
+ #
33
+ # HuggingFace-specific converters functions
34
+ #
35
+ def convert_hf_cubes(obj: object) -> object:
36
+ """Convert a list of cubes to an unnamed R list."""
37
+ if isinstance(obj, list | tuple):
38
+ return r_fnc_unname(convert_to_r(obj))
39
+
40
+ return obj
41
+
42
+
43
+ #
44
+ # HuggingFace-specific converters config
45
+ #
46
+ hf_converters = {
47
+ "cube": convert_hf_cubes,
48
+ }
49
+
50
+
51
+ #
52
+ # HuggingFace
53
+ #
54
+ @function_call(r_pkg_sits.sits_from_hf, resolve_and_invoke_content_class)
55
+ @attach_doc("sits_from_hf")
56
+ def sits_from_hf(
57
+ *args, **kwargs
58
+ ) -> SITSCubeModel | SITSTimeSeriesModel | SITSMachineLearningMethod:
59
+ """Read data cubes, samples and models shared on HuggingFace."""
60
+
61
+
62
+ @rpy2_fix_type_custom(converters=hf_converters)
63
+ @function_call(r_pkg_sits.sits_to_hf, SITStructureData)
64
+ @attach_doc("sits_to_hf")
65
+ def sits_to_hf(
66
+ cube: SITSCubeModel | list[SITSCubeModel], *args, **kwargs
67
+ ) -> SITStructureData:
68
+ """Describe a data cube as a HuggingFace dataset."""
69
+
70
+
71
+ @function_call(r_pkg_sits.sits_config_to_hf, SITStructureData)
72
+ @attach_doc("sits_config_to_hf")
73
+ def sits_config_to_hf(*args, **kwargs) -> SITStructureData:
74
+ """Describe a collection of sits as a HuggingFace dataset."""
@@ -25,8 +25,15 @@ import pytest
25
25
  from pysits.backend.pkgs import r_pkg_sits
26
26
  from pysits.models.data.frame import SITSFrame
27
27
  from pysits.models.data.matrix import SITSConfusionMatrix
28
+ from pysits.models.data.ts import SITSTimeSeriesModel
28
29
  from pysits.sits.context import cerrado_2classes
29
- from pysits.sits.exporters import sits_timeseries_to_csv, sits_to_csv, sits_to_xlsx
30
+ from pysits.sits.exporters import (
31
+ sits_from_parquet,
32
+ sits_timeseries_to_csv,
33
+ sits_to_csv,
34
+ sits_to_parquet,
35
+ sits_to_xlsx,
36
+ )
30
37
  from pysits.sits.ml import sits_rfor
31
38
  from pysits.sits.ts import sits_sample, sits_validate
32
39
 
@@ -94,3 +101,46 @@ def test_sits_to_xlsx(tmp_path: Path, accuracy):
94
101
  r_pkg_sits.sits_to_xlsx(accuracy._instance, file=str(r_file))
95
102
 
96
103
  assert read_xlsx(py_file) == read_xlsx(r_file)
104
+
105
+
106
+ def test_sits_parquet(tmp_path: Path):
107
+ """Test time series export / import using parquet."""
108
+ # local file
109
+ file = tmp_path / "samples.parquet"
110
+
111
+ # export samples as parquet
112
+ sits_to_parquet(cerrado_2classes, file=file)
113
+
114
+ # import samples from parquet
115
+ samples = sits_from_parquet(file)
116
+
117
+ # samples must be a time series model
118
+ assert isinstance(samples, SITSTimeSeriesModel)
119
+
120
+ # metadata and nested series must be equal to the original samples
121
+ metadata = samples.drop(columns="time_series")
122
+ expected = cerrado_2classes.drop(columns="time_series")
123
+
124
+ assert metadata.equals(expected)
125
+ assert all(
126
+ ts.equals(expected_ts)
127
+ for ts, expected_ts in zip(
128
+ samples["time_series"], cerrado_2classes["time_series"], strict=True
129
+ )
130
+ )
131
+
132
+
133
+ def test_sits_from_parquet_remote(http_server):
134
+ """Test time series import using remote parquet file."""
135
+ # remote file
136
+ directory, base_url = http_server
137
+
138
+ # export samples as parquet
139
+ sits_to_parquet(cerrado_2classes, file=directory / "samples.parquet")
140
+
141
+ # import samples from parquet
142
+ samples = sits_from_parquet(f"{base_url}/samples.parquet")
143
+
144
+ # samples must be a time series model
145
+ assert isinstance(samples, SITSTimeSeriesModel)
146
+ assert len(samples) == len(cerrado_2classes)
@@ -0,0 +1,154 @@
1
+ #
2
+ # Copyright (C) 2025 sits developers.
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify it
5
+ # under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, see <https://www.gnu.org/licenses/>.
16
+ #
17
+
18
+ """Unit tests for HuggingFace export operations."""
19
+
20
+ from pathlib import Path
21
+
22
+ import httpx2
23
+ import pytest
24
+
25
+ from pysits.backend.pkgs import r_pkg_sits
26
+ from pysits.models.data.base import SITStructureData
27
+ from pysits.models.data.cube import SITSCubeModel
28
+ from pysits.models.data.ts import SITSTimeSeriesModel
29
+ from pysits.models.ml import SITSMachineLearningMethod
30
+ from pysits.sits.exporters import sits_config_to_hf, sits_from_hf, sits_to_hf
31
+
32
+
33
+ #
34
+ # Helpers
35
+ #
36
+ def list_files(directory: Path) -> list[str]:
37
+ """List the files of a directory."""
38
+ return sorted(
39
+ file.relative_to(directory).as_posix()
40
+ for file in directory.rglob("*")
41
+ if file.is_file()
42
+ )
43
+
44
+
45
+ #
46
+ # Fixtures
47
+ #
48
+ @pytest.fixture(scope="module")
49
+ def hf_online() -> None:
50
+ """Skip the tests of a module when HuggingFace is not accessible."""
51
+ try:
52
+ httpx2.head("https://huggingface.co", follow_redirects=True)
53
+
54
+ except httpx2.HTTPError:
55
+ pytest.skip("HuggingFace is not accessible")
56
+
57
+
58
+ #
59
+ # Tests
60
+ #
61
+ def test_sits_to_hf(local_cube, tmp_path: Path):
62
+ """Test data cube described as a HuggingFace dataset."""
63
+ py_dir = tmp_path / "python"
64
+ r_dir = tmp_path / "r"
65
+ list_dir = tmp_path / "list"
66
+
67
+ for directory in (py_dir, r_dir, list_dir):
68
+ directory.mkdir()
69
+
70
+ # single cube, definition and cache are written
71
+ result = sits_to_hf(local_cube, output_dir=py_dir, repo="user/dataset")
72
+ r_pkg_sits.sits_to_hf(
73
+ local_cube._instance, output_dir=str(r_dir), repo="user/dataset"
74
+ )
75
+
76
+ # validate the results
77
+ assert isinstance(result, SITStructureData)
78
+ assert list_files(py_dir) == ["sits/cache.rds", "sits/sits.yml"]
79
+
80
+ # read the results
81
+ result_py = (py_dir / "sits/sits.yml").read_text()
82
+ result_r = (r_dir / "sits/sits.yml").read_text()
83
+
84
+ assert result_py == result_r
85
+
86
+ # convert list of cubes
87
+ sits_to_hf([local_cube], output_dir=list_dir)
88
+
89
+ # test - only the definition is written, cache is not supported
90
+ assert list_files(list_dir) == ["sits/sits.yml"]
91
+
92
+
93
+ def test_sits_config_to_hf(tmp_path: Path):
94
+ """Test collection described as a HuggingFace dataset."""
95
+ py_dir = tmp_path / "python"
96
+ r_dir = tmp_path / "r"
97
+
98
+ for directory in (py_dir, r_dir):
99
+ directory.mkdir()
100
+
101
+ # convert collection
102
+ result = sits_config_to_hf(
103
+ source="MPC",
104
+ collection="SENTINEL-2-L2A",
105
+ bands=["B02", "B03"],
106
+ output_dir=py_dir,
107
+ )
108
+
109
+ # convert collection in R
110
+ r_pkg_sits.sits_config_to_hf(
111
+ source="MPC",
112
+ collection="SENTINEL-2-L2A",
113
+ bands=["B02", "B03"],
114
+ output_dir=str(r_dir),
115
+ )
116
+
117
+ # validate the results
118
+ assert isinstance(result, SITStructureData)
119
+ assert list_files(py_dir) == ["sits/sits.yml"]
120
+
121
+ # read the results
122
+ result_py = (py_dir / "sits/sits.yml").read_text()
123
+ result_r = (r_dir / "sits/sits.yml").read_text()
124
+
125
+ assert result_py == result_r
126
+
127
+
128
+ @pytest.mark.parametrize(
129
+ "repo, options, expected",
130
+ [
131
+ (
132
+ "felipemcarlos/sits_mod13q1_sinop",
133
+ {"start_date": "2013-09-14", "end_date": "2013-10-16"},
134
+ SITSCubeModel,
135
+ ),
136
+ ("felipemcarlos/sits_samples_modis_ndvi", {}, SITSTimeSeriesModel),
137
+ (
138
+ "felipemcarlos/sits_rfor_modis_ndvi",
139
+ {"type": "model"},
140
+ SITSMachineLearningMethod,
141
+ ),
142
+ ],
143
+ )
144
+ def test_sits_from_hf(hf_online, tmp_path: Path, repo: str, options: dict, expected):
145
+ """Test data cube, samples and model read from HuggingFace."""
146
+ result = sits_from_hf(
147
+ repo,
148
+ output_dir=tmp_path,
149
+ progress=False,
150
+ **options,
151
+ )
152
+
153
+ # validate the results
154
+ assert isinstance(result, expected)