pysits 2.0.0.dev7__tar.gz → 2.0.0.dev8__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.
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/PKG-INFO +2 -1
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pyproject.toml +2 -1
- pysits-2.0.0.dev8/pysits/network.py +100 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/ml.py +3 -1
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/utils.py +31 -8
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/conftest.py +51 -0
- pysits-2.0.0.dev8/tests/test_network.py +160 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_utils.py +20 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/uv.lock +74 -1
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/.gitattributes +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/.github/actions/setup-pysits/action.yml +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/.github/workflows/ruff.yaml +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/.github/workflows/tests.yaml +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/.gitignore +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/.pre-commit-config.yaml +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/LICENSE +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/README.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/conda/meta.yaml +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/__init__.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/backend/__init__.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/backend/arrow.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/backend/functions.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/backend/loaders.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/backend/pkgs.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/backend/rinterface.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/conversions/__init__.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/conversions/clojure.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/conversions/common.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/conversions/decorators.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/conversions/dsl/__init__.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/conversions/dsl/base.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/conversions/dsl/mask.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/conversions/dsl/tuning.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/conversions/stac.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/conversions/tibble.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/conversions/vector.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/conversions/xarray.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/__init__.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/impute_linear.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/impute_mean.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/impute_mean_window.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/impute_median.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/plot.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_accuracy.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_accuracy_summary.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_add_base_cube.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_apply.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_as_geopandas.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_bands.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_barlow_twins.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_bbox.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_classify.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_clean.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_cluster_clean.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_cluster_dendro.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_cluster_frequency.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_colors.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_colors_qgis.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_colors_reset.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_colors_set.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_colors_show.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_combine_predictions.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_confidence_sampling.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_config.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_config_show.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_config_user_file.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_contrastive_learning.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_cube.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_cube_copy.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_encode.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_formula_linear.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_formula_logref.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_geo_dist.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_get_class.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_get_data.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_get_probs.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_kfold_validate.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_label_classification.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_labels.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_labels_summary.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_lightgbm.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_lighttae.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_list_collections.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_lstm_fcn.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_merge.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_mixture_model.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_mlp.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_model_export.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_mosaic.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_parallel.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_patterns.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_pre_train.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_pred_features.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_pred_normalize.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_pred_references.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_pred_sample.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_predictors.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_random_sampling.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_reclassify.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_reduce.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_reduce_imbalance.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_regularize.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_resnet.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_rfor.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_roi_to_tiles.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_sample.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_sampling_design.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_sankey.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_segment.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_select.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_show_prediction.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_slic.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_smooth.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_snic.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_som_clean_samples.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_som_evaluate_cluster.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_som_map.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_som_remove_samples.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_ssl_lejepa.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_ssl_mae.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_ssl_vicreg.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_stats.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_stratified_sampling.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_svm.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_tae.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_tempcnn.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_texture.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_tiles_to_roi.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_timeline.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_timeseries_to_csv.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_to_csv.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_to_xlsx.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_train.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_tuning.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_tuning_hparams.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_uncertainty.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_uncertainty_sampling.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_validate.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_variance.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_view.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/sits_xgboost.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/content/summary.md +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/docs/decorators.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/extras/__init__.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/extras/earthdatalogin.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/extras/torch.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/jinja.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/__init__.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/base.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/data/__init__.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/data/accuracy.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/data/base.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/data/cube.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/data/frame.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/data/frame_accessor.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/data/matrix.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/data/table.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/data/ts.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/data/tuning.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/data/vector.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/frame.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/ml.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/resolver.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/models/visual.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/settings.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/__init__.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/colors.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/config.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/context.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/cube.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/data.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/exporters/__init__.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/exporters/files.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/exporters/sf.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/exporters/xarray.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/impute.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/segment.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/tiles.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/ts.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/tuning.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/sits/visualization.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/templates/cube.html +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/templates/plot.html +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/templates/tuning.html +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/visualization/__init__.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/visualization/base.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/visualization/device.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/visualization/host.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/visualization/leaflet.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/pysits/visualization/options.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_backend.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_classification.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_config.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_conversions.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_cube.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_data.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_dsl.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_embedding.py +1 -1
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_exporters.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_exporters_geopandas.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_exporters_xarray.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_extras.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_indexing.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_ml_models.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_resolver.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_rl_models.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_som.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_tiles.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_tuning.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_validation.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_visual_models.py +0 -0
- {pysits-2.0.0.dev7 → pysits-2.0.0.dev8}/tests/test_visualization.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pysits
|
|
3
|
-
Version: 2.0.0.
|
|
3
|
+
Version: 2.0.0.dev8
|
|
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,6 +17,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
17
17
|
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
18
18
|
Requires-Python: <4,>=3.10
|
|
19
19
|
Requires-Dist: geopandas>=1.1.0
|
|
20
|
+
Requires-Dist: httpx2>=2.13.0
|
|
20
21
|
Requires-Dist: jinja2>=3.1.6
|
|
21
22
|
Requires-Dist: matplotlib>=3.10.1
|
|
22
23
|
Requires-Dist: pandas>=2.2.3
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
[project]
|
|
19
19
|
name = "pysits"
|
|
20
|
-
version = "2.0.0.
|
|
20
|
+
version = "2.0.0.dev8"
|
|
21
21
|
description = "Python wrapper for the sits R package"
|
|
22
22
|
readme = "README.md"
|
|
23
23
|
requires-python = ">=3.10,<4"
|
|
@@ -71,6 +71,7 @@ dependencies = [
|
|
|
71
71
|
"shapely>=2.1.1",
|
|
72
72
|
"pyarrow>=20.0.0",
|
|
73
73
|
"jinja2>=3.1.6",
|
|
74
|
+
"httpx2>=2.13.0",
|
|
74
75
|
]
|
|
75
76
|
|
|
76
77
|
[project.urls]
|
|
@@ -0,0 +1,100 @@
|
|
|
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
|
+
"""Network operations."""
|
|
19
|
+
|
|
20
|
+
import os
|
|
21
|
+
import tempfile
|
|
22
|
+
from collections.abc import Iterator
|
|
23
|
+
from contextlib import contextmanager
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from urllib.parse import urlparse
|
|
26
|
+
|
|
27
|
+
import httpx2
|
|
28
|
+
|
|
29
|
+
#
|
|
30
|
+
# Supported URL schemes
|
|
31
|
+
#
|
|
32
|
+
REMOTE_SCHEMES = ("http", "https")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
#
|
|
36
|
+
# Auxiliary functions
|
|
37
|
+
#
|
|
38
|
+
def is_remote(location: str | Path) -> bool:
|
|
39
|
+
"""Check if a location points to a remote resource.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
location (str | Path): File location (local path or URL).
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
bool: ``True`` when ``location`` is an URL with a supported scheme.
|
|
46
|
+
|
|
47
|
+
Notes:
|
|
48
|
+
- Supported schemes are ``http`` and ``https``.
|
|
49
|
+
"""
|
|
50
|
+
return urlparse(str(location)).scheme in REMOTE_SCHEMES
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
#
|
|
54
|
+
# File management
|
|
55
|
+
#
|
|
56
|
+
@contextmanager
|
|
57
|
+
def fetch_to_tempfile(url: str, *, suffix: str = "") -> Iterator[Path]:
|
|
58
|
+
"""Download a remote file to a temporary file.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
url (str): File URL.
|
|
62
|
+
|
|
63
|
+
suffix (str): Suffix for the temporary file name.
|
|
64
|
+
|
|
65
|
+
Yields:
|
|
66
|
+
Path: Path of the downloaded file.
|
|
67
|
+
|
|
68
|
+
Raises:
|
|
69
|
+
httpx2.HTTPError: If the file cannot be downloaded.
|
|
70
|
+
|
|
71
|
+
Notes:
|
|
72
|
+
- The temporary file is removed when the context exits, including
|
|
73
|
+
when the download fails or the caller raises.
|
|
74
|
+
"""
|
|
75
|
+
# Create a temporary file
|
|
76
|
+
descriptor, name = tempfile.mkstemp(suffix=suffix)
|
|
77
|
+
|
|
78
|
+
# Name as path
|
|
79
|
+
local_file = Path(name)
|
|
80
|
+
|
|
81
|
+
# Try to download the file
|
|
82
|
+
try:
|
|
83
|
+
# Open the stream in binary mode
|
|
84
|
+
with os.fdopen(descriptor, "wb") as stream:
|
|
85
|
+
# Enable redirects to facilitate operations on remote files
|
|
86
|
+
# stored in systems like huggingface and similar platforms.
|
|
87
|
+
with httpx2.stream("GET", url, follow_redirects=True) as response:
|
|
88
|
+
# Raise an exception if the response is not successful
|
|
89
|
+
response.raise_for_status()
|
|
90
|
+
|
|
91
|
+
# Write the content to the temporary file
|
|
92
|
+
for chunk in response.iter_bytes():
|
|
93
|
+
stream.write(chunk)
|
|
94
|
+
|
|
95
|
+
# Yield the path to the temporary file
|
|
96
|
+
yield local_file
|
|
97
|
+
|
|
98
|
+
finally:
|
|
99
|
+
# Remove the temporary file
|
|
100
|
+
local_file.unlink(missing_ok=True)
|
|
@@ -84,7 +84,9 @@ sits_lightgbm = closure_factory("sits_lightgbm")
|
|
|
84
84
|
sits_ssl_mae = closure_factory("sits_ssl_mae", converters=dl_converters)
|
|
85
85
|
sits_ssl_lejepa = closure_factory("sits_ssl_lejepa", converters=dl_converters)
|
|
86
86
|
sits_ssl_vicreg = closure_factory("sits_ssl_vicreg", converters=dl_converters)
|
|
87
|
-
sits_ssl_barlow_twins = closure_factory(
|
|
87
|
+
sits_ssl_barlow_twins = closure_factory(
|
|
88
|
+
"sits_ssl_barlow_twins", converters=dl_converters
|
|
89
|
+
)
|
|
88
90
|
|
|
89
91
|
sits_barlow_twins = closure_factory("sits_barlow_twins", converters=dl_converters)
|
|
90
92
|
sits_contrastive_learning = closure_factory(
|
|
@@ -27,6 +27,7 @@ from pysits.models.resolver import (
|
|
|
27
27
|
resolve_and_invoke_accuracy_class,
|
|
28
28
|
resolve_and_invoke_content_class,
|
|
29
29
|
)
|
|
30
|
+
from pysits.network import fetch_to_tempfile, is_remote
|
|
30
31
|
|
|
31
32
|
#
|
|
32
33
|
# Data class resolver
|
|
@@ -56,19 +57,41 @@ def read_rds(file: str | Path) -> SITSFrame:
|
|
|
56
57
|
"""Read RDS file compatible with SITS.
|
|
57
58
|
|
|
58
59
|
Args:
|
|
59
|
-
file (str | Path): RDS file.
|
|
60
|
+
file (str | Path): RDS file. It can be a local path or an HTTP(S) URL.
|
|
60
61
|
|
|
61
62
|
Returns:
|
|
62
63
|
SITSFrame: SITS Data instance (can be a ``cube`` or a ``time-series`` object).
|
|
63
|
-
"""
|
|
64
|
-
file = Path(file)
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
Raises:
|
|
66
|
+
FileNotFoundError: If a local RDS file does not exist. A missing
|
|
67
|
+
remote file is reported by ``httpx2`` instead,
|
|
68
|
+
as an ``HTTPStatusError``.
|
|
69
|
+
|
|
70
|
+
httpx2.HTTPError: If a remote RDS file cannot be downloaded.
|
|
69
71
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
ValueError: If the RDS file has an object not supported by sits.
|
|
73
|
+
"""
|
|
74
|
+
# If is remote file, we download it
|
|
75
|
+
if is_remote(file):
|
|
76
|
+
# Remote files are downloaded before being read. In R, it is possible
|
|
77
|
+
# to read RDS straight from an ``url`` connection, but that only works
|
|
78
|
+
# when the content is gzipped: the other compressions ``saveRDS`` produces
|
|
79
|
+
# (``xz`` and ``bzip2``) are rejected when read this way.
|
|
80
|
+
# So we download the file to a temporary file and read it from there to avoid
|
|
81
|
+
# this issue.
|
|
82
|
+
with fetch_to_tempfile(str(file), suffix=".rds") as local_file:
|
|
83
|
+
# Download and read content!
|
|
84
|
+
rds_content = r_fnc_read_rds(local_file.as_posix())
|
|
85
|
+
|
|
86
|
+
else:
|
|
87
|
+
file = Path(file)
|
|
88
|
+
|
|
89
|
+
# Check if file exists
|
|
90
|
+
if not file.exists():
|
|
91
|
+
raise FileNotFoundError("Failed to read RDS: File does not exist.")
|
|
92
|
+
|
|
93
|
+
# Read RDS
|
|
94
|
+
rds_content = r_fnc_read_rds(file.as_posix())
|
|
72
95
|
|
|
73
96
|
# Resolve and invoke data class
|
|
74
97
|
for resolver in RDS_RESOLVERS:
|
|
@@ -25,6 +25,10 @@ import os
|
|
|
25
25
|
os.environ.setdefault("MPLBACKEND", "Agg")
|
|
26
26
|
|
|
27
27
|
import webbrowser
|
|
28
|
+
from functools import partial
|
|
29
|
+
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
from threading import Thread
|
|
28
32
|
from typing import Any
|
|
29
33
|
|
|
30
34
|
import matplotlib
|
|
@@ -36,6 +40,11 @@ from pysits.sits.cube import sits_cube
|
|
|
36
40
|
from pysits.sits.utils import r_package_dir
|
|
37
41
|
from pysits.visualization.options import reset_plot_options
|
|
38
42
|
|
|
43
|
+
#
|
|
44
|
+
# Path prefix the test server answers with a redirect
|
|
45
|
+
#
|
|
46
|
+
REDIRECT_PREFIX = "/redirect/"
|
|
47
|
+
|
|
39
48
|
|
|
40
49
|
#
|
|
41
50
|
# Helpers
|
|
@@ -107,3 +116,45 @@ def no_browser(monkeypatch):
|
|
|
107
116
|
monkeypatch.setattr(webbrowser, "open_new_tab", lambda x: None)
|
|
108
117
|
|
|
109
118
|
yield
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class _RedirectingRequestHandler(SimpleHTTPRequestHandler):
|
|
122
|
+
"""Serve a directory with a redirect."""
|
|
123
|
+
|
|
124
|
+
def do_GET(self) -> None: # noqa: N802 (name defined by the base class)
|
|
125
|
+
# If path starts with a given prefix, simulate a redirect
|
|
126
|
+
if self.path.startswith(REDIRECT_PREFIX):
|
|
127
|
+
# Simulate a redirect
|
|
128
|
+
self.send_response(302)
|
|
129
|
+
self.send_header("Location", self.path[len(REDIRECT_PREFIX) - 1 :])
|
|
130
|
+
self.end_headers()
|
|
131
|
+
|
|
132
|
+
return
|
|
133
|
+
|
|
134
|
+
super().do_GET()
|
|
135
|
+
|
|
136
|
+
def log_message(self, *args, **kwargs) -> None:
|
|
137
|
+
"""Keep the per-request log out of the test output."""
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@pytest.fixture
|
|
141
|
+
def http_server(tmp_path: Path):
|
|
142
|
+
"""HTTP server serving a directory with a redirect."""
|
|
143
|
+
handler = partial(
|
|
144
|
+
_RedirectingRequestHandler,
|
|
145
|
+
directory=str(tmp_path),
|
|
146
|
+
)
|
|
147
|
+
server = ThreadingHTTPServer(("127.0.0.1", 0), handler)
|
|
148
|
+
|
|
149
|
+
# Start the server in a daemon thread
|
|
150
|
+
thread = Thread(target=server.serve_forever, daemon=True)
|
|
151
|
+
thread.start()
|
|
152
|
+
|
|
153
|
+
# Yield the directory and its base URL
|
|
154
|
+
try:
|
|
155
|
+
yield tmp_path, f"http://127.0.0.1:{server.server_port}"
|
|
156
|
+
|
|
157
|
+
# Shutdown the server
|
|
158
|
+
finally:
|
|
159
|
+
server.shutdown()
|
|
160
|
+
server.server_close()
|
|
@@ -0,0 +1,160 @@
|
|
|
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 network operations."""
|
|
19
|
+
|
|
20
|
+
import socket
|
|
21
|
+
import tempfile
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from threading import Thread
|
|
24
|
+
|
|
25
|
+
import httpx2
|
|
26
|
+
import pytest
|
|
27
|
+
|
|
28
|
+
from pysits.network import fetch_to_tempfile, is_remote
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
#
|
|
32
|
+
# Auxiliary functions
|
|
33
|
+
#
|
|
34
|
+
def temporary_files() -> set[Path]:
|
|
35
|
+
"""List the files currently in the temporary directory."""
|
|
36
|
+
return set(Path(tempfile.gettempdir()).iterdir())
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
#
|
|
40
|
+
# Fixtures
|
|
41
|
+
#
|
|
42
|
+
@pytest.fixture
|
|
43
|
+
def raw_server():
|
|
44
|
+
"""HTTP Server."""
|
|
45
|
+
server_sockets = []
|
|
46
|
+
|
|
47
|
+
def start(response: bytes) -> str:
|
|
48
|
+
"""Start the HTTP server."""
|
|
49
|
+
# Create a socket and bind it to a random port
|
|
50
|
+
server_socket = socket.socket()
|
|
51
|
+
server_socket.bind(("127.0.0.1", 0))
|
|
52
|
+
server_socket.listen(1)
|
|
53
|
+
server_sockets.append(server_socket)
|
|
54
|
+
|
|
55
|
+
# Start a thread to serve the response
|
|
56
|
+
def serve() -> None:
|
|
57
|
+
try:
|
|
58
|
+
connection, _ = server_socket.accept()
|
|
59
|
+
connection.recv(4096)
|
|
60
|
+
connection.sendall(response)
|
|
61
|
+
connection.close()
|
|
62
|
+
|
|
63
|
+
except OSError:
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
# Start the thread
|
|
67
|
+
Thread(target=serve, daemon=True).start()
|
|
68
|
+
|
|
69
|
+
# Return the URL of the server
|
|
70
|
+
return f"http://127.0.0.1:{server_socket.getsockname()[1]}/samples.rds"
|
|
71
|
+
|
|
72
|
+
yield start
|
|
73
|
+
|
|
74
|
+
for server_socket in server_sockets:
|
|
75
|
+
server_socket.close()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
#
|
|
79
|
+
# Tests
|
|
80
|
+
#
|
|
81
|
+
@pytest.mark.parametrize(
|
|
82
|
+
("location", "expected"),
|
|
83
|
+
[
|
|
84
|
+
("https://example.org/samples.rds", True),
|
|
85
|
+
("http://example.org/samples.rds", True),
|
|
86
|
+
("/data/samples.rds", False),
|
|
87
|
+
("/home/user/samples.rds", False),
|
|
88
|
+
# Note: ``urlparse`` reads the drive letter as the scheme,
|
|
89
|
+
# so a Windows path must not be mistaken for a remote location
|
|
90
|
+
(r"C:\data\samples.rds", False),
|
|
91
|
+
],
|
|
92
|
+
)
|
|
93
|
+
def test_is_remote(location: str, expected: bool):
|
|
94
|
+
"""Test remote location identification."""
|
|
95
|
+
assert is_remote(location) is expected
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_fetch_to_tempfile_downloads_and_cleans_up(http_server):
|
|
99
|
+
"""Test remote content download."""
|
|
100
|
+
directory, base_url = http_server
|
|
101
|
+
|
|
102
|
+
# Save payload
|
|
103
|
+
samples_file_local = directory / "samples.rds"
|
|
104
|
+
samples_file_local.write_bytes(b"sits-payload")
|
|
105
|
+
|
|
106
|
+
# Fetch the file
|
|
107
|
+
samples_file_remote = f"{base_url}/samples.rds"
|
|
108
|
+
|
|
109
|
+
with fetch_to_tempfile(samples_file_remote, suffix=".rds") as local_file:
|
|
110
|
+
assert local_file.read_bytes() == b"sits-payload"
|
|
111
|
+
|
|
112
|
+
# Check the file is deleted
|
|
113
|
+
assert not local_file.exists()
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def test_fetch_to_tempfile_follows_redirects(http_server):
|
|
117
|
+
"""Test redirect following."""
|
|
118
|
+
directory, base_url = http_server
|
|
119
|
+
|
|
120
|
+
# Save payload
|
|
121
|
+
samples_file_local = directory / "samples.rds"
|
|
122
|
+
samples_file_local.write_bytes(b"sits-payload")
|
|
123
|
+
|
|
124
|
+
# Fetch the file
|
|
125
|
+
samples_file_remote = f"{base_url}/redirect/samples.rds"
|
|
126
|
+
|
|
127
|
+
with fetch_to_tempfile(samples_file_remote, suffix=".rds") as local_file:
|
|
128
|
+
assert local_file.read_bytes() == b"sits-payload"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def test_fetch_to_tempfile_rejects_error_status(http_server):
|
|
132
|
+
"""Test error response handling."""
|
|
133
|
+
_, base_url = http_server
|
|
134
|
+
|
|
135
|
+
# Save payload
|
|
136
|
+
before = temporary_files()
|
|
137
|
+
|
|
138
|
+
# Fetch file
|
|
139
|
+
with pytest.raises(httpx2.HTTPStatusError):
|
|
140
|
+
with fetch_to_tempfile(f"{base_url}/non-existing-file.rds"):
|
|
141
|
+
pass
|
|
142
|
+
|
|
143
|
+
assert temporary_files() == before
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def test_fetch_to_tempfile_rejects_truncated_response(raw_server):
|
|
147
|
+
"""Test truncated response handling."""
|
|
148
|
+
# Create a server that returns a truncated response
|
|
149
|
+
url = raw_server(b"HTTP/1.1 200 OK\r\nContent-Length: 5000\r\n\r\n" + b"x" * 100)
|
|
150
|
+
|
|
151
|
+
# Save payload
|
|
152
|
+
before = temporary_files()
|
|
153
|
+
|
|
154
|
+
# Fetch file
|
|
155
|
+
with pytest.raises(httpx2.RemoteProtocolError):
|
|
156
|
+
with fetch_to_tempfile(url):
|
|
157
|
+
pass
|
|
158
|
+
|
|
159
|
+
# Check the file is deleted
|
|
160
|
+
assert temporary_files() == before
|
|
@@ -53,6 +53,26 @@ def test_read_rds(tmp_path: Path):
|
|
|
53
53
|
assert isinstance(rds_content, SITSTimeSeriesModel)
|
|
54
54
|
|
|
55
55
|
|
|
56
|
+
@pytest.mark.parametrize("compress", ["gzip", "xz", "bzip2"])
|
|
57
|
+
def test_read_rds_remote(http_server, compress: str):
|
|
58
|
+
"""Test read RDS from a remote file."""
|
|
59
|
+
directory, base_url = http_server
|
|
60
|
+
|
|
61
|
+
# Save RDS
|
|
62
|
+
r_fnc_save_rds = load_function_from_package("base::saveRDS")
|
|
63
|
+
r_fnc_save_rds(
|
|
64
|
+
samples_modis_ndvi._instance,
|
|
65
|
+
(directory / "samples.rds").as_posix(),
|
|
66
|
+
compress=compress,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Read remote RDS
|
|
70
|
+
rds_content = read_rds(f"{base_url}/samples.rds")
|
|
71
|
+
|
|
72
|
+
# Check the content
|
|
73
|
+
assert isinstance(rds_content, SITSTimeSeriesModel)
|
|
74
|
+
|
|
75
|
+
|
|
56
76
|
def test_read_rds_file_not_found():
|
|
57
77
|
"""Test read RDS file not found."""
|
|
58
78
|
with pytest.raises(FileNotFoundError):
|
|
@@ -28,6 +28,20 @@ wheels = [
|
|
|
28
28
|
{ url = "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl", hash = "sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0", size = 13427, upload-time = "2026-07-23T20:16:12.938Z" },
|
|
29
29
|
]
|
|
30
30
|
|
|
31
|
+
[[package]]
|
|
32
|
+
name = "anyio"
|
|
33
|
+
version = "4.15.1"
|
|
34
|
+
source = { registry = "https://pypi.org/simple" }
|
|
35
|
+
dependencies = [
|
|
36
|
+
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
|
37
|
+
{ name = "idna" },
|
|
38
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.15'" },
|
|
39
|
+
]
|
|
40
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a9/d2/f4d173e22df740bc37b1db102b386ba719b66e95b0f0d751f556b387e6d2/anyio-4.15.1.tar.gz", hash = "sha256:9f28306018cbd6d329e64a36d58256edff76dd996fe423bc957326e578b82a94", size = 276966, upload-time = "2026-09-05T10:42:39.44Z" }
|
|
41
|
+
wheels = [
|
|
42
|
+
{ url = "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl", hash = "sha256:6152fdbbf9a77fdec97731721bebf7c4c44f7c29b424b0065826173efc7ed101", size = 132079, upload-time = "2026-09-05T10:42:37.923Z" },
|
|
43
|
+
]
|
|
44
|
+
|
|
31
45
|
[[package]]
|
|
32
46
|
name = "appnope"
|
|
33
47
|
version = "0.1.4"
|
|
@@ -752,6 +766,54 @@ wheels = [
|
|
|
752
766
|
{ url = "https://files.pythonhosted.org/packages/be/82/79e02a0e5dd4aca81894842b9d6522624a40048a913c6384efb2987a4144/geopandas-1.1.0-py3-none-any.whl", hash = "sha256:b19b18bdc736ee05b237f5e9184211c452768a4c883f7d7f8421b0cbe1da5875", size = 338014, upload-time = "2025-06-01T16:54:29.239Z" },
|
|
753
767
|
]
|
|
754
768
|
|
|
769
|
+
[[package]]
|
|
770
|
+
name = "h11"
|
|
771
|
+
version = "0.16.0"
|
|
772
|
+
source = { registry = "https://pypi.org/simple" }
|
|
773
|
+
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
|
|
774
|
+
wheels = [
|
|
775
|
+
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
|
776
|
+
]
|
|
777
|
+
|
|
778
|
+
[[package]]
|
|
779
|
+
name = "httpcore2"
|
|
780
|
+
version = "2.13.0"
|
|
781
|
+
source = { registry = "https://pypi.org/simple" }
|
|
782
|
+
dependencies = [
|
|
783
|
+
{ name = "h11" },
|
|
784
|
+
{ name = "truststore" },
|
|
785
|
+
]
|
|
786
|
+
sdist = { url = "https://files.pythonhosted.org/packages/15/8c/e925b1c92018abb3a1863ce1549d76d2381e334d21d65d4ac8f65dabd78a/httpcore2-2.13.0.tar.gz", hash = "sha256:2adc8be4fb285fbcd6d894298db3b52c177e74b6674eda3a76bd36be3292a3db", size = 67740, upload-time = "2026-09-14T14:18:04.717Z" }
|
|
787
|
+
wheels = [
|
|
788
|
+
{ url = "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl", hash = "sha256:35ae5be347aa40467b4a5dc032ac67ebb6d27189fc97e8cebcf99616f6a1bb9e", size = 83162, upload-time = "2026-09-14T14:18:02.529Z" },
|
|
789
|
+
]
|
|
790
|
+
|
|
791
|
+
[[package]]
|
|
792
|
+
name = "httpx2"
|
|
793
|
+
version = "2.13.0"
|
|
794
|
+
source = { registry = "https://pypi.org/simple" }
|
|
795
|
+
dependencies = [
|
|
796
|
+
{ name = "anyio", marker = "sys_platform != 'emscripten'" },
|
|
797
|
+
{ name = "httpcore2", marker = "sys_platform != 'emscripten'" },
|
|
798
|
+
{ name = "httpx2-jsfetch", marker = "python_full_version >= '3.12' and sys_platform == 'emscripten'" },
|
|
799
|
+
{ name = "idna" },
|
|
800
|
+
{ name = "truststore", marker = "sys_platform != 'emscripten'" },
|
|
801
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
|
802
|
+
]
|
|
803
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b9/a0/e9deef4654132857b5a5dbe4eddd0ac59c2814500e11f2f5044cd81103ee/httpx2-2.13.0.tar.gz", hash = "sha256:81bd07dc67a3701729ef1f777a3c00c915d4539604fdb5afd327f8682f6b7b44", size = 100290, upload-time = "2026-09-14T14:18:05.486Z" }
|
|
804
|
+
wheels = [
|
|
805
|
+
{ url = "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl", hash = "sha256:fc12720cedf72faa26cca6b4ca394e05c894e7d7933fc45cafe767960804e49a", size = 95565, upload-time = "2026-09-14T14:18:03.553Z" },
|
|
806
|
+
]
|
|
807
|
+
|
|
808
|
+
[[package]]
|
|
809
|
+
name = "httpx2-jsfetch"
|
|
810
|
+
version = "1.0"
|
|
811
|
+
source = { registry = "https://pypi.org/simple" }
|
|
812
|
+
sdist = { url = "https://files.pythonhosted.org/packages/cd/c4/0e5636363151a2a1795e0a77617168b9ca438e1748ec05fc9b5687f93d64/httpx2_jsfetch-1.0.tar.gz", hash = "sha256:70a0e3eabfef7cce5ad9c629f7d01ca05e418f586646f4ddf14782e4c1454c60", size = 6872, upload-time = "2026-08-07T00:13:07.492Z" }
|
|
813
|
+
wheels = [
|
|
814
|
+
{ url = "https://files.pythonhosted.org/packages/9b/43/832f631d32e4f1211caa2ba368317739fe71f0b8530e4c9d15dc454bac2a/httpx2_jsfetch-1.0-py3-none-any.whl", hash = "sha256:cb916b707601e69a07721aabc8f3f6659be3a6893bc1ff5c6f9e02241df2da32", size = 6382, upload-time = "2026-08-07T00:13:06.567Z" },
|
|
815
|
+
]
|
|
816
|
+
|
|
755
817
|
[[package]]
|
|
756
818
|
name = "identify"
|
|
757
819
|
version = "2.6.12"
|
|
@@ -2266,10 +2328,11 @@ wheels = [
|
|
|
2266
2328
|
|
|
2267
2329
|
[[package]]
|
|
2268
2330
|
name = "pysits"
|
|
2269
|
-
version = "2.0.0.
|
|
2331
|
+
version = "2.0.0.dev8"
|
|
2270
2332
|
source = { editable = "." }
|
|
2271
2333
|
dependencies = [
|
|
2272
2334
|
{ name = "geopandas" },
|
|
2335
|
+
{ name = "httpx2" },
|
|
2273
2336
|
{ name = "jinja2" },
|
|
2274
2337
|
{ name = "matplotlib", version = "3.10.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
|
2275
2338
|
{ name = "matplotlib", version = "3.11.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
|
@@ -2316,6 +2379,7 @@ requires-dist = [
|
|
|
2316
2379
|
{ name = "cloudpickle", marker = "extra == 'dev'", specifier = ">=3.1.1" },
|
|
2317
2380
|
{ name = "dask", marker = "extra == 'xarray'", specifier = ">=2025.3.0" },
|
|
2318
2381
|
{ name = "geopandas", specifier = ">=1.1.0" },
|
|
2382
|
+
{ name = "httpx2", specifier = ">=2.13.0" },
|
|
2319
2383
|
{ name = "ipykernel", marker = "extra == 'dev'", specifier = ">=6.29.0" },
|
|
2320
2384
|
{ name = "jinja2", specifier = ">=3.1.6" },
|
|
2321
2385
|
{ name = "matplotlib", specifier = ">=3.10.1" },
|
|
@@ -3541,6 +3605,15 @@ wheels = [
|
|
|
3541
3605
|
{ url = "https://files.pythonhosted.org/packages/ad/66/0d785f0bc5e4315a96c989bb476d0fc07ea4f85132550c7b156ca2035d52/traitlets-5.16.1-py3-none-any.whl", hash = "sha256:f775618166caa0396c8e337099240f2bd3e5e917d203b2e6fbe21a58d3cb1f6b", size = 86211, upload-time = "2026-08-03T08:32:34.48Z" },
|
|
3542
3606
|
]
|
|
3543
3607
|
|
|
3608
|
+
[[package]]
|
|
3609
|
+
name = "truststore"
|
|
3610
|
+
version = "0.10.4"
|
|
3611
|
+
source = { registry = "https://pypi.org/simple" }
|
|
3612
|
+
sdist = { url = "https://files.pythonhosted.org/packages/53/a3/1585216310e344e8102c22482f6060c7a6ea0322b63e026372e6dcefcfd6/truststore-0.10.4.tar.gz", hash = "sha256:9d91bd436463ad5e4ee4aba766628dd6cd7010cf3e2461756b3303710eebc301", size = 26169, upload-time = "2025-08-12T18:49:02.73Z" }
|
|
3613
|
+
wheels = [
|
|
3614
|
+
{ url = "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl", hash = "sha256:adaeaecf1cbb5f4de3b1959b42d41f6fab57b2b1666adb59e89cb0b53361d981", size = 18660, upload-time = "2025-08-12T18:49:01.46Z" },
|
|
3615
|
+
]
|
|
3616
|
+
|
|
3544
3617
|
[[package]]
|
|
3545
3618
|
name = "typing-extensions"
|
|
3546
3619
|
version = "4.16.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|