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.
Files changed (262) hide show
  1. biolib/__init__.py +357 -11
  2. biolib/_data_record/data_record.py +380 -0
  3. biolib/_index/__init__.py +0 -0
  4. biolib/_index/index.py +55 -0
  5. biolib/_index/query_result.py +103 -0
  6. biolib/_internal/__init__.py +0 -0
  7. biolib/_internal/add_copilot_prompts.py +58 -0
  8. biolib/_internal/add_gui_files.py +81 -0
  9. biolib/_internal/data_record/__init__.py +1 -0
  10. biolib/_internal/data_record/data_record.py +85 -0
  11. biolib/_internal/data_record/push_data.py +116 -0
  12. biolib/_internal/data_record/remote_storage_endpoint.py +43 -0
  13. biolib/_internal/errors.py +5 -0
  14. biolib/_internal/file_utils.py +125 -0
  15. biolib/_internal/fuse_mount/__init__.py +1 -0
  16. biolib/_internal/fuse_mount/experiment_fuse_mount.py +209 -0
  17. biolib/_internal/http_client.py +159 -0
  18. biolib/_internal/lfs/__init__.py +1 -0
  19. biolib/_internal/lfs/cache.py +51 -0
  20. biolib/_internal/libs/__init__.py +1 -0
  21. biolib/_internal/libs/fusepy/__init__.py +1257 -0
  22. biolib/_internal/push_application.py +488 -0
  23. biolib/_internal/runtime.py +22 -0
  24. biolib/_internal/string_utils.py +13 -0
  25. biolib/_internal/templates/__init__.py +1 -0
  26. biolib/_internal/templates/copilot_template/.github/instructions/general-app-knowledge.instructions.md +10 -0
  27. biolib/_internal/templates/copilot_template/.github/instructions/style-general.instructions.md +20 -0
  28. biolib/_internal/templates/copilot_template/.github/instructions/style-python.instructions.md +16 -0
  29. biolib/_internal/templates/copilot_template/.github/instructions/style-react-ts.instructions.md +47 -0
  30. biolib/_internal/templates/copilot_template/.github/prompts/biolib_app_inputs.prompt.md +11 -0
  31. biolib/_internal/templates/copilot_template/.github/prompts/biolib_onboard_repo.prompt.md +19 -0
  32. biolib/_internal/templates/copilot_template/.github/prompts/biolib_run_apps.prompt.md +12 -0
  33. biolib/_internal/templates/dashboard_template/.biolib/config.yml +5 -0
  34. biolib/_internal/templates/github_workflow_template/.github/workflows/biolib.yml +21 -0
  35. biolib/_internal/templates/gitignore_template/.gitignore +10 -0
  36. biolib/_internal/templates/gui_template/.yarnrc.yml +1 -0
  37. biolib/_internal/templates/gui_template/App.tsx +53 -0
  38. biolib/_internal/templates/gui_template/Dockerfile +27 -0
  39. biolib/_internal/templates/gui_template/biolib-sdk.ts +82 -0
  40. biolib/_internal/templates/gui_template/dev-data/output.json +7 -0
  41. biolib/_internal/templates/gui_template/index.css +5 -0
  42. biolib/_internal/templates/gui_template/index.html +13 -0
  43. biolib/_internal/templates/gui_template/index.tsx +10 -0
  44. biolib/_internal/templates/gui_template/package.json +27 -0
  45. biolib/_internal/templates/gui_template/tsconfig.json +24 -0
  46. biolib/_internal/templates/gui_template/vite-plugin-dev-data.ts +50 -0
  47. biolib/_internal/templates/gui_template/vite.config.mts +10 -0
  48. biolib/_internal/templates/init_template/.biolib/config.yml +19 -0
  49. biolib/_internal/templates/init_template/Dockerfile +14 -0
  50. biolib/_internal/templates/init_template/requirements.txt +1 -0
  51. biolib/_internal/templates/init_template/run.py +12 -0
  52. biolib/_internal/templates/init_template/run.sh +4 -0
  53. biolib/_internal/templates/templates.py +25 -0
  54. biolib/_internal/tree_utils.py +106 -0
  55. biolib/_internal/utils/__init__.py +65 -0
  56. biolib/_internal/utils/auth.py +46 -0
  57. biolib/_internal/utils/job_url.py +33 -0
  58. biolib/_internal/utils/multinode.py +263 -0
  59. biolib/_runtime/runtime.py +157 -0
  60. biolib/_session/session.py +44 -0
  61. biolib/_shared/__init__.py +0 -0
  62. biolib/_shared/types/__init__.py +74 -0
  63. biolib/_shared/types/account.py +12 -0
  64. biolib/_shared/types/account_member.py +8 -0
  65. biolib/_shared/types/app.py +9 -0
  66. biolib/_shared/types/data_record.py +40 -0
  67. biolib/_shared/types/experiment.py +32 -0
  68. biolib/_shared/types/file_node.py +17 -0
  69. biolib/_shared/types/push.py +6 -0
  70. biolib/_shared/types/resource.py +37 -0
  71. biolib/_shared/types/resource_deploy_key.py +11 -0
  72. biolib/_shared/types/resource_permission.py +14 -0
  73. biolib/_shared/types/resource_version.py +19 -0
  74. biolib/_shared/types/result.py +14 -0
  75. biolib/_shared/types/typing.py +10 -0
  76. biolib/_shared/types/user.py +19 -0
  77. biolib/_shared/utils/__init__.py +7 -0
  78. biolib/_shared/utils/resource_uri.py +75 -0
  79. biolib/api/__init__.py +6 -0
  80. biolib/api/client.py +168 -0
  81. biolib/app/app.py +252 -49
  82. biolib/app/search_apps.py +45 -0
  83. biolib/biolib_api_client/api_client.py +126 -31
  84. biolib/biolib_api_client/app_types.py +24 -4
  85. biolib/biolib_api_client/auth.py +31 -8
  86. biolib/biolib_api_client/biolib_app_api.py +147 -52
  87. biolib/biolib_api_client/biolib_job_api.py +161 -141
  88. biolib/biolib_api_client/job_types.py +21 -5
  89. biolib/biolib_api_client/lfs_types.py +7 -23
  90. biolib/biolib_api_client/user_state.py +56 -0
  91. biolib/biolib_binary_format/__init__.py +1 -4
  92. biolib/biolib_binary_format/file_in_container.py +105 -0
  93. biolib/biolib_binary_format/module_input.py +24 -7
  94. biolib/biolib_binary_format/module_output_v2.py +149 -0
  95. biolib/biolib_binary_format/remote_endpoints.py +34 -0
  96. biolib/biolib_binary_format/remote_stream_seeker.py +59 -0
  97. biolib/biolib_binary_format/saved_job.py +3 -2
  98. biolib/biolib_binary_format/{attestation_document.py → stdout_and_stderr.py} +8 -8
  99. biolib/biolib_binary_format/system_status_update.py +3 -2
  100. biolib/biolib_binary_format/utils.py +175 -0
  101. biolib/biolib_docker_client/__init__.py +11 -2
  102. biolib/biolib_errors.py +36 -0
  103. biolib/biolib_logging.py +27 -10
  104. biolib/cli/__init__.py +38 -0
  105. biolib/cli/auth.py +46 -0
  106. biolib/cli/data_record.py +164 -0
  107. biolib/cli/index.py +32 -0
  108. biolib/cli/init.py +421 -0
  109. biolib/cli/lfs.py +101 -0
  110. biolib/cli/push.py +50 -0
  111. biolib/cli/run.py +63 -0
  112. biolib/cli/runtime.py +14 -0
  113. biolib/cli/sdk.py +16 -0
  114. biolib/cli/start.py +56 -0
  115. biolib/compute_node/cloud_utils/cloud_utils.py +110 -161
  116. biolib/compute_node/job_worker/cache_state.py +66 -88
  117. biolib/compute_node/job_worker/cache_types.py +1 -6
  118. biolib/compute_node/job_worker/docker_image_cache.py +112 -37
  119. biolib/compute_node/job_worker/executors/__init__.py +0 -3
  120. biolib/compute_node/job_worker/executors/docker_executor.py +532 -199
  121. biolib/compute_node/job_worker/executors/docker_types.py +9 -1
  122. biolib/compute_node/job_worker/executors/types.py +19 -9
  123. biolib/compute_node/job_worker/job_legacy_input_wait_timeout_thread.py +30 -0
  124. biolib/compute_node/job_worker/job_max_runtime_timer_thread.py +3 -5
  125. biolib/compute_node/job_worker/job_storage.py +108 -0
  126. biolib/compute_node/job_worker/job_worker.py +397 -212
  127. biolib/compute_node/job_worker/large_file_system.py +87 -38
  128. biolib/compute_node/job_worker/network_alloc.py +99 -0
  129. biolib/compute_node/job_worker/network_buffer.py +240 -0
  130. biolib/compute_node/job_worker/utilization_reporter_thread.py +197 -0
  131. biolib/compute_node/job_worker/utils.py +9 -24
  132. biolib/compute_node/remote_host_proxy.py +400 -98
  133. biolib/compute_node/utils.py +31 -9
  134. biolib/compute_node/webserver/compute_node_results_proxy.py +189 -0
  135. biolib/compute_node/webserver/proxy_utils.py +28 -0
  136. biolib/compute_node/webserver/webserver.py +130 -44
  137. biolib/compute_node/webserver/webserver_types.py +2 -6
  138. biolib/compute_node/webserver/webserver_utils.py +77 -12
  139. biolib/compute_node/webserver/worker_thread.py +183 -42
  140. biolib/experiments/__init__.py +0 -0
  141. biolib/experiments/experiment.py +356 -0
  142. biolib/jobs/__init__.py +1 -0
  143. biolib/jobs/job.py +741 -0
  144. biolib/jobs/job_result.py +185 -0
  145. biolib/jobs/types.py +50 -0
  146. biolib/py.typed +0 -0
  147. biolib/runtime/__init__.py +14 -0
  148. biolib/sdk/__init__.py +91 -0
  149. biolib/tables.py +34 -0
  150. biolib/typing_utils.py +2 -7
  151. biolib/user/__init__.py +1 -0
  152. biolib/user/sign_in.py +54 -0
  153. biolib/utils/__init__.py +162 -0
  154. biolib/utils/cache_state.py +94 -0
  155. biolib/utils/multipart_uploader.py +194 -0
  156. biolib/utils/seq_util.py +150 -0
  157. biolib/utils/zip/remote_zip.py +640 -0
  158. pybiolib-1.2.1890.dist-info/METADATA +41 -0
  159. pybiolib-1.2.1890.dist-info/RECORD +177 -0
  160. {pybiolib-0.2.951.dist-info → pybiolib-1.2.1890.dist-info}/WHEEL +1 -1
  161. pybiolib-1.2.1890.dist-info/entry_points.txt +2 -0
  162. README.md +0 -17
  163. biolib/app/app_result.py +0 -68
  164. biolib/app/utils.py +0 -62
  165. biolib/biolib-js/0-biolib.worker.js +0 -1
  166. biolib/biolib-js/1-biolib.worker.js +0 -1
  167. biolib/biolib-js/2-biolib.worker.js +0 -1
  168. biolib/biolib-js/3-biolib.worker.js +0 -1
  169. biolib/biolib-js/4-biolib.worker.js +0 -1
  170. biolib/biolib-js/5-biolib.worker.js +0 -1
  171. biolib/biolib-js/6-biolib.worker.js +0 -1
  172. biolib/biolib-js/index.html +0 -10
  173. biolib/biolib-js/main-biolib.js +0 -1
  174. biolib/biolib_api_client/biolib_account_api.py +0 -21
  175. biolib/biolib_api_client/biolib_large_file_system_api.py +0 -108
  176. biolib/biolib_binary_format/aes_encrypted_package.py +0 -42
  177. biolib/biolib_binary_format/module_output.py +0 -58
  178. biolib/biolib_binary_format/rsa_encrypted_aes_package.py +0 -57
  179. biolib/biolib_push.py +0 -114
  180. biolib/cli.py +0 -203
  181. biolib/cli_utils.py +0 -273
  182. biolib/compute_node/cloud_utils/enclave_parent_types.py +0 -7
  183. biolib/compute_node/enclave/__init__.py +0 -2
  184. biolib/compute_node/enclave/enclave_remote_hosts.py +0 -53
  185. biolib/compute_node/enclave/nitro_secure_module_utils.py +0 -64
  186. biolib/compute_node/job_worker/executors/base_executor.py +0 -18
  187. biolib/compute_node/job_worker/executors/pyppeteer_executor.py +0 -173
  188. biolib/compute_node/job_worker/executors/remote/__init__.py +0 -1
  189. biolib/compute_node/job_worker/executors/remote/nitro_enclave_utils.py +0 -81
  190. biolib/compute_node/job_worker/executors/remote/remote_executor.py +0 -51
  191. biolib/lfs.py +0 -196
  192. biolib/pyppeteer/.circleci/config.yml +0 -100
  193. biolib/pyppeteer/.coveragerc +0 -3
  194. biolib/pyppeteer/.gitignore +0 -89
  195. biolib/pyppeteer/.pre-commit-config.yaml +0 -28
  196. biolib/pyppeteer/CHANGES.md +0 -253
  197. biolib/pyppeteer/CONTRIBUTING.md +0 -26
  198. biolib/pyppeteer/LICENSE +0 -12
  199. biolib/pyppeteer/README.md +0 -137
  200. biolib/pyppeteer/docs/Makefile +0 -177
  201. biolib/pyppeteer/docs/_static/custom.css +0 -28
  202. biolib/pyppeteer/docs/_templates/layout.html +0 -10
  203. biolib/pyppeteer/docs/changes.md +0 -1
  204. biolib/pyppeteer/docs/conf.py +0 -299
  205. biolib/pyppeteer/docs/index.md +0 -21
  206. biolib/pyppeteer/docs/make.bat +0 -242
  207. biolib/pyppeteer/docs/reference.md +0 -211
  208. biolib/pyppeteer/docs/server.py +0 -60
  209. biolib/pyppeteer/poetry.lock +0 -1699
  210. biolib/pyppeteer/pyppeteer/__init__.py +0 -135
  211. biolib/pyppeteer/pyppeteer/accessibility.py +0 -286
  212. biolib/pyppeteer/pyppeteer/browser.py +0 -401
  213. biolib/pyppeteer/pyppeteer/browser_fetcher.py +0 -194
  214. biolib/pyppeteer/pyppeteer/command.py +0 -22
  215. biolib/pyppeteer/pyppeteer/connection/__init__.py +0 -242
  216. biolib/pyppeteer/pyppeteer/connection/cdpsession.py +0 -101
  217. biolib/pyppeteer/pyppeteer/coverage.py +0 -346
  218. biolib/pyppeteer/pyppeteer/device_descriptors.py +0 -787
  219. biolib/pyppeteer/pyppeteer/dialog.py +0 -79
  220. biolib/pyppeteer/pyppeteer/domworld.py +0 -597
  221. biolib/pyppeteer/pyppeteer/emulation_manager.py +0 -53
  222. biolib/pyppeteer/pyppeteer/errors.py +0 -48
  223. biolib/pyppeteer/pyppeteer/events.py +0 -63
  224. biolib/pyppeteer/pyppeteer/execution_context.py +0 -156
  225. biolib/pyppeteer/pyppeteer/frame/__init__.py +0 -299
  226. biolib/pyppeteer/pyppeteer/frame/frame_manager.py +0 -306
  227. biolib/pyppeteer/pyppeteer/helpers.py +0 -245
  228. biolib/pyppeteer/pyppeteer/input.py +0 -371
  229. biolib/pyppeteer/pyppeteer/jshandle.py +0 -598
  230. biolib/pyppeteer/pyppeteer/launcher.py +0 -683
  231. biolib/pyppeteer/pyppeteer/lifecycle_watcher.py +0 -169
  232. biolib/pyppeteer/pyppeteer/models/__init__.py +0 -103
  233. biolib/pyppeteer/pyppeteer/models/_protocol.py +0 -12460
  234. biolib/pyppeteer/pyppeteer/multimap.py +0 -82
  235. biolib/pyppeteer/pyppeteer/network_manager.py +0 -678
  236. biolib/pyppeteer/pyppeteer/options.py +0 -8
  237. biolib/pyppeteer/pyppeteer/page.py +0 -1728
  238. biolib/pyppeteer/pyppeteer/pipe_transport.py +0 -59
  239. biolib/pyppeteer/pyppeteer/target.py +0 -147
  240. biolib/pyppeteer/pyppeteer/task_queue.py +0 -24
  241. biolib/pyppeteer/pyppeteer/timeout_settings.py +0 -36
  242. biolib/pyppeteer/pyppeteer/tracing.py +0 -93
  243. biolib/pyppeteer/pyppeteer/us_keyboard_layout.py +0 -305
  244. biolib/pyppeteer/pyppeteer/util.py +0 -18
  245. biolib/pyppeteer/pyppeteer/websocket_transport.py +0 -47
  246. biolib/pyppeteer/pyppeteer/worker.py +0 -101
  247. biolib/pyppeteer/pyproject.toml +0 -97
  248. biolib/pyppeteer/spell.txt +0 -137
  249. biolib/pyppeteer/tox.ini +0 -72
  250. biolib/pyppeteer/utils/generate_protocol_types.py +0 -603
  251. biolib/start_cli.py +0 -7
  252. biolib/utils.py +0 -47
  253. biolib/validators/validate_app_version.py +0 -183
  254. biolib/validators/validate_argument.py +0 -134
  255. biolib/validators/validate_module.py +0 -323
  256. biolib/validators/validate_zip_file.py +0 -40
  257. biolib/validators/validator_utils.py +0 -103
  258. pybiolib-0.2.951.dist-info/LICENSE +0 -21
  259. pybiolib-0.2.951.dist-info/METADATA +0 -61
  260. pybiolib-0.2.951.dist-info/RECORD +0 -153
  261. pybiolib-0.2.951.dist-info/entry_points.txt +0 -3
  262. /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
- """