UncountablePythonSDK 0.0.41__tar.gz → 0.0.42__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.
Potentially problematic release.
This version of UncountablePythonSDK might be problematic. Click here for more details.
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/.github/workflows/documentation.yml +2 -3
- {uncountablepythonsdk-0.0.41/UncountablePythonSDK.egg-info → uncountablepythonsdk-0.0.42}/PKG-INFO +5 -1
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42/UncountablePythonSDK.egg-info}/PKG-INFO +5 -1
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/UncountablePythonSDK.egg-info/SOURCES.txt +20 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/UncountablePythonSDK.egg-info/requires.txt +4 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/requirements.txt +3 -3
- uncountablepythonsdk-0.0.42/examples/invoke_uploader.py +23 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/argument_parser/argument_parser.py +1 -1
- uncountablepythonsdk-0.0.42/pkgs/filesystem_utils/__init__.py +17 -0
- uncountablepythonsdk-0.0.42/pkgs/filesystem_utils/_gdrive_session.py +306 -0
- uncountablepythonsdk-0.0.42/pkgs/filesystem_utils/_local_session.py +69 -0
- uncountablepythonsdk-0.0.42/pkgs/filesystem_utils/_sftp_session.py +147 -0
- uncountablepythonsdk-0.0.42/pkgs/filesystem_utils/file_type_utils.py +61 -0
- uncountablepythonsdk-0.0.42/pkgs/filesystem_utils/filesystem_session.py +39 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/emit_open_api.py +4 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/emit_open_api_util.py +4 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/emit_python.py +13 -14
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pyproject.toml +5 -1
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/core/file_upload.py +13 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/integration/construct_client.py +1 -1
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/integration/cron.py +9 -6
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/integration/entrypoint.py +1 -1
- uncountablepythonsdk-0.0.42/uncountable/integration/executors/executors.py +24 -0
- uncountablepythonsdk-0.0.42/uncountable/integration/executors/generic_upload_executor.py +245 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/integration/executors/script_executor.py +1 -1
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/integration/job.py +18 -1
- uncountablepythonsdk-0.0.42/uncountable/integration/secret_retrieval/__init__.py +3 -0
- uncountablepythonsdk-0.0.42/uncountable/integration/secret_retrieval/retrieve_secret.py +40 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/integration/server.py +1 -1
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/__init__.py +8 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/batch/execute_batch.py +5 -5
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/batch/execute_batch_load_async.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/chemical/convert_chemical_formats.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/entity/create_entities.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/entity/create_entity.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/entity/get_entities_data.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/entity/list_entities.py +5 -5
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/entity/lock_entity.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/entity/resolve_entity_ids.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/entity/set_values.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/entity/transition_entity_phase.py +5 -5
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/entity/unlock_entity.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/equipment/associate_equipment_input.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/field_options/upsert_field_options.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/id_source/list_id_source.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/id_source/match_id_source.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/input_groups/get_input_group_names.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/inputs/create_inputs.py +5 -5
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/inputs/get_input_data.py +7 -7
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/inputs/get_input_names.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/inputs/get_inputs_data.py +7 -7
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/inputs/set_input_attribute_values.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/inputs/set_input_category.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/inputs/set_input_subcategories.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/inputs/set_intermediate_type.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/material_families/update_entity_material_families.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/outputs/get_output_data.py +7 -7
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/outputs/get_output_names.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/outputs/resolve_output_conditions.py +6 -6
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/permissions/set_core_permissions.py +7 -7
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/project/get_projects.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/project/get_projects_data.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipe_links/create_recipe_link.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipe_links/remove_recipe_link.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipe_metadata/get_recipe_metadata_data.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/add_recipe_to_project.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/archive_recipes.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/associate_recipe_as_input.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/associate_recipe_as_lot.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/create_recipe.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/create_recipes.py +5 -5
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/disassociate_recipe_as_input.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/edit_recipe_inputs.py +12 -12
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/get_curve.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/get_recipe_calculations.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/get_recipe_links.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/get_recipe_names.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/get_recipe_output_metadata.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/get_recipes_data.py +12 -12
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/lock_recipes.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/remove_recipe_from_project.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/set_recipe_inputs.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/set_recipe_metadata.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/set_recipe_output_annotations.py +7 -7
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/set_recipe_outputs.py +5 -5
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/set_recipe_tags.py +7 -7
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/unarchive_recipes.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/unlock_recipes.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/triggers/run_trigger.py +3 -3
- uncountablepythonsdk-0.0.42/uncountable/types/api/uploader/__init__.py +1 -0
- uncountablepythonsdk-0.0.42/uncountable/types/api/uploader/invoke_uploader.py +38 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/async_batch_processor.py +36 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/async_batch_t.py +6 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/calculations_t.py +2 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/chemical_structure_t.py +2 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/client_base.py +25 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/curves_t.py +3 -3
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/entity_t.py +2 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/experiment_groups_t.py +2 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/field_values_t.py +5 -5
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/fields_t.py +2 -2
- uncountablepythonsdk-0.0.42/uncountable/types/generic_upload.py +9 -0
- uncountablepythonsdk-0.0.42/uncountable/types/generic_upload_t.py +41 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/id_source_t.py +5 -5
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/identifier_t.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/input_attributes_t.py +2 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/inputs_t.py +2 -2
- uncountablepythonsdk-0.0.42/uncountable/types/job_definition.py +26 -0
- uncountablepythonsdk-0.0.42/uncountable/types/job_definition_t.py +203 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/outputs_t.py +2 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/phases_t.py +2 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipe_identifiers_t.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipe_links_t.py +2 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipe_metadata_t.py +4 -4
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipe_output_metadata_t.py +2 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipe_tags_t.py +2 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipe_workflow_steps_t.py +5 -5
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipes_t.py +2 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/response_t.py +2 -2
- uncountablepythonsdk-0.0.42/uncountable/types/secret_retrieval.py +12 -0
- uncountablepythonsdk-0.0.42/uncountable/types/secret_retrieval_t.py +69 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/units_t.py +2 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/users_t.py +2 -2
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/workflows_t.py +3 -3
- uncountablepythonsdk-0.0.41/uncountable/integration/types.py +0 -89
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/.github/workflows/publish.yml +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/.gitignore +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/README.md +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/UncountablePythonSDK.egg-info/dependency_links.txt +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/UncountablePythonSDK.egg-info/top_level.txt +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/.gitignore +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/conf.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/index.md +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/justfile +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/quickstart.md +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/static/favicons/android-chrome-192x192.png +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/static/favicons/android-chrome-512x512.png +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/static/favicons/apple-touch-icon.png +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/static/favicons/browserconfig.xml +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/static/favicons/favicon-16x16.png +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/static/favicons/favicon-32x32.png +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/static/favicons/manifest.json +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/static/favicons/mstile-150x150.png +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/static/favicons/safari-pinned-tab.svg +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/docs/static/logo_blue.png +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/examples/async_batch.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/examples/create_entity.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/examples/edit_recipe_inputs.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/examples/upload_files.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/argument_parser/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/argument_parser/_is_enum.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/argument_parser/_is_namedtuple.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/argument_parser/case_convert.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/serialization/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/serialization/missing_sentry.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/serialization/opaque_key.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/serialization/serial_class.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/serialization/serial_union.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/serialization/yaml.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/serialization_util/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/serialization_util/_get_type_for_serialization.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/serialization_util/convert_to_snakecase.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/serialization_util/serialization_helpers.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/strenum_compat/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/strenum_compat/strenum_compat.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/__main__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/actions_registry/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/actions_registry/__main__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/actions_registry/emit_typescript.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/builder.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/config.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/emit_io_ts.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/emit_typescript.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/emit_typescript_util.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/load_types.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/open_api_util.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/parts/base.py.prepart +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/parts/base.ts.prepart +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/test.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/type_info/__main__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/type_info/emit_type_info.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/util.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/value_spec/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/value_spec/__main__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/value_spec/convert_type.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/value_spec/emit_python.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/type_spec/value_spec/types.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/setup.cfg +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/core/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/core/async_batch.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/core/client.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/core/types.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/integration/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/integration/db/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/integration/db/connect.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/integration/executors/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/py.typed +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/batch/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/chemical/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/entity/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/equipment/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/field_options/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/id_source/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/input_groups/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/inputs/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/material_families/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/outputs/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/permissions/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/project/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipe_links/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipe_metadata/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/recipes/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/api/triggers/__init__.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/async_batch.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/base.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/base_t.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/calculations.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/chemical_structure.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/curves.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/entity.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/experiment_groups.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/field_values.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/fields.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/id_source.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/identifier.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/input_attributes.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/inputs.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/outputs.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/permissions.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/permissions_t.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/phases.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/post_base.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/post_base_t.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipe_identifiers.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipe_inputs.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipe_inputs_t.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipe_links.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipe_metadata.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipe_output_metadata.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipe_tags.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipe_workflow_steps.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/recipes.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/response.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/units.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/users.py +0 -0
- {uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/uncountable/types/workflows.py +0 -0
{uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/.github/workflows/documentation.yml
RENAMED
|
@@ -11,10 +11,9 @@ jobs:
|
|
|
11
11
|
steps:
|
|
12
12
|
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
|
|
13
13
|
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5
|
|
14
|
-
- uses: extractions/setup-
|
|
14
|
+
- uses: extractions/setup-crate@4993624604c307fbca528d28a3c8b60fa5ecc859 # v1
|
|
15
15
|
with:
|
|
16
|
-
|
|
17
|
-
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
16
|
+
repo: casey/just@0.10
|
|
18
17
|
- name: Install dependencies
|
|
19
18
|
run: |
|
|
20
19
|
# install the dependencies for the package
|
{uncountablepythonsdk-0.0.41/UncountablePythonSDK.egg-info → uncountablepythonsdk-0.0.42}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: UncountablePythonSDK
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.42
|
|
4
4
|
Summary: Uncountable SDK
|
|
5
5
|
Project-URL: Homepage, https://github.com/uncountableinc/uncountable-python-sdk
|
|
6
6
|
Project-URL: Repository, https://github.com/uncountableinc/uncountable-python-sdk.git
|
|
@@ -24,6 +24,10 @@ Requires-Dist: APScheduler==3.*
|
|
|
24
24
|
Requires-Dist: python-dateutil==2.*
|
|
25
25
|
Requires-Dist: shelljob==0.*
|
|
26
26
|
Requires-Dist: PyYAML==6.*
|
|
27
|
+
Requires-Dist: google-api-python-client==2.*
|
|
28
|
+
Requires-Dist: tqdm==4.*
|
|
29
|
+
Requires-Dist: pysftp==0.*
|
|
30
|
+
Requires-Dist: paramiko==3.*
|
|
27
31
|
Provides-Extra: test
|
|
28
32
|
Requires-Dist: mypy==1.*; extra == "test"
|
|
29
33
|
Requires-Dist: ruff==0.*; extra == "test"
|
{uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42/UncountablePythonSDK.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: UncountablePythonSDK
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.42
|
|
4
4
|
Summary: Uncountable SDK
|
|
5
5
|
Project-URL: Homepage, https://github.com/uncountableinc/uncountable-python-sdk
|
|
6
6
|
Project-URL: Repository, https://github.com/uncountableinc/uncountable-python-sdk.git
|
|
@@ -24,6 +24,10 @@ Requires-Dist: APScheduler==3.*
|
|
|
24
24
|
Requires-Dist: python-dateutil==2.*
|
|
25
25
|
Requires-Dist: shelljob==0.*
|
|
26
26
|
Requires-Dist: PyYAML==6.*
|
|
27
|
+
Requires-Dist: google-api-python-client==2.*
|
|
28
|
+
Requires-Dist: tqdm==4.*
|
|
29
|
+
Requires-Dist: pysftp==0.*
|
|
30
|
+
Requires-Dist: paramiko==3.*
|
|
27
31
|
Provides-Extra: test
|
|
28
32
|
Requires-Dist: mypy==1.*; extra == "test"
|
|
29
33
|
Requires-Dist: ruff==0.*; extra == "test"
|
|
@@ -27,6 +27,7 @@ docs/static/favicons/safari-pinned-tab.svg
|
|
|
27
27
|
examples/async_batch.py
|
|
28
28
|
examples/create_entity.py
|
|
29
29
|
examples/edit_recipe_inputs.py
|
|
30
|
+
examples/invoke_uploader.py
|
|
30
31
|
examples/upload_files.py
|
|
31
32
|
pkgs/__init__.py
|
|
32
33
|
pkgs/argument_parser/__init__.py
|
|
@@ -34,6 +35,12 @@ pkgs/argument_parser/_is_enum.py
|
|
|
34
35
|
pkgs/argument_parser/_is_namedtuple.py
|
|
35
36
|
pkgs/argument_parser/argument_parser.py
|
|
36
37
|
pkgs/argument_parser/case_convert.py
|
|
38
|
+
pkgs/filesystem_utils/__init__.py
|
|
39
|
+
pkgs/filesystem_utils/_gdrive_session.py
|
|
40
|
+
pkgs/filesystem_utils/_local_session.py
|
|
41
|
+
pkgs/filesystem_utils/_sftp_session.py
|
|
42
|
+
pkgs/filesystem_utils/file_type_utils.py
|
|
43
|
+
pkgs/filesystem_utils/filesystem_session.py
|
|
37
44
|
pkgs/serialization/__init__.py
|
|
38
45
|
pkgs/serialization/missing_sentry.py
|
|
39
46
|
pkgs/serialization/opaque_key.py
|
|
@@ -85,11 +92,14 @@ uncountable/integration/cron.py
|
|
|
85
92
|
uncountable/integration/entrypoint.py
|
|
86
93
|
uncountable/integration/job.py
|
|
87
94
|
uncountable/integration/server.py
|
|
88
|
-
uncountable/integration/types.py
|
|
89
95
|
uncountable/integration/db/__init__.py
|
|
90
96
|
uncountable/integration/db/connect.py
|
|
91
97
|
uncountable/integration/executors/__init__.py
|
|
98
|
+
uncountable/integration/executors/executors.py
|
|
99
|
+
uncountable/integration/executors/generic_upload_executor.py
|
|
92
100
|
uncountable/integration/executors/script_executor.py
|
|
101
|
+
uncountable/integration/secret_retrieval/__init__.py
|
|
102
|
+
uncountable/integration/secret_retrieval/retrieve_secret.py
|
|
93
103
|
uncountable/types/__init__.py
|
|
94
104
|
uncountable/types/async_batch.py
|
|
95
105
|
uncountable/types/async_batch_processor.py
|
|
@@ -111,6 +121,8 @@ uncountable/types/field_values.py
|
|
|
111
121
|
uncountable/types/field_values_t.py
|
|
112
122
|
uncountable/types/fields.py
|
|
113
123
|
uncountable/types/fields_t.py
|
|
124
|
+
uncountable/types/generic_upload.py
|
|
125
|
+
uncountable/types/generic_upload_t.py
|
|
114
126
|
uncountable/types/id_source.py
|
|
115
127
|
uncountable/types/id_source_t.py
|
|
116
128
|
uncountable/types/identifier.py
|
|
@@ -119,6 +131,8 @@ uncountable/types/input_attributes.py
|
|
|
119
131
|
uncountable/types/input_attributes_t.py
|
|
120
132
|
uncountable/types/inputs.py
|
|
121
133
|
uncountable/types/inputs_t.py
|
|
134
|
+
uncountable/types/job_definition.py
|
|
135
|
+
uncountable/types/job_definition_t.py
|
|
122
136
|
uncountable/types/outputs.py
|
|
123
137
|
uncountable/types/outputs_t.py
|
|
124
138
|
uncountable/types/permissions.py
|
|
@@ -145,6 +159,8 @@ uncountable/types/recipes.py
|
|
|
145
159
|
uncountable/types/recipes_t.py
|
|
146
160
|
uncountable/types/response.py
|
|
147
161
|
uncountable/types/response_t.py
|
|
162
|
+
uncountable/types/secret_retrieval.py
|
|
163
|
+
uncountable/types/secret_retrieval_t.py
|
|
148
164
|
uncountable/types/units.py
|
|
149
165
|
uncountable/types/units_t.py
|
|
150
166
|
uncountable/types/users.py
|
|
@@ -226,4 +242,6 @@ uncountable/types/api/recipes/set_recipe_tags.py
|
|
|
226
242
|
uncountable/types/api/recipes/unarchive_recipes.py
|
|
227
243
|
uncountable/types/api/recipes/unlock_recipes.py
|
|
228
244
|
uncountable/types/api/triggers/__init__.py
|
|
229
|
-
uncountable/types/api/triggers/run_trigger.py
|
|
245
|
+
uncountable/types/api/triggers/run_trigger.py
|
|
246
|
+
uncountable/types/api/uploader/__init__.py
|
|
247
|
+
uncountable/types/api/uploader/invoke_uploader.py
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from uncountable.core import AuthDetailsApiKey, Client, MediaFileUpload
|
|
4
|
+
from uncountable.types.identifier_t import IdentifierKeyId
|
|
5
|
+
|
|
6
|
+
client = Client(
|
|
7
|
+
base_url="http://localhost:5000",
|
|
8
|
+
auth_details=AuthDetailsApiKey(
|
|
9
|
+
api_id=os.environ["UNC_API_ID"],
|
|
10
|
+
api_secret_key=os.environ["UNC_API_SECRET_KEY"],
|
|
11
|
+
),
|
|
12
|
+
)
|
|
13
|
+
uploaded = client.upload_files(
|
|
14
|
+
file_uploads=[
|
|
15
|
+
MediaFileUpload(path="~/Downloads/my_file_to_upload.csv"),
|
|
16
|
+
]
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
client.invoke_uploader(
|
|
20
|
+
file_ids=[file.file_id for file in uploaded],
|
|
21
|
+
uploader_key=IdentifierKeyId(id=48),
|
|
22
|
+
material_family_keys=[IdentifierKeyId(id=1)],
|
|
23
|
+
)
|
{uncountablepythonsdk-0.0.41 → uncountablepythonsdk-0.0.42}/pkgs/argument_parser/argument_parser.py
RENAMED
|
@@ -218,7 +218,7 @@ def _build_parser_inner(
|
|
|
218
218
|
arg_parsers = [_build_parser_inner(arg, context) for arg in sorted_args]
|
|
219
219
|
return lambda value: _invoke_fallback_parsers(parsed_type, arg_parsers, value)
|
|
220
220
|
|
|
221
|
-
if parsed_type is typing.Any:
|
|
221
|
+
if parsed_type is typing.Any: # type: ignore[comparison-overlap]
|
|
222
222
|
return lambda value: value
|
|
223
223
|
|
|
224
224
|
if origin in (list, set):
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from ._gdrive_session import GDriveSession as GDriveSession
|
|
2
|
+
from ._gdrive_session import delete_gdrive_file as delete_gdrive_file
|
|
3
|
+
from ._gdrive_session import download_gdrive_file as download_gdrive_file
|
|
4
|
+
from ._gdrive_session import list_gdrive_files as list_gdrive_files
|
|
5
|
+
from ._gdrive_session import move_gdrive_file as move_gdrive_file
|
|
6
|
+
from ._gdrive_session import upload_file_gdrive as upload_file_gdrive
|
|
7
|
+
from ._local_session import LocalSession as LocalSession
|
|
8
|
+
from ._sftp_session import SFTPSession as SFTPSession
|
|
9
|
+
from ._sftp_session import list_sftp_files as list_sftp_files
|
|
10
|
+
from ._sftp_session import move_sftp_files as move_sftp_files
|
|
11
|
+
from .file_type_utils import FileObjectData as FileObjectData
|
|
12
|
+
from .file_type_utils import FileSystemFileReference as FileSystemFileReference
|
|
13
|
+
from .file_type_utils import FileSystemObject as FileSystemObject
|
|
14
|
+
from .file_type_utils import FileSystemSFTPConfig as FileSystemSFTPConfig
|
|
15
|
+
from .file_type_utils import FileTransfer as FileTransfer
|
|
16
|
+
from .file_type_utils import IncompatibleFileReference as IncompatibleFileReference
|
|
17
|
+
from .file_type_utils import RemoteObjectReference as RemoteObjectReference
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from io import BytesIO
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
|
|
5
|
+
from google.oauth2 import service_account
|
|
6
|
+
from googleapiclient.discovery import build as build_gdrive_connection
|
|
7
|
+
from googleapiclient.errors import HttpError
|
|
8
|
+
from googleapiclient.http import MediaIoBaseDownload, MediaIoBaseUpload
|
|
9
|
+
from tqdm import tqdm
|
|
10
|
+
|
|
11
|
+
from pkgs.filesystem_utils.file_type_utils import (
|
|
12
|
+
FileObjectData,
|
|
13
|
+
FileSystemFileReference,
|
|
14
|
+
FileSystemObject,
|
|
15
|
+
FileTransfer,
|
|
16
|
+
IncompatibleFileReference,
|
|
17
|
+
RemoteObjectReference,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from .filesystem_session import FileSystemSession
|
|
21
|
+
|
|
22
|
+
# NOTE: google apis do not have static types
|
|
23
|
+
GDriveResource = Any
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def download_gdrive_file(
|
|
27
|
+
gdrive_connection: GDriveResource,
|
|
28
|
+
file_id: str,
|
|
29
|
+
filename: str,
|
|
30
|
+
mime_type: str,
|
|
31
|
+
*,
|
|
32
|
+
verbose: bool = False,
|
|
33
|
+
) -> Optional[FileObjectData]:
|
|
34
|
+
if "folder" in mime_type:
|
|
35
|
+
if verbose:
|
|
36
|
+
print(f"{filename} is a folder and will not be downloaded.")
|
|
37
|
+
return None
|
|
38
|
+
elif "google-apps" in mime_type:
|
|
39
|
+
# Handle google workspace doc
|
|
40
|
+
if "spreadsheet" in mime_type:
|
|
41
|
+
if verbose:
|
|
42
|
+
print(f"{filename} is a Google Sheet, exporting.")
|
|
43
|
+
file_request = gdrive_connection.files().export_media(
|
|
44
|
+
fileId=file_id, mimeType="text/csv"
|
|
45
|
+
)
|
|
46
|
+
filename += ".csv"
|
|
47
|
+
elif "document" in mime_type:
|
|
48
|
+
if verbose:
|
|
49
|
+
print(f"{filename} is a Google Doc, exporting.")
|
|
50
|
+
file_request = gdrive_connection.files().export_media(
|
|
51
|
+
fileId=file_id, mimeType="application/msword"
|
|
52
|
+
)
|
|
53
|
+
filename += ".doc"
|
|
54
|
+
else:
|
|
55
|
+
if verbose:
|
|
56
|
+
print(f"{filename} is an unsupported google workspace filetype.")
|
|
57
|
+
print(f"Skipping. mimeType: {mime_type}.")
|
|
58
|
+
return None
|
|
59
|
+
else:
|
|
60
|
+
file_request = gdrive_connection.files().get_media(fileId=file_id)
|
|
61
|
+
|
|
62
|
+
file_handler = BytesIO()
|
|
63
|
+
downloader = MediaIoBaseDownload(file_handler, file_request)
|
|
64
|
+
download_complete = False
|
|
65
|
+
while not download_complete:
|
|
66
|
+
status, download_complete = downloader.next_chunk()
|
|
67
|
+
|
|
68
|
+
file_handler.seek(0)
|
|
69
|
+
file_data = file_handler.read()
|
|
70
|
+
return FileObjectData(
|
|
71
|
+
file_data=file_data,
|
|
72
|
+
file_IO=BytesIO(file_data),
|
|
73
|
+
filename=filename,
|
|
74
|
+
filepath=file_id,
|
|
75
|
+
metadata={"id": file_id},
|
|
76
|
+
mime_type=mime_type,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def list_gdrive_files(
|
|
81
|
+
gdrive_connection: GDriveResource, gdrive_folder_id: str, *, recurse: bool = False
|
|
82
|
+
) -> list[dict[str, str]]:
|
|
83
|
+
query = f"parents = '{gdrive_folder_id}'"
|
|
84
|
+
print("Listing files", end="", flush=True)
|
|
85
|
+
paginated_files_in_folder = [
|
|
86
|
+
(
|
|
87
|
+
gdrive_connection.files()
|
|
88
|
+
.list(
|
|
89
|
+
q=query,
|
|
90
|
+
corpora="allDrives",
|
|
91
|
+
includeItemsFromAllDrives=True,
|
|
92
|
+
supportsAllDrives=True,
|
|
93
|
+
)
|
|
94
|
+
.execute()
|
|
95
|
+
)
|
|
96
|
+
]
|
|
97
|
+
while paginated_files_in_folder[-1].get("nextPageToken") is not None:
|
|
98
|
+
print(".", end="", flush=True)
|
|
99
|
+
paginated_files_in_folder.append(
|
|
100
|
+
gdrive_connection.files()
|
|
101
|
+
.list(
|
|
102
|
+
q=query,
|
|
103
|
+
corpora="allDrives",
|
|
104
|
+
includeItemsFromAllDrives=True,
|
|
105
|
+
supportsAllDrives=True,
|
|
106
|
+
pageToken=paginated_files_in_folder[-1]["nextPageToken"],
|
|
107
|
+
)
|
|
108
|
+
.execute()
|
|
109
|
+
)
|
|
110
|
+
print()
|
|
111
|
+
# Get available files: https://developers.google.com/drive/api/v3/manage-downloads#python
|
|
112
|
+
files: list[dict[str, str]] = []
|
|
113
|
+
for files_in_folder in paginated_files_in_folder:
|
|
114
|
+
files.extend(files_in_folder.get("files", []))
|
|
115
|
+
subfiles: list[dict[str, str]] = []
|
|
116
|
+
if recurse:
|
|
117
|
+
for file in files:
|
|
118
|
+
if file["mimeType"] == "application/vnd.google-apps.folder":
|
|
119
|
+
subfiles.extend(
|
|
120
|
+
list_gdrive_files(
|
|
121
|
+
gdrive_connection=gdrive_connection,
|
|
122
|
+
gdrive_folder_id=file["id"],
|
|
123
|
+
recurse=True,
|
|
124
|
+
)
|
|
125
|
+
)
|
|
126
|
+
return [*files, *subfiles]
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def upload_file_gdrive(
|
|
130
|
+
gdrive_connection: GDriveResource,
|
|
131
|
+
src_file: BytesIO,
|
|
132
|
+
mime_type: str,
|
|
133
|
+
dest_folder_id: str,
|
|
134
|
+
dest_filename: str,
|
|
135
|
+
) -> None:
|
|
136
|
+
file_metadata = {"name": dest_filename, "parents": [dest_folder_id]}
|
|
137
|
+
media = MediaIoBaseUpload(src_file, mimetype=mime_type)
|
|
138
|
+
try:
|
|
139
|
+
gdrive_connection.files().create(
|
|
140
|
+
body=file_metadata, media_body=media, fields="id", supportsAllDrives=True
|
|
141
|
+
).execute()
|
|
142
|
+
except HttpError:
|
|
143
|
+
print("FileSystemObject Upload to GDrive Unsuccessful")
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def move_gdrive_file(
|
|
147
|
+
gdrive_connection: GDriveResource,
|
|
148
|
+
src_file_id: str,
|
|
149
|
+
dest_folder_id: str,
|
|
150
|
+
*,
|
|
151
|
+
dest_filename: Optional[str] = None,
|
|
152
|
+
) -> None:
|
|
153
|
+
# Retrieve the existing parents to remove
|
|
154
|
+
file = (
|
|
155
|
+
gdrive_connection.files()
|
|
156
|
+
.get(fileId=src_file_id, fields="parents, name", supportsTeamDrives=True)
|
|
157
|
+
.execute()
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
new_filename = file["name"]
|
|
161
|
+
if dest_filename is not None:
|
|
162
|
+
new_filename = dest_filename
|
|
163
|
+
previous_parents = ",".join(file.get("parents"))
|
|
164
|
+
metadata = {"name": new_filename}
|
|
165
|
+
gdrive_connection.files().update(
|
|
166
|
+
fileId=src_file_id, body=metadata, fields="name", supportsTeamDrives=True
|
|
167
|
+
).execute()
|
|
168
|
+
gdrive_connection.files().update(
|
|
169
|
+
fileId=src_file_id,
|
|
170
|
+
addParents=dest_folder_id,
|
|
171
|
+
removeParents=previous_parents,
|
|
172
|
+
fields="id, parents",
|
|
173
|
+
supportsTeamDrives=True,
|
|
174
|
+
).execute()
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def delete_gdrive_file(gdrive_connection: GDriveResource, file_id: str) -> None:
|
|
178
|
+
gdrive_connection.files().delete(fileId=file_id, supportsAllDrives=True).execute()
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class GDriveSession(FileSystemSession):
|
|
182
|
+
def __init__(self, service_account_json_path: str) -> None:
|
|
183
|
+
super().__init__()
|
|
184
|
+
self.service_account_json_path = service_account_json_path
|
|
185
|
+
|
|
186
|
+
def start(self) -> None:
|
|
187
|
+
credentials = service_account.Credentials.from_service_account_file( # type: ignore[no-untyped-call]
|
|
188
|
+
self.service_account_json_path
|
|
189
|
+
)
|
|
190
|
+
gdrive_connection = build_gdrive_connection(
|
|
191
|
+
"drive", "v3", credentials=credentials
|
|
192
|
+
)
|
|
193
|
+
self.connection = gdrive_connection
|
|
194
|
+
|
|
195
|
+
def list_files(
|
|
196
|
+
self,
|
|
197
|
+
dir_path: FileSystemObject,
|
|
198
|
+
*,
|
|
199
|
+
recursive: bool = False,
|
|
200
|
+
valid_file_extensions: Optional[tuple[str, ...]] = None,
|
|
201
|
+
) -> list[FileSystemObject]:
|
|
202
|
+
if not isinstance(dir_path, RemoteObjectReference):
|
|
203
|
+
raise IncompatibleFileReference(
|
|
204
|
+
"Incompatible FileSystemObject to GDriveSession.list_files"
|
|
205
|
+
)
|
|
206
|
+
if not dir_path.is_dir:
|
|
207
|
+
raise IncompatibleFileReference(
|
|
208
|
+
"FileSystemObject does not reference a directory"
|
|
209
|
+
)
|
|
210
|
+
files = list_gdrive_files(self.connection, dir_path.file_id, recurse=recursive)
|
|
211
|
+
gdrive_files: list[FileSystemObject] = []
|
|
212
|
+
for file_context in files:
|
|
213
|
+
if (
|
|
214
|
+
valid_file_extensions is not None
|
|
215
|
+
and os.path.splitext(file_context["name"])[1] not in valid_file_extensions
|
|
216
|
+
):
|
|
217
|
+
continue
|
|
218
|
+
gdrive_files.append(
|
|
219
|
+
RemoteObjectReference(
|
|
220
|
+
file_id=file_context["id"],
|
|
221
|
+
mime_type=file_context["mimeType"],
|
|
222
|
+
filename=file_context["name"],
|
|
223
|
+
)
|
|
224
|
+
)
|
|
225
|
+
return gdrive_files
|
|
226
|
+
|
|
227
|
+
def delete_files(self, filepaths: list[FileSystemObject]) -> None:
|
|
228
|
+
"""Warning:
|
|
229
|
+
Security account must have sufficient permissions to perform delete!
|
|
230
|
+
https://developers.google.com/drive/api/v3/reference/files/delete?hl=en
|
|
231
|
+
https://developers.google.com/drive/api/v3/ref-roles
|
|
232
|
+
"""
|
|
233
|
+
for file_object in filepaths:
|
|
234
|
+
if not isinstance(file_object, RemoteObjectReference):
|
|
235
|
+
raise IncompatibleFileReference(
|
|
236
|
+
"Incompatible FileSystemObject provided to GDriveSession.delete_files"
|
|
237
|
+
)
|
|
238
|
+
delete_gdrive_file(self.connection, file_object.file_id)
|
|
239
|
+
|
|
240
|
+
def move_files(self, file_mappings: list[FileTransfer]) -> None:
|
|
241
|
+
for src_file, dest_file in file_mappings:
|
|
242
|
+
if (
|
|
243
|
+
isinstance(src_file, FileSystemFileReference)
|
|
244
|
+
or not isinstance(dest_file, RemoteObjectReference)
|
|
245
|
+
or not dest_file.is_dir
|
|
246
|
+
or (isinstance(src_file, RemoteObjectReference) and src_file.is_dir)
|
|
247
|
+
):
|
|
248
|
+
continue
|
|
249
|
+
new_filename = dest_file.filename
|
|
250
|
+
if isinstance(src_file, RemoteObjectReference):
|
|
251
|
+
if new_filename is not None:
|
|
252
|
+
move_gdrive_file(
|
|
253
|
+
self.connection,
|
|
254
|
+
src_file.file_id,
|
|
255
|
+
dest_file.file_id,
|
|
256
|
+
dest_filename=new_filename,
|
|
257
|
+
)
|
|
258
|
+
else:
|
|
259
|
+
move_gdrive_file(self.connection, src_file.file_id, dest_file.file_id)
|
|
260
|
+
elif isinstance(src_file, FileObjectData):
|
|
261
|
+
if src_file.mime_type is None:
|
|
262
|
+
raise IncompatibleFileReference(
|
|
263
|
+
"No mime_type present on source file data."
|
|
264
|
+
)
|
|
265
|
+
new_filename = src_file.filename
|
|
266
|
+
if dest_file.filename is not None:
|
|
267
|
+
new_filename = dest_file.filename
|
|
268
|
+
upload_file_gdrive(
|
|
269
|
+
self.connection,
|
|
270
|
+
src_file.file_IO,
|
|
271
|
+
src_file.mime_type,
|
|
272
|
+
dest_file.file_id,
|
|
273
|
+
new_filename,
|
|
274
|
+
)
|
|
275
|
+
else:
|
|
276
|
+
raise IncompatibleFileReference(
|
|
277
|
+
"Unrecognized file reference in FileTransfer object"
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
def download_files(self, filepaths: list[FileSystemObject]) -> list[FileObjectData]:
|
|
281
|
+
downloaded_files: list[FileObjectData] = []
|
|
282
|
+
print(f"Downloading {len(filepaths)} files")
|
|
283
|
+
for file_object in tqdm(filepaths):
|
|
284
|
+
if (
|
|
285
|
+
not isinstance(file_object, RemoteObjectReference)
|
|
286
|
+
or file_object.filename is None
|
|
287
|
+
):
|
|
288
|
+
raise IncompatibleFileReference(
|
|
289
|
+
"Incompatible FileSystemObject included in filepaths"
|
|
290
|
+
)
|
|
291
|
+
downloaded_file = download_gdrive_file(
|
|
292
|
+
self.connection,
|
|
293
|
+
file_object.file_id,
|
|
294
|
+
file_object.filename,
|
|
295
|
+
file_object.mime_type,
|
|
296
|
+
)
|
|
297
|
+
if downloaded_file is not None:
|
|
298
|
+
downloaded_files.append(downloaded_file)
|
|
299
|
+
return downloaded_files
|
|
300
|
+
|
|
301
|
+
def __enter__(self) -> "GDriveSession":
|
|
302
|
+
self.start()
|
|
303
|
+
return self
|
|
304
|
+
|
|
305
|
+
def __exit__(self, exc_type: object, exc_val: object, exc_tb: object) -> None:
|
|
306
|
+
self.connection.close()
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from io import BytesIO
|
|
3
|
+
|
|
4
|
+
from pkgs.filesystem_utils.file_type_utils import (
|
|
5
|
+
FileObjectData,
|
|
6
|
+
FileSystemFileReference,
|
|
7
|
+
FileSystemObject,
|
|
8
|
+
FileTransfer,
|
|
9
|
+
IncompatibleFileReference,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
from .filesystem_session import FileSystemSession
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class LocalSession(FileSystemSession):
|
|
16
|
+
def __init__(self) -> None:
|
|
17
|
+
super().__init__()
|
|
18
|
+
|
|
19
|
+
def start(self) -> None:
|
|
20
|
+
return None
|
|
21
|
+
|
|
22
|
+
def __enter__(self) -> "LocalSession":
|
|
23
|
+
return self
|
|
24
|
+
|
|
25
|
+
def __exit__(self, exc_type: object, exc_val: object, exc_tb: object) -> None:
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
def move_files(self, file_mappings: list[FileTransfer]) -> None:
|
|
29
|
+
for src_file, dest_file in file_mappings:
|
|
30
|
+
if not (
|
|
31
|
+
isinstance(src_file, FileSystemFileReference)
|
|
32
|
+
and isinstance(dest_file, FileSystemFileReference)
|
|
33
|
+
):
|
|
34
|
+
raise IncompatibleFileReference()
|
|
35
|
+
os.rename(src_file.filepath, dest_file.filepath)
|
|
36
|
+
|
|
37
|
+
def download_files(self, filepaths: list[FileSystemObject]) -> list[FileObjectData]:
|
|
38
|
+
downloaded_files: list[FileObjectData] = []
|
|
39
|
+
for file_object in filepaths:
|
|
40
|
+
if (
|
|
41
|
+
not isinstance(file_object, FileSystemFileReference)
|
|
42
|
+
or file_object.filename is None
|
|
43
|
+
):
|
|
44
|
+
raise IncompatibleFileReference()
|
|
45
|
+
with open(file_object.filepath, "rb") as file_data:
|
|
46
|
+
file_bytes = file_data.read()
|
|
47
|
+
downloaded_files.append(
|
|
48
|
+
FileObjectData(
|
|
49
|
+
file_bytes,
|
|
50
|
+
BytesIO(file_bytes),
|
|
51
|
+
file_object.filename,
|
|
52
|
+
filepath=file_object.filepath,
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
return downloaded_files
|
|
56
|
+
|
|
57
|
+
def list_files(
|
|
58
|
+
self, dir_path: FileSystemObject, *, recursive: bool = False
|
|
59
|
+
) -> list[FileSystemObject]:
|
|
60
|
+
if not isinstance(dir_path, FileSystemFileReference) or not os.path.isdir(
|
|
61
|
+
dir_path.filepath
|
|
62
|
+
):
|
|
63
|
+
raise IncompatibleFileReference()
|
|
64
|
+
if recursive:
|
|
65
|
+
raise NotImplementedError("recursive not implemented for local session")
|
|
66
|
+
return [
|
|
67
|
+
FileSystemFileReference(os.path.join(dir_path.filepath, filename))
|
|
68
|
+
for filename in os.listdir(dir_path.filepath)
|
|
69
|
+
]
|