pybiolib 0.2.951__py3-none-any.whl → 1.2.1890__py3-none-any.whl
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.
- biolib/__init__.py +357 -11
- biolib/_data_record/data_record.py +380 -0
- biolib/_index/__init__.py +0 -0
- biolib/_index/index.py +55 -0
- biolib/_index/query_result.py +103 -0
- biolib/_internal/__init__.py +0 -0
- biolib/_internal/add_copilot_prompts.py +58 -0
- biolib/_internal/add_gui_files.py +81 -0
- biolib/_internal/data_record/__init__.py +1 -0
- biolib/_internal/data_record/data_record.py +85 -0
- biolib/_internal/data_record/push_data.py +116 -0
- biolib/_internal/data_record/remote_storage_endpoint.py +43 -0
- biolib/_internal/errors.py +5 -0
- biolib/_internal/file_utils.py +125 -0
- biolib/_internal/fuse_mount/__init__.py +1 -0
- biolib/_internal/fuse_mount/experiment_fuse_mount.py +209 -0
- biolib/_internal/http_client.py +159 -0
- biolib/_internal/lfs/__init__.py +1 -0
- biolib/_internal/lfs/cache.py +51 -0
- biolib/_internal/libs/__init__.py +1 -0
- biolib/_internal/libs/fusepy/__init__.py +1257 -0
- biolib/_internal/push_application.py +488 -0
- biolib/_internal/runtime.py +22 -0
- biolib/_internal/string_utils.py +13 -0
- biolib/_internal/templates/__init__.py +1 -0
- biolib/_internal/templates/copilot_template/.github/instructions/general-app-knowledge.instructions.md +10 -0
- biolib/_internal/templates/copilot_template/.github/instructions/style-general.instructions.md +20 -0
- biolib/_internal/templates/copilot_template/.github/instructions/style-python.instructions.md +16 -0
- biolib/_internal/templates/copilot_template/.github/instructions/style-react-ts.instructions.md +47 -0
- biolib/_internal/templates/copilot_template/.github/prompts/biolib_app_inputs.prompt.md +11 -0
- biolib/_internal/templates/copilot_template/.github/prompts/biolib_onboard_repo.prompt.md +19 -0
- biolib/_internal/templates/copilot_template/.github/prompts/biolib_run_apps.prompt.md +12 -0
- biolib/_internal/templates/dashboard_template/.biolib/config.yml +5 -0
- biolib/_internal/templates/github_workflow_template/.github/workflows/biolib.yml +21 -0
- biolib/_internal/templates/gitignore_template/.gitignore +10 -0
- biolib/_internal/templates/gui_template/.yarnrc.yml +1 -0
- biolib/_internal/templates/gui_template/App.tsx +53 -0
- biolib/_internal/templates/gui_template/Dockerfile +27 -0
- biolib/_internal/templates/gui_template/biolib-sdk.ts +82 -0
- biolib/_internal/templates/gui_template/dev-data/output.json +7 -0
- biolib/_internal/templates/gui_template/index.css +5 -0
- biolib/_internal/templates/gui_template/index.html +13 -0
- biolib/_internal/templates/gui_template/index.tsx +10 -0
- biolib/_internal/templates/gui_template/package.json +27 -0
- biolib/_internal/templates/gui_template/tsconfig.json +24 -0
- biolib/_internal/templates/gui_template/vite-plugin-dev-data.ts +50 -0
- biolib/_internal/templates/gui_template/vite.config.mts +10 -0
- biolib/_internal/templates/init_template/.biolib/config.yml +19 -0
- biolib/_internal/templates/init_template/Dockerfile +14 -0
- biolib/_internal/templates/init_template/requirements.txt +1 -0
- biolib/_internal/templates/init_template/run.py +12 -0
- biolib/_internal/templates/init_template/run.sh +4 -0
- biolib/_internal/templates/templates.py +25 -0
- biolib/_internal/tree_utils.py +106 -0
- biolib/_internal/utils/__init__.py +65 -0
- biolib/_internal/utils/auth.py +46 -0
- biolib/_internal/utils/job_url.py +33 -0
- biolib/_internal/utils/multinode.py +263 -0
- biolib/_runtime/runtime.py +157 -0
- biolib/_session/session.py +44 -0
- biolib/_shared/__init__.py +0 -0
- biolib/_shared/types/__init__.py +74 -0
- biolib/_shared/types/account.py +12 -0
- biolib/_shared/types/account_member.py +8 -0
- biolib/_shared/types/app.py +9 -0
- biolib/_shared/types/data_record.py +40 -0
- biolib/_shared/types/experiment.py +32 -0
- biolib/_shared/types/file_node.py +17 -0
- biolib/_shared/types/push.py +6 -0
- biolib/_shared/types/resource.py +37 -0
- biolib/_shared/types/resource_deploy_key.py +11 -0
- biolib/_shared/types/resource_permission.py +14 -0
- biolib/_shared/types/resource_version.py +19 -0
- biolib/_shared/types/result.py +14 -0
- biolib/_shared/types/typing.py +10 -0
- biolib/_shared/types/user.py +19 -0
- biolib/_shared/utils/__init__.py +7 -0
- biolib/_shared/utils/resource_uri.py +75 -0
- biolib/api/__init__.py +6 -0
- biolib/api/client.py +168 -0
- biolib/app/app.py +252 -49
- biolib/app/search_apps.py +45 -0
- biolib/biolib_api_client/api_client.py +126 -31
- biolib/biolib_api_client/app_types.py +24 -4
- biolib/biolib_api_client/auth.py +31 -8
- biolib/biolib_api_client/biolib_app_api.py +147 -52
- biolib/biolib_api_client/biolib_job_api.py +161 -141
- biolib/biolib_api_client/job_types.py +21 -5
- biolib/biolib_api_client/lfs_types.py +7 -23
- biolib/biolib_api_client/user_state.py +56 -0
- biolib/biolib_binary_format/__init__.py +1 -4
- biolib/biolib_binary_format/file_in_container.py +105 -0
- biolib/biolib_binary_format/module_input.py +24 -7
- biolib/biolib_binary_format/module_output_v2.py +149 -0
- biolib/biolib_binary_format/remote_endpoints.py +34 -0
- biolib/biolib_binary_format/remote_stream_seeker.py +59 -0
- biolib/biolib_binary_format/saved_job.py +3 -2
- biolib/biolib_binary_format/{attestation_document.py → stdout_and_stderr.py} +8 -8
- biolib/biolib_binary_format/system_status_update.py +3 -2
- biolib/biolib_binary_format/utils.py +175 -0
- biolib/biolib_docker_client/__init__.py +11 -2
- biolib/biolib_errors.py +36 -0
- biolib/biolib_logging.py +27 -10
- biolib/cli/__init__.py +38 -0
- biolib/cli/auth.py +46 -0
- biolib/cli/data_record.py +164 -0
- biolib/cli/index.py +32 -0
- biolib/cli/init.py +421 -0
- biolib/cli/lfs.py +101 -0
- biolib/cli/push.py +50 -0
- biolib/cli/run.py +63 -0
- biolib/cli/runtime.py +14 -0
- biolib/cli/sdk.py +16 -0
- biolib/cli/start.py +56 -0
- biolib/compute_node/cloud_utils/cloud_utils.py +110 -161
- biolib/compute_node/job_worker/cache_state.py +66 -88
- biolib/compute_node/job_worker/cache_types.py +1 -6
- biolib/compute_node/job_worker/docker_image_cache.py +112 -37
- biolib/compute_node/job_worker/executors/__init__.py +0 -3
- biolib/compute_node/job_worker/executors/docker_executor.py +532 -199
- biolib/compute_node/job_worker/executors/docker_types.py +9 -1
- biolib/compute_node/job_worker/executors/types.py +19 -9
- biolib/compute_node/job_worker/job_legacy_input_wait_timeout_thread.py +30 -0
- biolib/compute_node/job_worker/job_max_runtime_timer_thread.py +3 -5
- biolib/compute_node/job_worker/job_storage.py +108 -0
- biolib/compute_node/job_worker/job_worker.py +397 -212
- biolib/compute_node/job_worker/large_file_system.py +87 -38
- biolib/compute_node/job_worker/network_alloc.py +99 -0
- biolib/compute_node/job_worker/network_buffer.py +240 -0
- biolib/compute_node/job_worker/utilization_reporter_thread.py +197 -0
- biolib/compute_node/job_worker/utils.py +9 -24
- biolib/compute_node/remote_host_proxy.py +400 -98
- biolib/compute_node/utils.py +31 -9
- biolib/compute_node/webserver/compute_node_results_proxy.py +189 -0
- biolib/compute_node/webserver/proxy_utils.py +28 -0
- biolib/compute_node/webserver/webserver.py +130 -44
- biolib/compute_node/webserver/webserver_types.py +2 -6
- biolib/compute_node/webserver/webserver_utils.py +77 -12
- biolib/compute_node/webserver/worker_thread.py +183 -42
- biolib/experiments/__init__.py +0 -0
- biolib/experiments/experiment.py +356 -0
- biolib/jobs/__init__.py +1 -0
- biolib/jobs/job.py +741 -0
- biolib/jobs/job_result.py +185 -0
- biolib/jobs/types.py +50 -0
- biolib/py.typed +0 -0
- biolib/runtime/__init__.py +14 -0
- biolib/sdk/__init__.py +91 -0
- biolib/tables.py +34 -0
- biolib/typing_utils.py +2 -7
- biolib/user/__init__.py +1 -0
- biolib/user/sign_in.py +54 -0
- biolib/utils/__init__.py +162 -0
- biolib/utils/cache_state.py +94 -0
- biolib/utils/multipart_uploader.py +194 -0
- biolib/utils/seq_util.py +150 -0
- biolib/utils/zip/remote_zip.py +640 -0
- pybiolib-1.2.1890.dist-info/METADATA +41 -0
- pybiolib-1.2.1890.dist-info/RECORD +177 -0
- {pybiolib-0.2.951.dist-info → pybiolib-1.2.1890.dist-info}/WHEEL +1 -1
- pybiolib-1.2.1890.dist-info/entry_points.txt +2 -0
- README.md +0 -17
- biolib/app/app_result.py +0 -68
- biolib/app/utils.py +0 -62
- biolib/biolib-js/0-biolib.worker.js +0 -1
- biolib/biolib-js/1-biolib.worker.js +0 -1
- biolib/biolib-js/2-biolib.worker.js +0 -1
- biolib/biolib-js/3-biolib.worker.js +0 -1
- biolib/biolib-js/4-biolib.worker.js +0 -1
- biolib/biolib-js/5-biolib.worker.js +0 -1
- biolib/biolib-js/6-biolib.worker.js +0 -1
- biolib/biolib-js/index.html +0 -10
- biolib/biolib-js/main-biolib.js +0 -1
- biolib/biolib_api_client/biolib_account_api.py +0 -21
- biolib/biolib_api_client/biolib_large_file_system_api.py +0 -108
- biolib/biolib_binary_format/aes_encrypted_package.py +0 -42
- biolib/biolib_binary_format/module_output.py +0 -58
- biolib/biolib_binary_format/rsa_encrypted_aes_package.py +0 -57
- biolib/biolib_push.py +0 -114
- biolib/cli.py +0 -203
- biolib/cli_utils.py +0 -273
- biolib/compute_node/cloud_utils/enclave_parent_types.py +0 -7
- biolib/compute_node/enclave/__init__.py +0 -2
- biolib/compute_node/enclave/enclave_remote_hosts.py +0 -53
- biolib/compute_node/enclave/nitro_secure_module_utils.py +0 -64
- biolib/compute_node/job_worker/executors/base_executor.py +0 -18
- biolib/compute_node/job_worker/executors/pyppeteer_executor.py +0 -173
- biolib/compute_node/job_worker/executors/remote/__init__.py +0 -1
- biolib/compute_node/job_worker/executors/remote/nitro_enclave_utils.py +0 -81
- biolib/compute_node/job_worker/executors/remote/remote_executor.py +0 -51
- biolib/lfs.py +0 -196
- biolib/pyppeteer/.circleci/config.yml +0 -100
- biolib/pyppeteer/.coveragerc +0 -3
- biolib/pyppeteer/.gitignore +0 -89
- biolib/pyppeteer/.pre-commit-config.yaml +0 -28
- biolib/pyppeteer/CHANGES.md +0 -253
- biolib/pyppeteer/CONTRIBUTING.md +0 -26
- biolib/pyppeteer/LICENSE +0 -12
- biolib/pyppeteer/README.md +0 -137
- biolib/pyppeteer/docs/Makefile +0 -177
- biolib/pyppeteer/docs/_static/custom.css +0 -28
- biolib/pyppeteer/docs/_templates/layout.html +0 -10
- biolib/pyppeteer/docs/changes.md +0 -1
- biolib/pyppeteer/docs/conf.py +0 -299
- biolib/pyppeteer/docs/index.md +0 -21
- biolib/pyppeteer/docs/make.bat +0 -242
- biolib/pyppeteer/docs/reference.md +0 -211
- biolib/pyppeteer/docs/server.py +0 -60
- biolib/pyppeteer/poetry.lock +0 -1699
- biolib/pyppeteer/pyppeteer/__init__.py +0 -135
- biolib/pyppeteer/pyppeteer/accessibility.py +0 -286
- biolib/pyppeteer/pyppeteer/browser.py +0 -401
- biolib/pyppeteer/pyppeteer/browser_fetcher.py +0 -194
- biolib/pyppeteer/pyppeteer/command.py +0 -22
- biolib/pyppeteer/pyppeteer/connection/__init__.py +0 -242
- biolib/pyppeteer/pyppeteer/connection/cdpsession.py +0 -101
- biolib/pyppeteer/pyppeteer/coverage.py +0 -346
- biolib/pyppeteer/pyppeteer/device_descriptors.py +0 -787
- biolib/pyppeteer/pyppeteer/dialog.py +0 -79
- biolib/pyppeteer/pyppeteer/domworld.py +0 -597
- biolib/pyppeteer/pyppeteer/emulation_manager.py +0 -53
- biolib/pyppeteer/pyppeteer/errors.py +0 -48
- biolib/pyppeteer/pyppeteer/events.py +0 -63
- biolib/pyppeteer/pyppeteer/execution_context.py +0 -156
- biolib/pyppeteer/pyppeteer/frame/__init__.py +0 -299
- biolib/pyppeteer/pyppeteer/frame/frame_manager.py +0 -306
- biolib/pyppeteer/pyppeteer/helpers.py +0 -245
- biolib/pyppeteer/pyppeteer/input.py +0 -371
- biolib/pyppeteer/pyppeteer/jshandle.py +0 -598
- biolib/pyppeteer/pyppeteer/launcher.py +0 -683
- biolib/pyppeteer/pyppeteer/lifecycle_watcher.py +0 -169
- biolib/pyppeteer/pyppeteer/models/__init__.py +0 -103
- biolib/pyppeteer/pyppeteer/models/_protocol.py +0 -12460
- biolib/pyppeteer/pyppeteer/multimap.py +0 -82
- biolib/pyppeteer/pyppeteer/network_manager.py +0 -678
- biolib/pyppeteer/pyppeteer/options.py +0 -8
- biolib/pyppeteer/pyppeteer/page.py +0 -1728
- biolib/pyppeteer/pyppeteer/pipe_transport.py +0 -59
- biolib/pyppeteer/pyppeteer/target.py +0 -147
- biolib/pyppeteer/pyppeteer/task_queue.py +0 -24
- biolib/pyppeteer/pyppeteer/timeout_settings.py +0 -36
- biolib/pyppeteer/pyppeteer/tracing.py +0 -93
- biolib/pyppeteer/pyppeteer/us_keyboard_layout.py +0 -305
- biolib/pyppeteer/pyppeteer/util.py +0 -18
- biolib/pyppeteer/pyppeteer/websocket_transport.py +0 -47
- biolib/pyppeteer/pyppeteer/worker.py +0 -101
- biolib/pyppeteer/pyproject.toml +0 -97
- biolib/pyppeteer/spell.txt +0 -137
- biolib/pyppeteer/tox.ini +0 -72
- biolib/pyppeteer/utils/generate_protocol_types.py +0 -603
- biolib/start_cli.py +0 -7
- biolib/utils.py +0 -47
- biolib/validators/validate_app_version.py +0 -183
- biolib/validators/validate_argument.py +0 -134
- biolib/validators/validate_module.py +0 -323
- biolib/validators/validate_zip_file.py +0 -40
- biolib/validators/validator_utils.py +0 -103
- pybiolib-0.2.951.dist-info/LICENSE +0 -21
- pybiolib-0.2.951.dist-info/METADATA +0 -61
- pybiolib-0.2.951.dist-info/RECORD +0 -153
- pybiolib-0.2.951.dist-info/entry_points.txt +0 -3
- /LICENSE → /pybiolib-1.2.1890.dist-info/licenses/LICENSE +0 -0
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
"""Dialog module."""
|
|
5
|
-
from types import SimpleNamespace
|
|
6
|
-
|
|
7
|
-
from biolib.pyppeteer.pyppeteer.connection import CDPSession
|
|
8
|
-
from biolib.pyppeteer.pyppeteer.errors import BrowserError
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class Dialog:
|
|
12
|
-
"""Dialog class.
|
|
13
|
-
|
|
14
|
-
Dialog objects are dispatched by page via the ``dialog`` event.
|
|
15
|
-
|
|
16
|
-
An example of using ``Dialog`` class:
|
|
17
|
-
|
|
18
|
-
.. code::
|
|
19
|
-
|
|
20
|
-
browser = await launch()
|
|
21
|
-
page = await browser.newPage()
|
|
22
|
-
|
|
23
|
-
async def close_dialog(dialog):
|
|
24
|
-
print(dialog.message)
|
|
25
|
-
await dialog.dismiss()
|
|
26
|
-
await browser.close()
|
|
27
|
-
|
|
28
|
-
page.on(
|
|
29
|
-
'dialog',
|
|
30
|
-
lambda dialog: asyncio.ensure_future(close_dialog(dialog))
|
|
31
|
-
)
|
|
32
|
-
await page.evaluate('() => alert("1")')
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
Type = SimpleNamespace(Alert='alert', BeforeUnload='beforeunload', Confirm='confirm', Prompt='prompt',)
|
|
36
|
-
|
|
37
|
-
def __init__(self, client: CDPSession, type_: str, message: str, defaultValue: str = '') -> None:
|
|
38
|
-
self._client = client
|
|
39
|
-
self._type = type_
|
|
40
|
-
self._message = message
|
|
41
|
-
self._handled = False
|
|
42
|
-
self._defaultValue = defaultValue
|
|
43
|
-
|
|
44
|
-
@property
|
|
45
|
-
def type(self) -> str:
|
|
46
|
-
"""Get dialog type.
|
|
47
|
-
|
|
48
|
-
One of ``alert``, ``beforeunload``, ``confirm``, or ``prompt``.
|
|
49
|
-
"""
|
|
50
|
-
return self._type
|
|
51
|
-
|
|
52
|
-
@property
|
|
53
|
-
def message(self) -> str:
|
|
54
|
-
"""Get dialog message."""
|
|
55
|
-
return self._message
|
|
56
|
-
|
|
57
|
-
@property
|
|
58
|
-
def defaultValue(self) -> str:
|
|
59
|
-
"""If dialog is prompt, get default prompt value.
|
|
60
|
-
|
|
61
|
-
If dialog is not prompt, return empty string (``''``).
|
|
62
|
-
"""
|
|
63
|
-
return self._defaultValue
|
|
64
|
-
|
|
65
|
-
async def accept(self, promptText: str = '') -> None:
|
|
66
|
-
"""Accept the dialog.
|
|
67
|
-
|
|
68
|
-
* ``promptText`` (str): A text to enter in prompt. If the dialog's type
|
|
69
|
-
is not prompt, this does not cause any effect.
|
|
70
|
-
"""
|
|
71
|
-
self._handled = True
|
|
72
|
-
await self._client.send('Page.handleJavaScriptDialog', {'accept': True, 'promptText': promptText,})
|
|
73
|
-
|
|
74
|
-
async def dismiss(self) -> None:
|
|
75
|
-
"""Dismiss the dialog."""
|
|
76
|
-
if self._handled:
|
|
77
|
-
raise BrowserError('Cannot dismiss dialog which is already handled!')
|
|
78
|
-
self._handled = True
|
|
79
|
-
await self._client.send('Page.handleJavaScriptDialog', {'accept': False,})
|
|
@@ -1,597 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
from asyncio import Future, Task
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Generator, List, Optional, Set, Union
|
|
5
|
-
|
|
6
|
-
from biolib.pyppeteer.pyppeteer import helpers
|
|
7
|
-
from biolib.pyppeteer.pyppeteer.errors import BrowserError, NetworkError, PageError
|
|
8
|
-
from biolib.pyppeteer.pyppeteer.lifecycle_watcher import LifecycleWatcher
|
|
9
|
-
from biolib.pyppeteer.pyppeteer.models import JSFunctionArg, MouseButton
|
|
10
|
-
from biolib.pyppeteer.pyppeteer.timeout_settings import TimeoutSettings
|
|
11
|
-
|
|
12
|
-
if TYPE_CHECKING:
|
|
13
|
-
from pyppeteer.jshandle import JSHandle, ElementHandle
|
|
14
|
-
from pyppeteer.frame import Frame, FrameManager
|
|
15
|
-
from pyppeteer.execution_context import ExecutionContext
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
async def readFileAsync(path, encoding):
|
|
19
|
-
return Path(path).read_text(encoding=encoding)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class DOMWorld:
|
|
23
|
-
def __init__(
|
|
24
|
-
self, frameManager: 'FrameManager', frame: 'Frame', timeoutSettings: TimeoutSettings,
|
|
25
|
-
):
|
|
26
|
-
self._frameManager = frameManager
|
|
27
|
-
self._frame = frame
|
|
28
|
-
self._timeoutSettings = timeoutSettings
|
|
29
|
-
self.loop = self._frameManager._client.loop
|
|
30
|
-
|
|
31
|
-
self._documentTask: Optional[Task['ElementHandle']] = None
|
|
32
|
-
self._contextFuture: Optional[Future['ExecutionContext']] = None
|
|
33
|
-
self._contextResolveCallback: Optional[Callable] = None
|
|
34
|
-
self._setContext()
|
|
35
|
-
|
|
36
|
-
self._waitTasks: Set[WaitTask] = set()
|
|
37
|
-
self._detached = False
|
|
38
|
-
|
|
39
|
-
# Aliases for query methods:
|
|
40
|
-
self.J = self.querySelector
|
|
41
|
-
self.Jx = self.xpath
|
|
42
|
-
self.Jeval = self.querySelectorEval
|
|
43
|
-
self.JJ = self.querySelectorAll
|
|
44
|
-
self.JJeval = self.querySelectorAllEval
|
|
45
|
-
|
|
46
|
-
@property
|
|
47
|
-
def frame(self) -> 'Frame':
|
|
48
|
-
return self._frame
|
|
49
|
-
|
|
50
|
-
def _setContext(self, context: Optional['ExecutionContext'] = None) -> None:
|
|
51
|
-
if context:
|
|
52
|
-
self._contextResolveCallback(context)
|
|
53
|
-
self._contextResolveCallback = None
|
|
54
|
-
for waitTask in self._waitTasks:
|
|
55
|
-
self.loop.create_task(waitTask.rerun())
|
|
56
|
-
else:
|
|
57
|
-
self._documentTask = None
|
|
58
|
-
self._contextFuture = self.loop.create_future()
|
|
59
|
-
self._contextResolveCallback = lambda _: self._contextFuture.set_result(_)
|
|
60
|
-
|
|
61
|
-
def _hasContext(self) -> bool:
|
|
62
|
-
return not self._contextResolveCallback
|
|
63
|
-
|
|
64
|
-
def _detach(self) -> None:
|
|
65
|
-
self._detached = True
|
|
66
|
-
for task in self._waitTasks:
|
|
67
|
-
task.terminate(BrowserError('waitForFunctions failed: frame got detached.'))
|
|
68
|
-
|
|
69
|
-
@property
|
|
70
|
-
async def executionContext(self) -> Optional['ExecutionContext']:
|
|
71
|
-
if self._detached:
|
|
72
|
-
raise BrowserError(
|
|
73
|
-
'Execution Context is not available in detached '
|
|
74
|
-
f'frame: {self._frame.url} (are you trying to evaluate?)'
|
|
75
|
-
)
|
|
76
|
-
return await self._contextFuture if self._contextFuture else None
|
|
77
|
-
|
|
78
|
-
async def evaluateHandle(self, pageFunction: str, *args: JSFunctionArg) -> 'ElementHandle':
|
|
79
|
-
context = await self.executionContext
|
|
80
|
-
return await context.evaluateHandle(pageFunction=pageFunction, *args)
|
|
81
|
-
|
|
82
|
-
async def evaluate(self, pageFunction: str, *args: JSFunctionArg):
|
|
83
|
-
context = await self.executionContext
|
|
84
|
-
return await context.evaluate(pageFunction, *args)
|
|
85
|
-
|
|
86
|
-
async def querySelector(self, selector: str) -> Optional['ElementHandle']:
|
|
87
|
-
document = await self._document
|
|
88
|
-
return await document.querySelector(selector)
|
|
89
|
-
|
|
90
|
-
@property
|
|
91
|
-
def _document(self) -> Awaitable['ElementHandle']:
|
|
92
|
-
if self._documentTask:
|
|
93
|
-
return self._documentTask
|
|
94
|
-
|
|
95
|
-
async def create_document_fut() -> 'ElementHandle':
|
|
96
|
-
nonlocal self
|
|
97
|
-
context = await self.executionContext
|
|
98
|
-
document = await context.evaluateHandle('document')
|
|
99
|
-
return document.asElement()
|
|
100
|
-
|
|
101
|
-
self._documentTask = self.loop.create_task(create_document_fut())
|
|
102
|
-
return self._documentTask
|
|
103
|
-
|
|
104
|
-
async def xpath(self, expression: str) -> List['ElementHandle']:
|
|
105
|
-
document = await self._document
|
|
106
|
-
return await document.xpath(expression)
|
|
107
|
-
|
|
108
|
-
async def querySelectorEval(self, selector: str, pageFunction: str, *args: JSFunctionArg) -> Any:
|
|
109
|
-
document = await self._document
|
|
110
|
-
return await document.querySelectorEval(selector, pageFunction, *args)
|
|
111
|
-
|
|
112
|
-
async def querySelectorAll(self, selector: str) -> List['ElementHandle']:
|
|
113
|
-
"""Get all elements which matches `selector`.
|
|
114
|
-
|
|
115
|
-
Details see :meth:`pyppeteer.page.Page.querySelectorAll`.
|
|
116
|
-
"""
|
|
117
|
-
document = await self._document
|
|
118
|
-
value = await document.querySelectorAll(selector)
|
|
119
|
-
return value
|
|
120
|
-
|
|
121
|
-
async def querySelectorAllEval(self, selector: str, pageFunction: str, *args: JSFunctionArg) -> Optional[Dict]:
|
|
122
|
-
"""Execute function on all elements which matches selector.
|
|
123
|
-
|
|
124
|
-
Details see :meth:`pyppeteer.page.Page.querySelectorAllEval`.
|
|
125
|
-
"""
|
|
126
|
-
document = await self._document
|
|
127
|
-
value = await document.JJeval(selector, pageFunction, *args)
|
|
128
|
-
return value
|
|
129
|
-
|
|
130
|
-
@property
|
|
131
|
-
async def content(self) -> str:
|
|
132
|
-
return await self.evaluate(
|
|
133
|
-
"""
|
|
134
|
-
() => {
|
|
135
|
-
let retVal = '';
|
|
136
|
-
if (document.doctype)
|
|
137
|
-
retVal = new XMLSerializer().serializeToString(document.doctype);
|
|
138
|
-
if (document.documentElement)
|
|
139
|
-
retVal += document.documentElement.outerHTML;
|
|
140
|
-
return retVal;
|
|
141
|
-
}
|
|
142
|
-
"""
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
async def setContent(self, html: str, waitUntil=None, timeout=None) -> None:
|
|
146
|
-
if timeout is None:
|
|
147
|
-
timeout = self._timeoutSettings.navigationTimeout
|
|
148
|
-
if waitUntil is None:
|
|
149
|
-
waitUntil = ['load']
|
|
150
|
-
await self.evaluate(
|
|
151
|
-
"""
|
|
152
|
-
html => {
|
|
153
|
-
document.open();
|
|
154
|
-
document.write(html);
|
|
155
|
-
document.close();
|
|
156
|
-
}
|
|
157
|
-
""",
|
|
158
|
-
html,
|
|
159
|
-
)
|
|
160
|
-
watcher = LifecycleWatcher(
|
|
161
|
-
frameManager=self._frameManager, frame=self._frame, waitUntil=waitUntil, timeout=timeout
|
|
162
|
-
)
|
|
163
|
-
error = await helpers.future_race(watcher.timeoutOrTerminationFuture, watcher.lifecycleFuture)
|
|
164
|
-
watcher.dispose()
|
|
165
|
-
if error:
|
|
166
|
-
raise error
|
|
167
|
-
|
|
168
|
-
async def addScriptTag(
|
|
169
|
-
self,
|
|
170
|
-
url: Optional[str] = None,
|
|
171
|
-
path: Optional[Union[str, Path]] = None,
|
|
172
|
-
content: Optional[str] = None,
|
|
173
|
-
type_: str = '',
|
|
174
|
-
) -> Union['ElementHandle', 'JSHandle']:
|
|
175
|
-
addScriptUrl = """
|
|
176
|
-
async function addScriptUrl(url, type) {
|
|
177
|
-
const script = document.createElement('script');
|
|
178
|
-
script.src = url;
|
|
179
|
-
if (type)
|
|
180
|
-
script.type = type;
|
|
181
|
-
const promise = new Promise((res, rej) => {
|
|
182
|
-
script.onload = res;
|
|
183
|
-
script.onerror = rej;
|
|
184
|
-
});
|
|
185
|
-
document.head.appendChild(script);
|
|
186
|
-
await promise;
|
|
187
|
-
return script;
|
|
188
|
-
}
|
|
189
|
-
"""
|
|
190
|
-
addScriptContent = """
|
|
191
|
-
function addScriptContent(content, type = 'text/javascript') {
|
|
192
|
-
const script = document.createElement('script');
|
|
193
|
-
script.type = type;
|
|
194
|
-
script.text = content;
|
|
195
|
-
let error = null;
|
|
196
|
-
script.onerror = e => error = e;
|
|
197
|
-
document.head.appendChild(script);
|
|
198
|
-
if (error)
|
|
199
|
-
throw error;
|
|
200
|
-
return script;
|
|
201
|
-
}
|
|
202
|
-
"""
|
|
203
|
-
context = await self.executionContext
|
|
204
|
-
if url:
|
|
205
|
-
try:
|
|
206
|
-
return await context.evaluateHandle(addScriptUrl, url, type_)
|
|
207
|
-
except Exception as e:
|
|
208
|
-
raise BrowserError(f'Loading script from {url} failed: {e}')
|
|
209
|
-
if path:
|
|
210
|
-
path = Path(path)
|
|
211
|
-
if not path.exists():
|
|
212
|
-
raise FileNotFoundError(f'The specified file, {path.name}, does not exist')
|
|
213
|
-
if not path.is_file():
|
|
214
|
-
raise ValueError(f'The specified path, {path.name}, is not a file')
|
|
215
|
-
contents = await readFileAsync(path, 'utf8')
|
|
216
|
-
contents += '//# sourceURL' + path.name
|
|
217
|
-
f = context.evaluateHandle(addScriptContent, contents, type_)
|
|
218
|
-
return (await f).asElement()
|
|
219
|
-
if content:
|
|
220
|
-
f = context.evaluateHandle(addScriptContent, content, type_)
|
|
221
|
-
return (await f).asElement()
|
|
222
|
-
raise BrowserError('provide a url, path or content argument')
|
|
223
|
-
|
|
224
|
-
async def addStyleTag(
|
|
225
|
-
self, url: Optional[str] = None, path: Optional[Union[Path, str]] = None, content: Optional[str] = None
|
|
226
|
-
) -> 'ElementHandle':
|
|
227
|
-
addStyleUrl = """
|
|
228
|
-
async function addStyleUrl(url) {
|
|
229
|
-
const link = document.createElement('link');
|
|
230
|
-
link.rel = 'stylesheet';
|
|
231
|
-
link.href = url;
|
|
232
|
-
const promise = new Promise((res, rej) => {
|
|
233
|
-
link.onload = res;
|
|
234
|
-
link.onerror = rej;
|
|
235
|
-
});
|
|
236
|
-
document.head.appendChild(link);
|
|
237
|
-
await promise;
|
|
238
|
-
return link;
|
|
239
|
-
}
|
|
240
|
-
"""
|
|
241
|
-
addStyleContent = """
|
|
242
|
-
async function addStyleContent(content) {
|
|
243
|
-
const style = document.createElement('style');
|
|
244
|
-
style.type = 'text/css';
|
|
245
|
-
style.appendChild(document.createTextNode(content));
|
|
246
|
-
const promise = new Promise((res, rej) => {
|
|
247
|
-
style.onload = res;
|
|
248
|
-
style.onerror = rej;
|
|
249
|
-
});
|
|
250
|
-
document.head.appendChild(style);
|
|
251
|
-
await promise;
|
|
252
|
-
return style;
|
|
253
|
-
}
|
|
254
|
-
"""
|
|
255
|
-
context = await self.executionContext
|
|
256
|
-
if url:
|
|
257
|
-
try:
|
|
258
|
-
return (await context.evaluateHandle(addStyleUrl, url)).asElement()
|
|
259
|
-
except Exception as e:
|
|
260
|
-
raise BrowserError(f'Loading style from {url} failed')
|
|
261
|
-
|
|
262
|
-
if path:
|
|
263
|
-
path = Path(path)
|
|
264
|
-
contents = await readFileAsync(path, 'utf8')
|
|
265
|
-
contents += f'/*# sourceURL={path.name}*/'
|
|
266
|
-
return (await context.evaluateHandle(addStyleContent, contents)).asElement()
|
|
267
|
-
|
|
268
|
-
if content:
|
|
269
|
-
return (await context.evaluateHandle(addStyleContent, content)).asElement()
|
|
270
|
-
raise BrowserError('provide an object with url, path or content property')
|
|
271
|
-
|
|
272
|
-
async def _select_handle(self, selector: str) -> 'ElementHandle':
|
|
273
|
-
handle = await self.querySelector(selector)
|
|
274
|
-
if not handle:
|
|
275
|
-
raise BrowserError(f'No node found for selector: {selector}')
|
|
276
|
-
return handle
|
|
277
|
-
|
|
278
|
-
async def click(self, selector: str, button: MouseButton = 'left', clickCount: int = 1, delay: float = 0) -> None:
|
|
279
|
-
"""
|
|
280
|
-
:param selector: CSS selector for element
|
|
281
|
-
:param button:
|
|
282
|
-
:param delay:
|
|
283
|
-
:param clickCount:
|
|
284
|
-
:return:
|
|
285
|
-
"""
|
|
286
|
-
handle = await self._select_handle(selector)
|
|
287
|
-
await handle.click(button=button, clickCount=clickCount, delay=delay)
|
|
288
|
-
await handle.dispose()
|
|
289
|
-
|
|
290
|
-
async def focus(self, selector: str) -> None:
|
|
291
|
-
handle = await self._select_handle(selector)
|
|
292
|
-
await handle.focus()
|
|
293
|
-
await handle.dispose()
|
|
294
|
-
|
|
295
|
-
async def hover(self, selector: str) -> None:
|
|
296
|
-
handle = await self._select_handle(selector)
|
|
297
|
-
await handle.hover()
|
|
298
|
-
await handle.dispose()
|
|
299
|
-
|
|
300
|
-
async def select(self, selector: str, *values: str) -> List[str]:
|
|
301
|
-
handle = await self._select_handle(selector)
|
|
302
|
-
result = await handle.select(*values)
|
|
303
|
-
await handle.dispose()
|
|
304
|
-
return result
|
|
305
|
-
|
|
306
|
-
async def tap(self, selector: str) -> None:
|
|
307
|
-
handle = await self._select_handle(selector)
|
|
308
|
-
await handle.tap()
|
|
309
|
-
await handle.dispose()
|
|
310
|
-
|
|
311
|
-
async def type(self, selector: str, text: str, delay: float = 0) -> None:
|
|
312
|
-
handle = await self._select_handle(selector)
|
|
313
|
-
await handle.type(text=text, delay=delay)
|
|
314
|
-
await handle.dispose()
|
|
315
|
-
|
|
316
|
-
async def waitForSelector(
|
|
317
|
-
self, selector: str, visible: bool = False, hidden: bool = False, timeout: float = None
|
|
318
|
-
) -> Optional['ElementHandle']:
|
|
319
|
-
return await self._waitForSelectorOrXpath(
|
|
320
|
-
selector, isXPath=False, visible=visible, hidden=hidden, timeout=timeout
|
|
321
|
-
)
|
|
322
|
-
|
|
323
|
-
async def waitForXpath(
|
|
324
|
-
self, xpath: str, visible: bool = False, hidden: bool = False, timeout: float = None
|
|
325
|
-
) -> Optional['ElementHandle']:
|
|
326
|
-
return await self._waitForSelectorOrXpath(xpath, isXPath=True, visible=visible, hidden=hidden, timeout=timeout)
|
|
327
|
-
|
|
328
|
-
async def waitForFunction(
|
|
329
|
-
self, pageFunction: str, *args: JSFunctionArg, polling: str = 'raf', timeout: Optional[float] = None,
|
|
330
|
-
) -> 'JSHandle':
|
|
331
|
-
if not timeout:
|
|
332
|
-
timeout = self._timeoutSettings.timeout
|
|
333
|
-
return await WaitTask(self, pageFunction, 'function', polling, timeout, self.loop, *args).promise
|
|
334
|
-
|
|
335
|
-
@property
|
|
336
|
-
async def title(self) -> str:
|
|
337
|
-
return await self.evaluate('document.title')
|
|
338
|
-
|
|
339
|
-
async def _waitForSelectorOrXpath(
|
|
340
|
-
self,
|
|
341
|
-
selectorOrXpath: str,
|
|
342
|
-
isXPath: bool,
|
|
343
|
-
visible: bool = False,
|
|
344
|
-
hidden: bool = False,
|
|
345
|
-
timeout: Optional[float] = None,
|
|
346
|
-
) -> Optional['ElementHandle']:
|
|
347
|
-
if not timeout:
|
|
348
|
-
timeout = self._timeoutSettings.timeout
|
|
349
|
-
if visible or hidden:
|
|
350
|
-
polling = 'raf'
|
|
351
|
-
else:
|
|
352
|
-
polling = 'mutation'
|
|
353
|
-
title = f"{'XPath' if isXPath else 'selector'} {selectorOrXpath}{' to be hidden' if hidden else ''}"
|
|
354
|
-
predicate = """
|
|
355
|
-
function predicate(selectorOrXPath, isXPath, waitForVisible, waitForHidden) {
|
|
356
|
-
const node = isXPath
|
|
357
|
-
? document.evaluate(selectorOrXPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue
|
|
358
|
-
: document.querySelector(selectorOrXPath);
|
|
359
|
-
if (!node)
|
|
360
|
-
return waitForHidden;
|
|
361
|
-
if (!waitForVisible && !waitForHidden)
|
|
362
|
-
return node;
|
|
363
|
-
const element = /** @type {Element} */ (node.nodeType === Node.TEXT_NODE ? node.parentElement : node);
|
|
364
|
-
|
|
365
|
-
const style = window.getComputedStyle(element);
|
|
366
|
-
const isVisible = style && style.visibility !== 'hidden' && hasVisibleBoundingBox();
|
|
367
|
-
const success = (waitForVisible === isVisible || waitForHidden === !isVisible);
|
|
368
|
-
return success ? node : null;
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* @return {boolean}
|
|
372
|
-
*/
|
|
373
|
-
function hasVisibleBoundingBox() {
|
|
374
|
-
const rect = element.getBoundingClientRect();
|
|
375
|
-
return !!(rect.top || rect.bottom || rect.width || rect.height);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
"""
|
|
379
|
-
waitTask = WaitTask(
|
|
380
|
-
self, predicate, title, polling, timeout, self.loop, selectorOrXpath, isXPath, visible, hidden
|
|
381
|
-
)
|
|
382
|
-
handle = await waitTask.promise
|
|
383
|
-
if not handle.asElement():
|
|
384
|
-
await handle.dispose()
|
|
385
|
-
return None
|
|
386
|
-
return handle.asElement()
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
class WaitTask:
|
|
390
|
-
"""WaitTask class.
|
|
391
|
-
|
|
392
|
-
Instance of this class is awaitable.
|
|
393
|
-
"""
|
|
394
|
-
|
|
395
|
-
def __init__(
|
|
396
|
-
self,
|
|
397
|
-
domWorld: DOMWorld,
|
|
398
|
-
predicateBody: str,
|
|
399
|
-
title: str,
|
|
400
|
-
polling: Union[str, int],
|
|
401
|
-
timeout: float,
|
|
402
|
-
loop: asyncio.AbstractEventLoop,
|
|
403
|
-
*args: JSFunctionArg,
|
|
404
|
-
) -> None:
|
|
405
|
-
if isinstance(polling, str):
|
|
406
|
-
if polling not in ['raf', 'mutation']:
|
|
407
|
-
raise ValueError(f'Unknown polling: {polling}')
|
|
408
|
-
elif isinstance(polling, (int, float)):
|
|
409
|
-
if polling <= 0:
|
|
410
|
-
raise ValueError(f'Cannot poll with non-positive interval: {polling}')
|
|
411
|
-
else:
|
|
412
|
-
raise ValueError(f'Unknown polling option: {polling}')
|
|
413
|
-
|
|
414
|
-
self._domWorld = domWorld
|
|
415
|
-
self._polling = polling
|
|
416
|
-
self._timeout = timeout
|
|
417
|
-
self.loop = loop
|
|
418
|
-
if args or helpers.is_js_func(predicateBody):
|
|
419
|
-
self._predicateBody = f'return ({predicateBody})(...args)'
|
|
420
|
-
else:
|
|
421
|
-
self._predicateBody = f'return {predicateBody}'
|
|
422
|
-
self._args = args
|
|
423
|
-
self._runCount = 0
|
|
424
|
-
self._terminated = False
|
|
425
|
-
self._timeoutError = False
|
|
426
|
-
domWorld._waitTasks.add(self)
|
|
427
|
-
|
|
428
|
-
self.promise = self.loop.create_future()
|
|
429
|
-
|
|
430
|
-
async def timer(timeout: float) -> None:
|
|
431
|
-
await asyncio.sleep(timeout / 1000)
|
|
432
|
-
self._timeoutError = True
|
|
433
|
-
self.terminate(TimeoutError(f'Waiting for {title} failed: timeout of {timeout}ms exceeded.'))
|
|
434
|
-
|
|
435
|
-
if timeout:
|
|
436
|
-
self._timeoutTimer = self.loop.create_task(timer(self._timeout))
|
|
437
|
-
self._runningTask: Optional[Task] = self.loop.create_task(self.rerun())
|
|
438
|
-
|
|
439
|
-
def __await__(self) -> Generator:
|
|
440
|
-
"""Make this class **awaitable**."""
|
|
441
|
-
result = yield from self.promise
|
|
442
|
-
if isinstance(result, Exception):
|
|
443
|
-
raise result
|
|
444
|
-
return result
|
|
445
|
-
|
|
446
|
-
def terminate(self, error: Exception) -> None:
|
|
447
|
-
"""Terminate this task."""
|
|
448
|
-
self._terminated = True
|
|
449
|
-
if not self.promise.done():
|
|
450
|
-
self.promise.set_exception(error)
|
|
451
|
-
self._cleanup()
|
|
452
|
-
|
|
453
|
-
async def rerun(self) -> None: # noqa: C901
|
|
454
|
-
"""Start polling."""
|
|
455
|
-
runCount = self._runCount = self._runCount + 1
|
|
456
|
-
success: Optional['JSHandle'] = None
|
|
457
|
-
error = None
|
|
458
|
-
|
|
459
|
-
try:
|
|
460
|
-
if await self._domWorld.executionContext is None:
|
|
461
|
-
raise PageError(f'No execution context for {self._domWorld}')
|
|
462
|
-
context = await self._domWorld.executionContext
|
|
463
|
-
success = await context.evaluateHandle(
|
|
464
|
-
waitForPredicatePageFunction, self._predicateBody, self._polling, self._timeout, *self._args,
|
|
465
|
-
)
|
|
466
|
-
except Exception as e:
|
|
467
|
-
error = e
|
|
468
|
-
|
|
469
|
-
if self.promise.done():
|
|
470
|
-
return
|
|
471
|
-
|
|
472
|
-
if self._terminated or runCount != self._runCount:
|
|
473
|
-
if success:
|
|
474
|
-
await success.dispose()
|
|
475
|
-
return
|
|
476
|
-
|
|
477
|
-
# Add try/except referring to puppeteer.
|
|
478
|
-
try:
|
|
479
|
-
if not error and success and (await self._domWorld.evaluate('s => !s', success)):
|
|
480
|
-
await success.dispose()
|
|
481
|
-
return
|
|
482
|
-
except NetworkError:
|
|
483
|
-
if success is not None:
|
|
484
|
-
await success.dispose()
|
|
485
|
-
return
|
|
486
|
-
|
|
487
|
-
# page is navigated and context is destroyed.
|
|
488
|
-
# Try again in the new execution context.
|
|
489
|
-
if isinstance(error, NetworkError) and 'Execution context was destroyed' in error.args[0]:
|
|
490
|
-
return
|
|
491
|
-
|
|
492
|
-
# Try again in the new execution context.
|
|
493
|
-
if isinstance(error, NetworkError) and 'Cannot find context with specified id' in error.args[0]:
|
|
494
|
-
return
|
|
495
|
-
|
|
496
|
-
if error:
|
|
497
|
-
self.promise.set_exception(error)
|
|
498
|
-
else:
|
|
499
|
-
self.promise.set_result(success)
|
|
500
|
-
|
|
501
|
-
self._cleanup()
|
|
502
|
-
|
|
503
|
-
def _cleanup(self) -> None:
|
|
504
|
-
if self._timeout and not self._timeoutError:
|
|
505
|
-
self._timeoutTimer.cancel()
|
|
506
|
-
self._domWorld._waitTasks.remove(self)
|
|
507
|
-
self._runningTask = None
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
waitForPredicatePageFunction = """
|
|
511
|
-
async function waitForPredicatePageFunction(predicateBody, polling, timeout, ...args) {
|
|
512
|
-
const predicate = new Function('...args', predicateBody);
|
|
513
|
-
let timedOut = false;
|
|
514
|
-
if (timeout)
|
|
515
|
-
setTimeout(() => timedOut = true, timeout);
|
|
516
|
-
if (polling === 'raf')
|
|
517
|
-
return await pollRaf();
|
|
518
|
-
if (polling === 'mutation')
|
|
519
|
-
return await pollMutation();
|
|
520
|
-
if (typeof polling === 'number')
|
|
521
|
-
return await pollInterval(polling);
|
|
522
|
-
|
|
523
|
-
/**
|
|
524
|
-
* @return {!Promise<*>}
|
|
525
|
-
*/
|
|
526
|
-
function pollMutation() {
|
|
527
|
-
const success = predicate.apply(null, args);
|
|
528
|
-
if (success)
|
|
529
|
-
return Promise.resolve(success);
|
|
530
|
-
|
|
531
|
-
let fulfill;
|
|
532
|
-
const result = new Promise(x => fulfill = x);
|
|
533
|
-
const observer = new MutationObserver(mutations => {
|
|
534
|
-
if (timedOut) {
|
|
535
|
-
observer.disconnect();
|
|
536
|
-
fulfill();
|
|
537
|
-
}
|
|
538
|
-
const success = predicate.apply(null, args);
|
|
539
|
-
if (success) {
|
|
540
|
-
observer.disconnect();
|
|
541
|
-
fulfill(success);
|
|
542
|
-
}
|
|
543
|
-
});
|
|
544
|
-
observer.observe(document, {
|
|
545
|
-
childList: true,
|
|
546
|
-
subtree: true,
|
|
547
|
-
attributes: true
|
|
548
|
-
});
|
|
549
|
-
return result;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
/**
|
|
553
|
-
* @return {!Promise<*>}
|
|
554
|
-
*/
|
|
555
|
-
function pollRaf() {
|
|
556
|
-
let fulfill;
|
|
557
|
-
const result = new Promise(x => fulfill = x);
|
|
558
|
-
onRaf();
|
|
559
|
-
return result;
|
|
560
|
-
|
|
561
|
-
function onRaf() {
|
|
562
|
-
if (timedOut) {
|
|
563
|
-
fulfill();
|
|
564
|
-
return;
|
|
565
|
-
}
|
|
566
|
-
const success = predicate.apply(null, args);
|
|
567
|
-
if (success)
|
|
568
|
-
fulfill(success);
|
|
569
|
-
else
|
|
570
|
-
requestAnimationFrame(onRaf);
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
/**
|
|
575
|
-
* @param {number} pollInterval
|
|
576
|
-
* @return {!Promise<*>}
|
|
577
|
-
*/
|
|
578
|
-
function pollInterval(pollInterval) {
|
|
579
|
-
let fulfill;
|
|
580
|
-
const result = new Promise(x => fulfill = x);
|
|
581
|
-
onTimeout();
|
|
582
|
-
return result;
|
|
583
|
-
|
|
584
|
-
function onTimeout() {
|
|
585
|
-
if (timedOut) {
|
|
586
|
-
fulfill();
|
|
587
|
-
return;
|
|
588
|
-
}
|
|
589
|
-
const success = predicate.apply(null, args);
|
|
590
|
-
if (success)
|
|
591
|
-
fulfill(success);
|
|
592
|
-
else
|
|
593
|
-
setTimeout(onTimeout, pollInterval);
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
"""
|