kernel 0.50.0__tar.gz → 0.52.0__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.
- kernel-0.52.0/.release-please-manifest.json +3 -0
- {kernel-0.50.0 → kernel-0.52.0}/CHANGELOG.md +71 -0
- {kernel-0.50.0 → kernel-0.52.0}/PKG-INFO +1 -1
- kernel-0.52.0/examples/browser_routing.py +26 -0
- {kernel-0.50.0 → kernel-0.52.0}/pyproject.toml +1 -1
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_client.py +111 -2
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_qs.py +2 -6
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_types.py +3 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_utils/_utils.py +34 -8
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_version.py +1 -1
- kernel-0.52.0/src/kernel/lib/browser_routing/__init__.py +3 -0
- kernel-0.52.0/src/kernel/lib/browser_routing/raw_http.py +150 -0
- kernel-0.52.0/src/kernel/lib/browser_routing/routing.py +243 -0
- kernel-0.52.0/src/kernel/lib/browser_routing/util.py +58 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/browsers/browsers.py +124 -1
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/profiles.py +4 -8
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/auth/managed_auth.py +27 -2
- kernel-0.52.0/tests/test_browser_routing.py +323 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/test_extract_files.py +23 -5
- {kernel-0.50.0 → kernel-0.52.0}/tests/test_files.py +1 -1
- kernel-0.50.0/.release-please-manifest.json +0 -3
- {kernel-0.50.0 → kernel-0.52.0}/.gitignore +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/CONTRIBUTING.md +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/LICENSE +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/README.md +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/SECURITY.md +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/api.md +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/bin/check-release-environment +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/bin/publish-pypi +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/examples/.keep +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/noxfile.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/release-please-config.json +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/requirements-dev.lock +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/requirements.lock +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_base_client.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_compat.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_constants.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_exceptions.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_files.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_models.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_resource.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_streaming.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_utils/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_utils/_compat.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_utils/_datetime_parse.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_utils/_json.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_utils/_logs.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_utils/_path.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_utils/_proxy.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_utils/_reflection.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_utils/_resources_proxy.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_utils/_streams.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_utils/_sync.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_utils/_transform.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/_utils/_typing.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/app_framework.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/lib/.keep +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/pagination.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/py.typed +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/apps.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/auth/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/auth/auth.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/auth/connections.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/browser_pools.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/browsers/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/browsers/computer.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/browsers/fs/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/browsers/fs/fs.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/browsers/fs/watch.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/browsers/logs.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/browsers/playwright.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/browsers/process.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/browsers/replays.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/credential_providers.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/credentials.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/deployments.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/extensions.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/invocations.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/projects/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/projects/limits.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/projects/projects.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/resources/proxies.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/app_list_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/app_list_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/auth/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/auth/connection_create_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/auth/connection_follow_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/auth/connection_list_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/auth/connection_login_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/auth/connection_submit_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/auth/connection_update_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/auth/login_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/auth/submit_fields_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_create_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_create_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_curl_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_curl_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_delete_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_list_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_list_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_load_extensions_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_persistence.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_persistence_param.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_pool.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_pool_acquire_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_pool_acquire_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_pool_create_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_pool_delete_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_pool_list_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_pool_ref.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_pool_release_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_pool_update_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_retrieve_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_retrieve_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_update_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_update_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browser_usage.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/computer_batch_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/computer_capture_screenshot_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/computer_click_mouse_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/computer_drag_mouse_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/computer_get_mouse_position_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/computer_move_mouse_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/computer_press_key_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/computer_read_clipboard_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/computer_scroll_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/computer_set_cursor_visibility_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/computer_set_cursor_visibility_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/computer_type_text_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/computer_write_clipboard_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/f_create_directory_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/f_delete_directory_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/f_delete_file_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/f_download_dir_zip_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/f_file_info_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/f_file_info_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/f_list_files_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/f_list_files_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/f_move_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/f_read_file_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/f_set_file_permissions_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/f_upload_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/f_upload_zip_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/f_write_file_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/fs/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/fs/watch_events_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/fs/watch_start_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/fs/watch_start_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/log_stream_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/playwright_execute_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/playwright_execute_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/process_exec_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/process_exec_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/process_kill_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/process_kill_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/process_resize_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/process_resize_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/process_spawn_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/process_spawn_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/process_status_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/process_stdin_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/process_stdin_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/process_stdout_stream_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/replay_list_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/replay_start_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/browsers/replay_start_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/credential.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/credential_create_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/credential_list_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/credential_provider.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/credential_provider_create_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/credential_provider_item.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/credential_provider_list_items_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/credential_provider_list_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/credential_provider_test_result.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/credential_provider_update_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/credential_totp_code_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/credential_update_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/deployment_create_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/deployment_create_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/deployment_follow_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/deployment_follow_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/deployment_list_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/deployment_list_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/deployment_retrieve_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/deployment_state_event.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/extension_download_from_chrome_store_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/extension_list_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/extension_upload_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/extension_upload_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/invocation_create_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/invocation_create_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/invocation_follow_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/invocation_follow_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/invocation_list_browsers_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/invocation_list_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/invocation_list_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/invocation_retrieve_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/invocation_state_event.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/invocation_update_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/invocation_update_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/profile.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/profile_create_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/profile_list_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/project.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/project_create_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/project_list_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/project_update_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/projects/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/projects/limit_update_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/projects/project_limits.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/proxy_check_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/proxy_check_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/proxy_create_params.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/proxy_create_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/proxy_list_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/proxy_retrieve_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/shared/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/shared/app_action.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/shared/browser_extension.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/shared/browser_profile.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/shared/browser_viewport.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/shared/error_detail.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/shared/error_event.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/shared/error_model.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/shared/heartbeat_event.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/shared/log_event.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/shared_params/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/shared_params/browser_extension.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/shared_params/browser_profile.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/src/kernel/types/shared_params/browser_viewport.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/auth/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/auth/test_connections.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/browsers/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/browsers/fs/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/browsers/fs/test_watch.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/browsers/test_computer.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/browsers/test_fs.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/browsers/test_logs.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/browsers/test_playwright.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/browsers/test_process.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/browsers/test_replays.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/projects/__init__.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/projects/test_limits.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/test_apps.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/test_browser_pools.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/test_browsers.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/test_credential_providers.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/test_credentials.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/test_deployments.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/test_extensions.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/test_invocations.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/test_profiles.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/test_projects.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/api_resources/test_proxies.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/conftest.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/sample_file.txt +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/test_client.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/test_models.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/test_qs.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/test_required_args.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/test_response.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/test_streaming.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/test_transform.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/test_utils/test_datetime_parse.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/test_utils/test_json.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/test_utils/test_path.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/test_utils/test_proxy.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/test_utils/test_typing.py +0 -0
- {kernel-0.50.0 → kernel-0.52.0}/tests/utils.py +0 -0
|
@@ -1,5 +1,76 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.52.0 (2026-04-29)
|
|
4
|
+
|
|
5
|
+
Full Changelog: [v0.51.0...v0.52.0](https://github.com/kernel/kernel-python-sdk/compare/v0.51.0...v0.52.0)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* profile download: 409 for empty profile + surface API errors in dashboard ([fd0c20e](https://github.com/kernel/kernel-python-sdk/commit/fd0c20eb17f0a6df382672c34830a81fac9217d9))
|
|
10
|
+
* support setting headers via env ([37dda88](https://github.com/kernel/kernel-python-sdk/commit/37dda88a1f88fdf4bd8da615cbb6be1aadae3f41))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* use correct field name format for multipart file arrays ([663f0a8](https://github.com/kernel/kernel-python-sdk/commit/663f0a8a633fd5b0f5f8b65ed169c4d780251e1d))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Documentation
|
|
19
|
+
|
|
20
|
+
* annotate response with httpx.Response in browser routing example ([0dfa1fb](https://github.com/kernel/kernel-python-sdk/commit/0dfa1fb978da1c4fd474840ae8664f027e1feb39))
|
|
21
|
+
* print buffered body and mention httpx.Response semantics ([84cb2e3](https://github.com/kernel/kernel-python-sdk/commit/84cb2e38486f330635487ed049d692f7c9716a1f))
|
|
22
|
+
* show both raw streaming and buffered curl in routing example ([407e748](https://github.com/kernel/kernel-python-sdk/commit/407e74862f99db13320ea6c02a8752759d4de60a))
|
|
23
|
+
* simplify browser routing example ([58b0ee2](https://github.com/kernel/kernel-python-sdk/commit/58b0ee27cdac1f4021c6e333f8157318c838ec56))
|
|
24
|
+
|
|
25
|
+
## 0.51.0 (2026-04-25)
|
|
26
|
+
|
|
27
|
+
Full Changelog: [v0.50.0...v0.51.0](https://github.com/kernel/kernel-python-sdk/compare/v0.50.0...v0.51.0)
|
|
28
|
+
|
|
29
|
+
### Features
|
|
30
|
+
|
|
31
|
+
* add browser-scoped session client ([7ca6887](https://github.com/kernel/kernel-python-sdk/commit/7ca68877e7011bb83862b7cc810a20d8254ea7dd))
|
|
32
|
+
* Expire stuck IN_PROGRESS managed auth sessions via background worker ([7781a3b](https://github.com/kernel/kernel-python-sdk/commit/7781a3b4635ded02dea60adf85878f50f7b7fb27))
|
|
33
|
+
* Expose browser_session_id on managed auth connection ([0ccb507](https://github.com/kernel/kernel-python-sdk/commit/0ccb50744032b4c31e0575fa7b06fb20503c8f55))
|
|
34
|
+
* generate browser-scoped resource bindings ([53b17c8](https://github.com/kernel/kernel-python-sdk/commit/53b17c8241cc71261d1e96f5929cbd4f05b2064b))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
### Bug Fixes
|
|
38
|
+
|
|
39
|
+
* address python browser routing ci follow-ups ([9690923](https://github.com/kernel/kernel-python-sdk/commit/9690923666cfe07de76267eee050d7743a8bad6f))
|
|
40
|
+
* evict deleted browser routes ([a873a18](https://github.com/kernel/kernel-python-sdk/commit/a873a18eba3f36937dc177ab981372e395722f8b))
|
|
41
|
+
* finish python browser routing cleanup ([694907a](https://github.com/kernel/kernel-python-sdk/commit/694907ab3419477e7058b85a7365ac4cce941105))
|
|
42
|
+
* normalize browser route cache session IDs ([f4c247b](https://github.com/kernel/kernel-python-sdk/commit/f4c247b425680b54d0ce3c7738fb82313bca7918))
|
|
43
|
+
* normalize python browser request string bodies ([3ce80e7](https://github.com/kernel/kernel-python-sdk/commit/3ce80e767d373b638ba1c2959bf18bf999629db0))
|
|
44
|
+
* quiet generator-script pyright noise ([0bdf85e](https://github.com/kernel/kernel-python-sdk/commit/0bdf85e0c38d4813056b61599273e88c7a64713a))
|
|
45
|
+
* reserve internal browser request query params ([b2c7aac](https://github.com/kernel/kernel-python-sdk/commit/b2c7aacac09a1bb7680cf493e9985438b169286c))
|
|
46
|
+
* satisfy browser-scoped lint checks ([8e8dde2](https://github.com/kernel/kernel-python-sdk/commit/8e8dde241c8817944baaacd155fe196f200868e8))
|
|
47
|
+
* satisfy generated browser-scoped type checks ([b410245](https://github.com/kernel/kernel-python-sdk/commit/b410245e1ad4bf8e29c17c59a5931654567b141f))
|
|
48
|
+
* sniff browser pool route cache updates ([5328730](https://github.com/kernel/kernel-python-sdk/commit/532873072f0400029768d1b7cf54b9fb1428ada9))
|
|
49
|
+
* type-check browser-scoped helpers ([cfff5b4](https://github.com/kernel/kernel-python-sdk/commit/cfff5b4c3635d327dd1ac0779d4e17e395efbec0))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
### Chores
|
|
53
|
+
|
|
54
|
+
* fix browser-scoped test import order ([fc34859](https://github.com/kernel/kernel-python-sdk/commit/fc34859c4f60f84038b425d9930c512e58134dea))
|
|
55
|
+
* **internal:** more robust bootstrap script ([6c9cdf3](https://github.com/kernel/kernel-python-sdk/commit/6c9cdf3ce828fab358c7e060f4e3313408cad257))
|
|
56
|
+
* keep browser-scoped generator lint clean ([a80716b](https://github.com/kernel/kernel-python-sdk/commit/a80716b791bf1f707aa7869290c47caefb0d9e27))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
### Documentation
|
|
60
|
+
|
|
61
|
+
* flesh out browser-scoped example ([ca5d188](https://github.com/kernel/kernel-python-sdk/commit/ca5d1884b590634df5623945e9585e0a66228ec3))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
### Refactors
|
|
65
|
+
|
|
66
|
+
* clean up python browser routing diff ([622f844](https://github.com/kernel/kernel-python-sdk/commit/622f8448a8a32f00b41d6e4890bfaf0a9374bd3e))
|
|
67
|
+
* drop browser-scoped wrapper clients ([dba503e](https://github.com/kernel/kernel-python-sdk/commit/dba503e832d54aa8d462d3d74b3027f8a9e865b6))
|
|
68
|
+
* inline browser resource passthrough returns ([02a2f59](https://github.com/kernel/kernel-python-sdk/commit/02a2f595c7e76ae7f0cea2ec1e88075df3a25be1))
|
|
69
|
+
* move python browser routing rollout to env ([0647d5c](https://github.com/kernel/kernel-python-sdk/commit/0647d5cab166e680bcb3436d1b502c3215492400))
|
|
70
|
+
* rename browser routing subresources config ([3ae9dab](https://github.com/kernel/kernel-python-sdk/commit/3ae9dab6b841e6f1191cdde073e36696f97feb39))
|
|
71
|
+
* simplify browser routing cache ([de0476f](https://github.com/kernel/kernel-python-sdk/commit/de0476fc043df48a58dd4067bb4b3c0fe7a83f0e))
|
|
72
|
+
* sniff browser routes in response hooks ([563de7d](https://github.com/kernel/kernel-python-sdk/commit/563de7d0ac8f141320edb060b4671935808e473a))
|
|
73
|
+
|
|
3
74
|
## 0.50.0 (2026-04-20)
|
|
4
75
|
|
|
5
76
|
Full Changelog: [v0.49.0...v0.50.0](https://github.com/kernel/kernel-python-sdk/compare/v0.49.0...v0.50.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: kernel
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.52.0
|
|
4
4
|
Summary: The official Python library for the kernel API
|
|
5
5
|
Project-URL: Homepage, https://github.com/kernel/kernel-python-sdk
|
|
6
6
|
Project-URL: Repository, https://github.com/kernel/kernel-python-sdk
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Example: direct-to-VM browser routing for raw HTTP."""
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
|
|
5
|
+
from kernel import Kernel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def main() -> None:
|
|
9
|
+
client = Kernel()
|
|
10
|
+
|
|
11
|
+
browser = client.browsers.create()
|
|
12
|
+
|
|
13
|
+
# Raw browser curl: streams the response. Use for large responses, when you want to stream,
|
|
14
|
+
# or when you want httpx.Response semantics.
|
|
15
|
+
response: httpx.Response = client.browsers.request(browser.session_id, "GET", "https://example.com")
|
|
16
|
+
print("status", response.status_code)
|
|
17
|
+
|
|
18
|
+
# Buffered browser curl: returns the full response in a JSON envelope. Use for small responses.
|
|
19
|
+
buffered = client.browsers.curl(browser.session_id, url="https://example.com", method="GET")
|
|
20
|
+
print("body", buffered.body)
|
|
21
|
+
|
|
22
|
+
client.browsers.delete_by_id(browser.session_id)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
if __name__ == "__main__":
|
|
26
|
+
main()
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
-
from typing import TYPE_CHECKING, Any, Dict, Mapping, cast
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Dict, Type, Mapping, cast
|
|
7
7
|
from typing_extensions import Self, Literal, override
|
|
8
8
|
|
|
9
9
|
import httpx
|
|
@@ -14,13 +14,19 @@ from ._types import (
|
|
|
14
14
|
Omit,
|
|
15
15
|
Timeout,
|
|
16
16
|
NotGiven,
|
|
17
|
+
ResponseT,
|
|
17
18
|
Transport,
|
|
18
19
|
ProxiesTypes,
|
|
19
20
|
RequestOptions,
|
|
20
21
|
not_given,
|
|
21
22
|
)
|
|
22
|
-
from ._utils import
|
|
23
|
+
from ._utils import (
|
|
24
|
+
is_given,
|
|
25
|
+
is_mapping_t,
|
|
26
|
+
get_async_library,
|
|
27
|
+
)
|
|
23
28
|
from ._compat import cached_property
|
|
29
|
+
from ._models import FinalRequestOptions
|
|
24
30
|
from ._version import __version__
|
|
25
31
|
from ._streaming import Stream as Stream, AsyncStream as AsyncStream
|
|
26
32
|
from ._exceptions import KernelError, APIStatusError
|
|
@@ -29,6 +35,15 @@ from ._base_client import (
|
|
|
29
35
|
SyncAPIClient,
|
|
30
36
|
AsyncAPIClient,
|
|
31
37
|
)
|
|
38
|
+
from .lib.browser_routing.routing import (
|
|
39
|
+
BrowserRouteCache,
|
|
40
|
+
BrowserRoutingConfig,
|
|
41
|
+
strip_direct_vm_auth,
|
|
42
|
+
rewrite_direct_vm_options,
|
|
43
|
+
browser_routing_config_from_env,
|
|
44
|
+
maybe_evict_browser_route_from_response,
|
|
45
|
+
maybe_populate_browser_route_cache_from_response,
|
|
46
|
+
)
|
|
32
47
|
|
|
33
48
|
if TYPE_CHECKING:
|
|
34
49
|
from .resources import (
|
|
@@ -79,8 +94,10 @@ ENVIRONMENTS: Dict[str, str] = {
|
|
|
79
94
|
class Kernel(SyncAPIClient):
|
|
80
95
|
# client options
|
|
81
96
|
api_key: str
|
|
97
|
+
browser_route_cache: BrowserRouteCache
|
|
82
98
|
|
|
83
99
|
_environment: Literal["production", "development"] | NotGiven
|
|
100
|
+
_browser_routing: BrowserRoutingConfig
|
|
84
101
|
|
|
85
102
|
def __init__(
|
|
86
103
|
self,
|
|
@@ -105,6 +122,7 @@ class Kernel(SyncAPIClient):
|
|
|
105
122
|
# outlining your use-case to help us decide if it should be
|
|
106
123
|
# part of our public interface in the future.
|
|
107
124
|
_strict_response_validation: bool = False,
|
|
125
|
+
_browser_route_cache: BrowserRouteCache | None = None,
|
|
108
126
|
) -> None:
|
|
109
127
|
"""Construct a new synchronous Kernel client instance.
|
|
110
128
|
|
|
@@ -144,6 +162,15 @@ class Kernel(SyncAPIClient):
|
|
|
144
162
|
except KeyError as exc:
|
|
145
163
|
raise ValueError(f"Unknown environment: {environment}") from exc
|
|
146
164
|
|
|
165
|
+
custom_headers_env = os.environ.get("KERNEL_CUSTOM_HEADERS")
|
|
166
|
+
if custom_headers_env is not None:
|
|
167
|
+
parsed: dict[str, str] = {}
|
|
168
|
+
for line in custom_headers_env.split("\n"):
|
|
169
|
+
colon = line.find(":")
|
|
170
|
+
if colon >= 0:
|
|
171
|
+
parsed[line[:colon].strip()] = line[colon + 1 :].strip()
|
|
172
|
+
default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})}
|
|
173
|
+
|
|
147
174
|
super().__init__(
|
|
148
175
|
version=__version__,
|
|
149
176
|
base_url=base_url,
|
|
@@ -154,6 +181,8 @@ class Kernel(SyncAPIClient):
|
|
|
154
181
|
custom_query=default_query,
|
|
155
182
|
_strict_response_validation=_strict_response_validation,
|
|
156
183
|
)
|
|
184
|
+
self.browser_route_cache = _browser_route_cache or BrowserRouteCache()
|
|
185
|
+
self._browser_routing = browser_routing_config_from_env()
|
|
157
186
|
|
|
158
187
|
@cached_property
|
|
159
188
|
def deployments(self) -> DeploymentsResource:
|
|
@@ -266,6 +295,37 @@ class Kernel(SyncAPIClient):
|
|
|
266
295
|
**self._custom_headers,
|
|
267
296
|
}
|
|
268
297
|
|
|
298
|
+
@override
|
|
299
|
+
def _prepare_options(self, options: Any) -> Any:
|
|
300
|
+
options = cast(Any, super()._prepare_options(options))
|
|
301
|
+
return rewrite_direct_vm_options(options, cache=self.browser_route_cache, config=self._browser_routing)
|
|
302
|
+
|
|
303
|
+
@override
|
|
304
|
+
def _prepare_request(self, request: httpx.Request) -> None:
|
|
305
|
+
strip_direct_vm_auth(request, cache=self.browser_route_cache)
|
|
306
|
+
|
|
307
|
+
@override
|
|
308
|
+
def _process_response(
|
|
309
|
+
self,
|
|
310
|
+
*,
|
|
311
|
+
cast_to: Type[ResponseT],
|
|
312
|
+
options: FinalRequestOptions,
|
|
313
|
+
response: httpx.Response,
|
|
314
|
+
stream: bool,
|
|
315
|
+
stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None,
|
|
316
|
+
retries_taken: int = 0,
|
|
317
|
+
) -> ResponseT:
|
|
318
|
+
maybe_populate_browser_route_cache_from_response(response, cache=self.browser_route_cache)
|
|
319
|
+
maybe_evict_browser_route_from_response(response, cache=self.browser_route_cache)
|
|
320
|
+
return super()._process_response(
|
|
321
|
+
cast_to=cast_to,
|
|
322
|
+
options=options,
|
|
323
|
+
response=response,
|
|
324
|
+
stream=stream,
|
|
325
|
+
stream_cls=stream_cls,
|
|
326
|
+
retries_taken=retries_taken,
|
|
327
|
+
)
|
|
328
|
+
|
|
269
329
|
def copy(
|
|
270
330
|
self,
|
|
271
331
|
*,
|
|
@@ -279,6 +339,7 @@ class Kernel(SyncAPIClient):
|
|
|
279
339
|
set_default_headers: Mapping[str, str] | None = None,
|
|
280
340
|
default_query: Mapping[str, object] | None = None,
|
|
281
341
|
set_default_query: Mapping[str, object] | None = None,
|
|
342
|
+
_browser_route_cache: BrowserRouteCache | None = None,
|
|
282
343
|
_extra_kwargs: Mapping[str, Any] = {},
|
|
283
344
|
) -> Self:
|
|
284
345
|
"""
|
|
@@ -312,6 +373,7 @@ class Kernel(SyncAPIClient):
|
|
|
312
373
|
max_retries=max_retries if is_given(max_retries) else self.max_retries,
|
|
313
374
|
default_headers=headers,
|
|
314
375
|
default_query=params,
|
|
376
|
+
_browser_route_cache=_browser_route_cache or self.browser_route_cache,
|
|
315
377
|
**_extra_kwargs,
|
|
316
378
|
)
|
|
317
379
|
|
|
@@ -356,8 +418,10 @@ class Kernel(SyncAPIClient):
|
|
|
356
418
|
class AsyncKernel(AsyncAPIClient):
|
|
357
419
|
# client options
|
|
358
420
|
api_key: str
|
|
421
|
+
browser_route_cache: BrowserRouteCache
|
|
359
422
|
|
|
360
423
|
_environment: Literal["production", "development"] | NotGiven
|
|
424
|
+
_browser_routing: BrowserRoutingConfig
|
|
361
425
|
|
|
362
426
|
def __init__(
|
|
363
427
|
self,
|
|
@@ -382,6 +446,7 @@ class AsyncKernel(AsyncAPIClient):
|
|
|
382
446
|
# outlining your use-case to help us decide if it should be
|
|
383
447
|
# part of our public interface in the future.
|
|
384
448
|
_strict_response_validation: bool = False,
|
|
449
|
+
_browser_route_cache: BrowserRouteCache | None = None,
|
|
385
450
|
) -> None:
|
|
386
451
|
"""Construct a new async AsyncKernel client instance.
|
|
387
452
|
|
|
@@ -421,6 +486,15 @@ class AsyncKernel(AsyncAPIClient):
|
|
|
421
486
|
except KeyError as exc:
|
|
422
487
|
raise ValueError(f"Unknown environment: {environment}") from exc
|
|
423
488
|
|
|
489
|
+
custom_headers_env = os.environ.get("KERNEL_CUSTOM_HEADERS")
|
|
490
|
+
if custom_headers_env is not None:
|
|
491
|
+
parsed: dict[str, str] = {}
|
|
492
|
+
for line in custom_headers_env.split("\n"):
|
|
493
|
+
colon = line.find(":")
|
|
494
|
+
if colon >= 0:
|
|
495
|
+
parsed[line[:colon].strip()] = line[colon + 1 :].strip()
|
|
496
|
+
default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})}
|
|
497
|
+
|
|
424
498
|
super().__init__(
|
|
425
499
|
version=__version__,
|
|
426
500
|
base_url=base_url,
|
|
@@ -431,6 +505,8 @@ class AsyncKernel(AsyncAPIClient):
|
|
|
431
505
|
custom_query=default_query,
|
|
432
506
|
_strict_response_validation=_strict_response_validation,
|
|
433
507
|
)
|
|
508
|
+
self.browser_route_cache = _browser_route_cache or BrowserRouteCache()
|
|
509
|
+
self._browser_routing = browser_routing_config_from_env()
|
|
434
510
|
|
|
435
511
|
@cached_property
|
|
436
512
|
def deployments(self) -> AsyncDeploymentsResource:
|
|
@@ -543,6 +619,37 @@ class AsyncKernel(AsyncAPIClient):
|
|
|
543
619
|
**self._custom_headers,
|
|
544
620
|
}
|
|
545
621
|
|
|
622
|
+
@override
|
|
623
|
+
async def _prepare_options(self, options: Any) -> Any:
|
|
624
|
+
options = cast(Any, await super()._prepare_options(options))
|
|
625
|
+
return rewrite_direct_vm_options(options, cache=self.browser_route_cache, config=self._browser_routing)
|
|
626
|
+
|
|
627
|
+
@override
|
|
628
|
+
async def _prepare_request(self, request: httpx.Request) -> None:
|
|
629
|
+
strip_direct_vm_auth(request, cache=self.browser_route_cache)
|
|
630
|
+
|
|
631
|
+
@override
|
|
632
|
+
async def _process_response(
|
|
633
|
+
self,
|
|
634
|
+
*,
|
|
635
|
+
cast_to: Type[ResponseT],
|
|
636
|
+
options: FinalRequestOptions,
|
|
637
|
+
response: httpx.Response,
|
|
638
|
+
stream: bool,
|
|
639
|
+
stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None,
|
|
640
|
+
retries_taken: int = 0,
|
|
641
|
+
) -> ResponseT:
|
|
642
|
+
maybe_populate_browser_route_cache_from_response(response, cache=self.browser_route_cache)
|
|
643
|
+
maybe_evict_browser_route_from_response(response, cache=self.browser_route_cache)
|
|
644
|
+
return await super()._process_response(
|
|
645
|
+
cast_to=cast_to,
|
|
646
|
+
options=options,
|
|
647
|
+
response=response,
|
|
648
|
+
stream=stream,
|
|
649
|
+
stream_cls=stream_cls,
|
|
650
|
+
retries_taken=retries_taken,
|
|
651
|
+
)
|
|
652
|
+
|
|
546
653
|
def copy(
|
|
547
654
|
self,
|
|
548
655
|
*,
|
|
@@ -556,6 +663,7 @@ class AsyncKernel(AsyncAPIClient):
|
|
|
556
663
|
set_default_headers: Mapping[str, str] | None = None,
|
|
557
664
|
default_query: Mapping[str, object] | None = None,
|
|
558
665
|
set_default_query: Mapping[str, object] | None = None,
|
|
666
|
+
_browser_route_cache: BrowserRouteCache | None = None,
|
|
559
667
|
_extra_kwargs: Mapping[str, Any] = {},
|
|
560
668
|
) -> Self:
|
|
561
669
|
"""
|
|
@@ -589,6 +697,7 @@ class AsyncKernel(AsyncAPIClient):
|
|
|
589
697
|
max_retries=max_retries if is_given(max_retries) else self.max_retries,
|
|
590
698
|
default_headers=headers,
|
|
591
699
|
default_query=params,
|
|
700
|
+
_browser_route_cache=_browser_route_cache or self.browser_route_cache,
|
|
592
701
|
**_extra_kwargs,
|
|
593
702
|
)
|
|
594
703
|
|
|
@@ -2,17 +2,13 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import Any, List, Tuple, Union, Mapping, TypeVar
|
|
4
4
|
from urllib.parse import parse_qs, urlencode
|
|
5
|
-
from typing_extensions import
|
|
5
|
+
from typing_extensions import get_args
|
|
6
6
|
|
|
7
|
-
from ._types import NotGiven, not_given
|
|
7
|
+
from ._types import NotGiven, ArrayFormat, NestedFormat, not_given
|
|
8
8
|
from ._utils import flatten
|
|
9
9
|
|
|
10
10
|
_T = TypeVar("_T")
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
ArrayFormat = Literal["comma", "repeat", "indices", "brackets"]
|
|
14
|
-
NestedFormat = Literal["dots", "brackets"]
|
|
15
|
-
|
|
16
12
|
PrimitiveData = Union[str, int, float, bool, None]
|
|
17
13
|
# this should be Data = Union[PrimitiveData, "List[Data]", "Tuple[Data]", "Mapping[str, Data]"]
|
|
18
14
|
# https://github.com/microsoft/pyright/issues/3555
|
|
@@ -47,6 +47,9 @@ AnyMapping = Mapping[str, object]
|
|
|
47
47
|
ModelT = TypeVar("ModelT", bound=pydantic.BaseModel)
|
|
48
48
|
_T = TypeVar("_T")
|
|
49
49
|
|
|
50
|
+
ArrayFormat = Literal["comma", "repeat", "indices", "brackets"]
|
|
51
|
+
NestedFormat = Literal["dots", "brackets"]
|
|
52
|
+
|
|
50
53
|
|
|
51
54
|
# Approximates httpx internal ProxiesTypes and RequestFiles types
|
|
52
55
|
# while adding support for `PathLike` instances
|
|
@@ -17,11 +17,11 @@ from typing import (
|
|
|
17
17
|
)
|
|
18
18
|
from pathlib import Path
|
|
19
19
|
from datetime import date, datetime
|
|
20
|
-
from typing_extensions import TypeGuard
|
|
20
|
+
from typing_extensions import TypeGuard, get_args
|
|
21
21
|
|
|
22
22
|
import sniffio
|
|
23
23
|
|
|
24
|
-
from .._types import Omit, NotGiven, FileTypes, HeadersLike
|
|
24
|
+
from .._types import Omit, NotGiven, FileTypes, ArrayFormat, HeadersLike
|
|
25
25
|
|
|
26
26
|
_T = TypeVar("_T")
|
|
27
27
|
_TupleT = TypeVar("_TupleT", bound=Tuple[object, ...])
|
|
@@ -40,25 +40,45 @@ def extract_files(
|
|
|
40
40
|
query: Mapping[str, object],
|
|
41
41
|
*,
|
|
42
42
|
paths: Sequence[Sequence[str]],
|
|
43
|
+
array_format: ArrayFormat = "brackets",
|
|
43
44
|
) -> list[tuple[str, FileTypes]]:
|
|
44
45
|
"""Recursively extract files from the given dictionary based on specified paths.
|
|
45
46
|
|
|
46
47
|
A path may look like this ['foo', 'files', '<array>', 'data'].
|
|
47
48
|
|
|
49
|
+
``array_format`` controls how ``<array>`` segments contribute to the emitted
|
|
50
|
+
field name. Supported values: ``"brackets"`` (``foo[]``), ``"repeat"`` and
|
|
51
|
+
``"comma"`` (``foo``), ``"indices"`` (``foo[0]``, ``foo[1]``).
|
|
52
|
+
|
|
48
53
|
Note: this mutates the given dictionary.
|
|
49
54
|
"""
|
|
50
55
|
files: list[tuple[str, FileTypes]] = []
|
|
51
56
|
for path in paths:
|
|
52
|
-
files.extend(_extract_items(query, path, index=0, flattened_key=None))
|
|
57
|
+
files.extend(_extract_items(query, path, index=0, flattened_key=None, array_format=array_format))
|
|
53
58
|
return files
|
|
54
59
|
|
|
55
60
|
|
|
61
|
+
def _array_suffix(array_format: ArrayFormat, array_index: int) -> str:
|
|
62
|
+
if array_format == "brackets":
|
|
63
|
+
return "[]"
|
|
64
|
+
if array_format == "indices":
|
|
65
|
+
return f"[{array_index}]"
|
|
66
|
+
if array_format == "repeat" or array_format == "comma":
|
|
67
|
+
# Both repeat the bare field name for each file part; there is no
|
|
68
|
+
# meaningful way to comma-join binary parts.
|
|
69
|
+
return ""
|
|
70
|
+
raise NotImplementedError(
|
|
71
|
+
f"Unknown array_format value: {array_format}, choose from {', '.join(get_args(ArrayFormat))}"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
56
75
|
def _extract_items(
|
|
57
76
|
obj: object,
|
|
58
77
|
path: Sequence[str],
|
|
59
78
|
*,
|
|
60
79
|
index: int,
|
|
61
80
|
flattened_key: str | None,
|
|
81
|
+
array_format: ArrayFormat,
|
|
62
82
|
) -> list[tuple[str, FileTypes]]:
|
|
63
83
|
try:
|
|
64
84
|
key = path[index]
|
|
@@ -75,9 +95,11 @@ def _extract_items(
|
|
|
75
95
|
|
|
76
96
|
if is_list(obj):
|
|
77
97
|
files: list[tuple[str, FileTypes]] = []
|
|
78
|
-
for entry in obj:
|
|
79
|
-
|
|
80
|
-
|
|
98
|
+
for array_index, entry in enumerate(obj):
|
|
99
|
+
suffix = _array_suffix(array_format, array_index)
|
|
100
|
+
emitted_key = (flattened_key + suffix) if flattened_key else suffix
|
|
101
|
+
assert_is_file_content(entry, key=emitted_key)
|
|
102
|
+
files.append((emitted_key, cast(FileTypes, entry)))
|
|
81
103
|
return files
|
|
82
104
|
|
|
83
105
|
assert_is_file_content(obj, key=flattened_key)
|
|
@@ -106,6 +128,7 @@ def _extract_items(
|
|
|
106
128
|
path,
|
|
107
129
|
index=index,
|
|
108
130
|
flattened_key=flattened_key,
|
|
131
|
+
array_format=array_format,
|
|
109
132
|
)
|
|
110
133
|
elif is_list(obj):
|
|
111
134
|
if key != "<array>":
|
|
@@ -117,9 +140,12 @@ def _extract_items(
|
|
|
117
140
|
item,
|
|
118
141
|
path,
|
|
119
142
|
index=index,
|
|
120
|
-
flattened_key=
|
|
143
|
+
flattened_key=(
|
|
144
|
+
(flattened_key if flattened_key is not None else "") + _array_suffix(array_format, array_index)
|
|
145
|
+
),
|
|
146
|
+
array_format=array_format,
|
|
121
147
|
)
|
|
122
|
-
for item in obj
|
|
148
|
+
for array_index, item in enumerate(obj)
|
|
123
149
|
]
|
|
124
150
|
)
|
|
125
151
|
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import IO, Any, Union, Mapping, cast
|
|
4
|
+
from contextlib import contextmanager, asynccontextmanager
|
|
5
|
+
from collections.abc import Iterable, Iterator, AsyncIterator
|
|
6
|
+
|
|
7
|
+
import httpx
|
|
8
|
+
|
|
9
|
+
from .util import sanitize_curl_raw_params
|
|
10
|
+
from .routing import BrowserRoute
|
|
11
|
+
from ..._types import Body, Timeout, NotGiven, not_given
|
|
12
|
+
from ..._models import FinalRequestOptions
|
|
13
|
+
|
|
14
|
+
BrowserRawContent = Union[bytes, bytearray, memoryview, str, IO[bytes], Iterable[bytes]]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def request_via_browser_route(
|
|
18
|
+
parent: Any,
|
|
19
|
+
route: BrowserRoute,
|
|
20
|
+
method: str,
|
|
21
|
+
url: str,
|
|
22
|
+
*,
|
|
23
|
+
content: BrowserRawContent | None = None,
|
|
24
|
+
json: Body | None = None,
|
|
25
|
+
headers: Mapping[str, str] | None = None,
|
|
26
|
+
params: Mapping[str, object] | None = None,
|
|
27
|
+
timeout: float | Timeout | None | NotGiven = not_given,
|
|
28
|
+
) -> httpx.Response:
|
|
29
|
+
if json is not None and content is not None:
|
|
30
|
+
raise TypeError("Passing both `json` and `content` is not supported")
|
|
31
|
+
query: dict[str, object] = {**sanitize_curl_raw_params(params), "url": url, "jwt": route.jwt}
|
|
32
|
+
options = FinalRequestOptions.construct(
|
|
33
|
+
method=method.upper(),
|
|
34
|
+
url=route.base_url.rstrip("/") + "/curl/raw",
|
|
35
|
+
params=query,
|
|
36
|
+
headers=headers or {},
|
|
37
|
+
content=_normalize_binary_content(content),
|
|
38
|
+
json_data=json,
|
|
39
|
+
timeout=_normalize_timeout(timeout),
|
|
40
|
+
)
|
|
41
|
+
return cast(httpx.Response, parent.request(httpx.Response, options))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@contextmanager
|
|
45
|
+
def stream_via_browser_route(
|
|
46
|
+
parent: Any,
|
|
47
|
+
route: BrowserRoute,
|
|
48
|
+
method: str,
|
|
49
|
+
url: str,
|
|
50
|
+
*,
|
|
51
|
+
content: BrowserRawContent | None = None,
|
|
52
|
+
headers: Mapping[str, str] | None = None,
|
|
53
|
+
params: Mapping[str, object] | None = None,
|
|
54
|
+
timeout: float | Timeout | None | NotGiven = not_given,
|
|
55
|
+
) -> Iterator[httpx.Response]:
|
|
56
|
+
query: dict[str, Any] = sanitize_curl_raw_params(params)
|
|
57
|
+
query["jwt"] = route.jwt
|
|
58
|
+
query["url"] = url
|
|
59
|
+
request_headers = {k: v for k, v in parent.default_headers.items() if isinstance(v, str)}
|
|
60
|
+
if content is None:
|
|
61
|
+
request_headers.pop("Content-Type", None)
|
|
62
|
+
if headers:
|
|
63
|
+
request_headers.update(headers)
|
|
64
|
+
request_headers.pop("Authorization", None)
|
|
65
|
+
effective_timeout = parent.timeout if isinstance(timeout, NotGiven) else timeout
|
|
66
|
+
with parent._client.stream(
|
|
67
|
+
method.upper(),
|
|
68
|
+
route.base_url.rstrip("/") + "/curl/raw",
|
|
69
|
+
params=query,
|
|
70
|
+
headers=request_headers,
|
|
71
|
+
content=_normalize_binary_content(content),
|
|
72
|
+
timeout=_normalize_timeout(effective_timeout),
|
|
73
|
+
) as response:
|
|
74
|
+
yield response
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
async def async_request_via_browser_route(
|
|
78
|
+
parent: Any,
|
|
79
|
+
route: BrowserRoute,
|
|
80
|
+
method: str,
|
|
81
|
+
url: str,
|
|
82
|
+
*,
|
|
83
|
+
content: BrowserRawContent | None = None,
|
|
84
|
+
json: Body | None = None,
|
|
85
|
+
headers: Mapping[str, str] | None = None,
|
|
86
|
+
params: Mapping[str, object] | None = None,
|
|
87
|
+
timeout: float | Timeout | None | NotGiven = not_given,
|
|
88
|
+
) -> httpx.Response:
|
|
89
|
+
if json is not None and content is not None:
|
|
90
|
+
raise TypeError("Passing both `json` and `content` is not supported")
|
|
91
|
+
query: dict[str, object] = {**sanitize_curl_raw_params(params), "url": url, "jwt": route.jwt}
|
|
92
|
+
options = FinalRequestOptions.construct(
|
|
93
|
+
method=method.upper(),
|
|
94
|
+
url=route.base_url.rstrip("/") + "/curl/raw",
|
|
95
|
+
params=query,
|
|
96
|
+
headers=headers or {},
|
|
97
|
+
content=_normalize_binary_content(content),
|
|
98
|
+
json_data=json,
|
|
99
|
+
timeout=_normalize_timeout(timeout),
|
|
100
|
+
)
|
|
101
|
+
return cast(httpx.Response, await parent.request(httpx.Response, options))
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@asynccontextmanager
|
|
105
|
+
async def async_stream_via_browser_route(
|
|
106
|
+
parent: Any,
|
|
107
|
+
route: BrowserRoute,
|
|
108
|
+
method: str,
|
|
109
|
+
url: str,
|
|
110
|
+
*,
|
|
111
|
+
content: BrowserRawContent | None = None,
|
|
112
|
+
headers: Mapping[str, str] | None = None,
|
|
113
|
+
params: Mapping[str, object] | None = None,
|
|
114
|
+
timeout: float | Timeout | None | NotGiven = not_given,
|
|
115
|
+
) -> AsyncIterator[httpx.Response]:
|
|
116
|
+
query: dict[str, Any] = sanitize_curl_raw_params(params)
|
|
117
|
+
query["jwt"] = route.jwt
|
|
118
|
+
query["url"] = url
|
|
119
|
+
request_headers = {k: v for k, v in parent.default_headers.items() if isinstance(v, str)}
|
|
120
|
+
if content is None:
|
|
121
|
+
request_headers.pop("Content-Type", None)
|
|
122
|
+
if headers:
|
|
123
|
+
request_headers.update(headers)
|
|
124
|
+
request_headers.pop("Authorization", None)
|
|
125
|
+
effective_timeout = parent.timeout if isinstance(timeout, NotGiven) else timeout
|
|
126
|
+
async with parent._client.stream(
|
|
127
|
+
method.upper(),
|
|
128
|
+
route.base_url.rstrip("/") + "/curl/raw",
|
|
129
|
+
params=query,
|
|
130
|
+
headers=request_headers,
|
|
131
|
+
content=_normalize_binary_content(content),
|
|
132
|
+
timeout=_normalize_timeout(effective_timeout),
|
|
133
|
+
) as response:
|
|
134
|
+
yield response
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _normalize_timeout(timeout: float | Timeout | None | NotGiven) -> float | Timeout | None:
|
|
138
|
+
return None if isinstance(timeout, NotGiven) else timeout
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _normalize_binary_content(content: BrowserRawContent | None) -> bytes | IO[bytes] | Iterable[bytes] | None:
|
|
142
|
+
if content is None:
|
|
143
|
+
return None
|
|
144
|
+
if isinstance(content, str):
|
|
145
|
+
return content.encode()
|
|
146
|
+
if isinstance(content, bytearray):
|
|
147
|
+
return bytes(content)
|
|
148
|
+
if isinstance(content, memoryview):
|
|
149
|
+
return content.tobytes()
|
|
150
|
+
return content
|