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,401 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
-
4
- """Browser module."""
5
- import asyncio
6
- import logging
7
- from asyncio import Future
8
- from subprocess import Popen
9
- from typing import TYPE_CHECKING, Awaitable, Callable, Dict, List, Optional, Sequence
10
-
11
- from pyee import AsyncIOEventEmitter
12
- from biolib.pyppeteer.pyppeteer.connection import Connection
13
- from biolib.pyppeteer.pyppeteer.errors import BrowserError
14
- from biolib.pyppeteer.pyppeteer.events import Events
15
- from biolib.pyppeteer.pyppeteer.models import Protocol, WebPermission
16
- from biolib.pyppeteer.pyppeteer.target import Target
17
- from biolib.pyppeteer.pyppeteer.task_queue import TaskQueue
18
-
19
- logger = logging.getLogger(__name__)
20
-
21
- if TYPE_CHECKING:
22
- from pyppeteer.page import Page
23
-
24
-
25
- class Browser(AsyncIOEventEmitter):
26
- """Browser class.
27
-
28
- A Browser object is created when pyppeteer connects to chrome, either
29
- through :func:`~pyppeteer.launcher.launch` or
30
- :func:`~pyppeteer.launcher.connect`.
31
- """
32
-
33
- def __init__(
34
- self,
35
- connection: Connection,
36
- contextIds: List[str],
37
- ignoreHTTPSErrors: bool,
38
- defaultViewport: Protocol.Page.Viewport,
39
- process: Optional[Popen] = None,
40
- closeCallback: Callable[[], Awaitable[None]] = None,
41
- ) -> None:
42
- super().__init__()
43
- self._ignoreHTTPSErrors = ignoreHTTPSErrors
44
- self._defaultViewport = defaultViewport
45
- self._process = process
46
- self._screenshotTaskQueue = TaskQueue()
47
- self._connection = connection
48
- self.loop = self._connection.loop
49
-
50
- if closeCallback:
51
- self._closeCallback = closeCallback
52
- else:
53
-
54
- async def _dummy_callback() -> None:
55
- pass
56
-
57
- self._closeCallback = _dummy_callback
58
-
59
- self._defaultContext = BrowserContext(self._connection, self, None)
60
- self._contexts: Dict[str, BrowserContext] = {}
61
- for contextId in contextIds:
62
- self._contexts[contextId] = BrowserContext(self._connection, self, None)
63
-
64
- self._targets: Dict[str, Target] = {}
65
- self._connection.on(Events.Connection.Disconnected, lambda: self.emit(Events.Browser.Disconnected))
66
- self._connection.on(
67
- 'Target.targetCreated', lambda event: self.loop.create_task(self._targetCreated(event)),
68
- )
69
- self._connection.on(
70
- 'Target.targetDestroyed', lambda event: self.loop.create_task(self._targetDestroyed(event)),
71
- )
72
- self._connection.on(
73
- 'Target.targetInfoChanged', lambda event: self.loop.create_task(self._targetInfoChanged(event)),
74
- )
75
-
76
- @property
77
- def process(self) -> Optional[Popen]:
78
- """Return process of this browser.
79
-
80
- If browser instance is created by :func:`pyppeteer.launcher.connect`,
81
- return ``None``.
82
- """
83
- return self._process
84
-
85
- async def createIncognitoBrowserContext(self) -> 'BrowserContext':
86
- """Create a new incognito browser context.
87
-
88
- This won't share cookies/cache with other browser contexts.
89
-
90
- .. code::
91
-
92
- browser = await launch()
93
- # Create a new incognito browser context.
94
- context = await browser.createIncognitoBrowserContext()
95
- # Create a new page in a pristine context.
96
- page = await context.newPage()
97
- # Do stuff
98
- await page.goto('https://example.com')
99
- ...
100
- """
101
- obj = await self._connection.send('Target.createBrowserContext')
102
- browserContextId = obj['browserContextId']
103
- context = BrowserContext(self._connection, self, browserContextId)
104
- self._contexts[browserContextId] = context
105
- return context
106
-
107
- @property
108
- def browserContexts(self) -> List['BrowserContext']:
109
- """Return a list of all open browser contexts.
110
-
111
- In a newly created browser, this will return a single instance of
112
- ``[BrowserContext]``
113
- """
114
- return [self._defaultContext] + [context for context in self._contexts.values()]
115
-
116
- @property
117
- def defaultBrowserContext(self) -> 'BrowserContext':
118
- return self._defaultContext
119
-
120
- async def _disposeContext(self, contextId: str) -> None:
121
- await self._connection.send('Target.disposeBrowserContext', {'browserContextId': contextId,})
122
- self._contexts.pop(contextId, None)
123
-
124
- @staticmethod
125
- async def create(
126
- connection: Connection,
127
- contextIds: List[str],
128
- ignoreHTTPSErrors: bool,
129
- defaultViewport: Protocol.Page.Viewport,
130
- process: Optional[Popen] = None,
131
- closeCallback: Callable[[], Awaitable[None]] = None,
132
- ) -> 'Browser':
133
- """Create browser object."""
134
- browser = Browser(connection, contextIds, ignoreHTTPSErrors, defaultViewport, process, closeCallback)
135
- await connection.send('Target.setDiscoverTargets', {'discover': True})
136
- return browser
137
-
138
- async def _targetCreated(self, event: Dict) -> None:
139
- targetInfo = event['targetInfo']
140
- browserContextId = targetInfo.get('browserContextId')
141
-
142
- if browserContextId and browserContextId in self._contexts:
143
- context = self._contexts[browserContextId]
144
- else:
145
- context = self._defaultContext
146
-
147
- target = Target(
148
- targetInfo=targetInfo,
149
- browserContext=context,
150
- sessionFactory=lambda: self._connection.createSession(targetInfo),
151
- ignoreHTTPSErrors=self._ignoreHTTPSErrors,
152
- defaultViewport=self._defaultViewport,
153
- screenshotTaskQueue=self._screenshotTaskQueue,
154
- loop=self._connection.loop,
155
- )
156
- if targetInfo['targetId'] in self._targets:
157
- raise BrowserError('target should not exist before create.')
158
- self._targets[targetInfo['targetId']] = target
159
- if await target._initializedPromise:
160
- self.emit(Events.Browser.TargetCreated, target)
161
- context.emit(Events.BrowserContext.TargetCreated, target)
162
-
163
- async def _targetDestroyed(self, event: Dict) -> None:
164
- target = self._targets[event['targetId']]
165
- del self._targets[event['targetId']]
166
- target._closedCallback()
167
- if await target._initializedPromise:
168
- self.emit(Events.Browser.TargetDestroyed, target)
169
- target.browserContext.emit(Events.BrowserContext.TargetDestroyed, target)
170
- target._initializedCallback(False)
171
-
172
- async def _targetInfoChanged(self, event: Dict) -> None:
173
- target = self._targets.get(event['targetInfo']['targetId'])
174
- if not target:
175
- raise BrowserError('target should exist before targetInfoChanged')
176
- previousURL = target.url
177
- wasInitialized = target._isInitialized
178
- target._targetInfoChanged(event['targetInfo'])
179
- if wasInitialized and previousURL != target.url:
180
- self.emit(Events.Browser.TargetChanged, target)
181
- target.browserContext.emit(Events.BrowserContext.TargetChanged, target)
182
-
183
- @property
184
- def wsEndpoint(self) -> str:
185
- """Return websocket end point url."""
186
- return self._connection.url
187
-
188
- async def newPage(self) -> 'Page':
189
- """Make new page on this browser and return its object."""
190
- return await self._defaultContext.newPage()
191
-
192
- async def _createPageInContext(self, contextId: Optional[str]) -> 'Page':
193
- options = {'url': 'about:blank'}
194
- if contextId:
195
- options['browserContextId'] = contextId
196
-
197
- targetId = (await self._connection.send('Target.createTarget', options)).get('targetId')
198
- target = self._targets.get(targetId)
199
- if target is None or not await target._initializedPromise:
200
- raise BrowserError('Failed to create target for page.')
201
- page = await target.page()
202
- if page is None:
203
- raise BrowserError('Failed to create page.')
204
- return page
205
-
206
- def targets(self) -> List[Target]:
207
- """Get a list of all active targets inside the browser.
208
-
209
- In case of multiple browser contexts, this will return a list
210
- with all the targets in all browser contexts.
211
- """
212
- return [target for target in self._targets.values() if target._isInitialized]
213
-
214
- @property
215
- def target(self) -> Target:
216
- """get active browser target"""
217
- return next((target for target in self.targets() if target.type == 'browser'))
218
-
219
- async def waitForTarget(self, predicate: Callable[[Target], bool], timeout: float = 30_000) -> Target:
220
- """
221
- Wait for target that matches predicate function.
222
- :param predicate: function that takes 1 argument of Target object
223
- :param timeout: how long to wait for target in milliseconds,
224
- TimeoutError will be raised otherwise
225
- """
226
- if timeout: # js uses ms while asyncio uses seconds
227
- timeout = timeout / 1_000
228
- existing_target = [target for target in self.targets() if predicate(target)]
229
- if existing_target:
230
- return existing_target[0]
231
-
232
- result_fut: Future[Target] = self.loop.create_future()
233
-
234
- def check(target: Target) -> None:
235
- if predicate(target):
236
- result_fut.set_result(target)
237
-
238
- self.on(Events.Browser.TargetCreated, check)
239
- self.on(Events.Browser.TargetChanged, check)
240
- result = await asyncio.wait_for(result_fut, timeout=timeout)
241
- self.remove_listener(Events.Browser.TargetCreated, check)
242
- self.remove_listener(Events.Browser.TargetChanged, check)
243
- return result
244
-
245
- @property
246
- async def pages(self) -> List['Page']:
247
- """Get all pages of this browser.
248
-
249
- Non visible pages, such as ``"background_page"``, will not be listed
250
- here. You can find then using :meth:`pyppeteer.target.Target.page`.
251
-
252
- In case of multiple browser contexts, this method will return a list
253
- with all the pages in all browser contexts.
254
- """
255
- pages = await asyncio.gather(*[context.pages() for context in self.browserContexts])
256
- return [p for ps in pages for p in ps]
257
-
258
- async def version(self) -> str:
259
- """Get version of the browser."""
260
- version = await self._getVersion()
261
- return version['product']
262
-
263
- async def userAgent(self) -> str:
264
- """Return browser's original user agent.
265
-
266
- .. note::
267
- Pages can override browser user agent with
268
- :meth:`pyppeteer.page.Page.setUserAgent`.
269
- """
270
- version = await self._getVersion()
271
- return version.get('userAgent', '')
272
-
273
- async def close(self) -> None:
274
- """Close connections and terminate browser process."""
275
- await self._closeCallback()
276
- await self.disconnect()
277
-
278
- async def disconnect(self) -> None:
279
- """Disconnect browser."""
280
- await self._connection.dispose()
281
-
282
- @property
283
- def isConnected(self) -> bool:
284
- return not self._connection._closed
285
-
286
- def _getVersion(self) -> Awaitable:
287
- return self._connection.send('Browser.getVersion')
288
-
289
-
290
- class BrowserContext(AsyncIOEventEmitter):
291
- """BrowserContext provides multiple independent browser sessions.
292
-
293
- When a browser is launched, it has a single BrowserContext used by default.
294
- The method `browser.newPage()` creates a page in the default browser
295
- context.
296
-
297
- If a page opens another page, e.g. with a ``window.open`` call, the popup
298
- will belong to the parent page's browser context.
299
-
300
- Pyppeteer allows creation of "incognito" browser context with
301
- ``browser.createIncognitoBrowserContext()`` method.
302
- "incognito" browser contexts don't write any browser data to disk.
303
-
304
- .. code::
305
-
306
- # Create new incognito browser context
307
- context = await browser.createIncognitoBrowserContext()
308
- # Create a new page inside context
309
- page = await context.newPage()
310
- # ... do stuff with page ...
311
- await page.goto('https://example.com')
312
- # Dispose context once it's no longer needed
313
- await context.close()
314
- """
315
-
316
- def __init__(self, connection: Connection, browser: Browser, contextId: Optional[str]) -> None:
317
- super().__init__()
318
- self._connection = connection
319
- self._browser = browser
320
- self._id = contextId
321
-
322
- def targets(self) -> List[Target]:
323
- """Return a list of all active targets inside the browser context."""
324
- targets = []
325
- for target in self._browser.targets():
326
- if target.browserContext == self:
327
- targets.append(target)
328
- return targets
329
-
330
- async def pages(self) -> List['Page']:
331
- """Return list of all open pages.
332
-
333
- Non-visible pages, such as ``"background_page"``, will not be listed
334
- here. You can find them using :meth:`pyppeteer.target.Target.page`.
335
- """
336
- pages = [target.page() for target in self.targets() if target.type == 'page']
337
- return [page for page in await asyncio.gather(*pages) if page]
338
-
339
- def isIncognito(self) -> bool:
340
- """Return whether BrowserContext is incognito.
341
-
342
- The default browser context is the only non-incognito browser context.
343
-
344
- .. note::
345
- The default browser context cannot be closed.
346
- """
347
- return bool(self._id)
348
-
349
- async def overridePermissions(self, origin: str, permissions: Sequence[WebPermission]) -> None:
350
- web_perm_to_protocol = {
351
- 'geolocation': 'geolocation',
352
- 'midi': 'midi',
353
- 'notifications': 'notifications',
354
- 'push': 'push',
355
- 'camera': 'videoCapture',
356
- 'microphone': 'audioCapture',
357
- 'background-sync': 'backgroundSync',
358
- 'ambient-light-sensor': 'sensors',
359
- 'accelerometer': 'sensors',
360
- 'gyroscope': 'sensors',
361
- 'magnetometer': 'sensors',
362
- 'accessibility-events': 'accessibilityEvents',
363
- 'clipboard-read': 'clipboardRead',
364
- 'clipboard-write': 'clipboardWrite',
365
- 'payment-handler': 'paymentHandler',
366
- # chrome specific
367
- 'midi-sysex': 'midiSysex',
368
- }
369
- protocol_perms = []
370
- for perm in permissions:
371
- protocol_perm = web_perm_to_protocol.get(perm)
372
- if protocol_perm is None:
373
- raise RuntimeError(f'Unknown permission: {perm}')
374
- protocol_perms.append(perm)
375
- await self._connection.send(
376
- 'Browser.grantPermissions', {'origin': origin, 'browserContextId': self._id, 'permissions': permissions}
377
- )
378
-
379
- async def clearPermissionOverrides(self) -> None:
380
- await self._connection.send('Browser.resetPermissions', {'browserContextId': self._id})
381
-
382
- async def newPage(self) -> 'Page':
383
- """Create a new page in the browser context."""
384
- return await self._browser._createPageInContext(self._id)
385
-
386
- @property
387
- def browser(self) -> Browser:
388
- """Return the browser this browser context belongs to."""
389
- return self._browser
390
-
391
- async def close(self) -> None:
392
- """Close the browser context.
393
-
394
- All the targets that belongs to the browser context will be closed.
395
-
396
- .. note::
397
- Only incognito browser context can be closed.
398
- """
399
- if self._id is None:
400
- raise BrowserError('Non-incognito profile cannot be closed')
401
- await self._browser._disposeContext(self._id)
@@ -1,194 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
-
4
- """
5
- Browser fetcher module.
6
- Chromium is being downloaded from:
7
- https://storage.googleapis.com/chromium-browser-snapshots
8
- see full download instructions:
9
- https://www.chromium.org/getting-involved/download-chromium
10
- for latest version see:
11
- https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Linux_x64%2FLAST_CHANGE?alt=media
12
- """
13
-
14
- import logging
15
- import os
16
- import shutil
17
- import struct
18
- import sys
19
- from distutils.util import strtobool
20
- from io import BytesIO
21
- from pathlib import Path
22
- from typing import Any, List, Optional, Sequence, Tuple, Union, cast
23
- from urllib import request
24
- from zipfile import ZipFile
25
- import encodings.cp437
26
-
27
- import certifi
28
- import urllib3
29
- from tqdm import tqdm
30
-
31
- from biolib.pyppeteer.pyppeteer import __chromium_revision__, __pyppeteer_home__
32
- from biolib.pyppeteer.pyppeteer.models import Platform, RevisionInfo
33
-
34
- if sys.version_info < (3, 8):
35
- from typing_inspect import get_args
36
- else:
37
- from typing import get_args
38
-
39
- logger = logging.getLogger(__name__)
40
-
41
- DEFAULT_DOWNLOAD_HOST = 'https://storage.googleapis.com'
42
- DOWNLOAD_HOST = os.environ.get('PYPPETEER_DOWNLOAD_HOST', DEFAULT_DOWNLOAD_HOST)
43
-
44
-
45
- def get_archive_name(platform: Platform, revision: str) -> str:
46
- if platform == 'linux':
47
- return 'chrome-linux'
48
- if platform == 'mac':
49
- return 'chrome-mac'
50
- if platform in ('win32', 'win64'):
51
- return 'chrome-win' if int(revision) > 591479 else 'chrome-win32'
52
- raise ValueError(f'Unsupported platform argument: {platform}')
53
-
54
-
55
- def download_url(platform: Platform, host: str, revision: str) -> str:
56
- windows_archive = 'chrome-win' if int(revision) > 591479 else 'chrome-win32'
57
-
58
- base_url = f'{host}/chromium-browser-snapshots'
59
- download_urls = {
60
- 'linux': f'{base_url}/Linux_x64/{revision}/chrome-linux.zip',
61
- 'mac': f'{base_url}/Mac/{revision}/chrome-mac.zip',
62
- 'win32': f'{base_url}/Win/{revision}/{windows_archive}.zip',
63
- 'win64': f'{base_url}/Win_x64/{revision}/{windows_archive}.zip',
64
- }
65
-
66
- return download_urls[platform]
67
-
68
-
69
- def parse_folder_path(folder_path: Path) -> Tuple[Optional[str], Optional[str]]:
70
- name = folder_path.name
71
- splits: Sequence[Any] = name.split('-')
72
- if len(splits) != 2 or splits[0] not in get_args(Platform): # type: ignore
73
- splits = (None, None)
74
- return cast(Tuple[Optional[str], Optional[str]], tuple(splits))
75
-
76
-
77
- def download_file(url: str, zip_path: BytesIO) -> None:
78
- CHUNK_SIZE = 4096
79
- file_req = request.urlopen(url)
80
- NO_PROGRESS_BAR = bool(strtobool(os.environ.get('PYPPETEER_NO_PROGRESS_BAR', 'false')))
81
-
82
-
83
- progress_bar = tqdm(
84
- total=int(file_req.getheader('Content-Length', 0)),
85
- unit="B",
86
- unit_scale=True,
87
- unit_divisor=1024,
88
- disable=NO_PROGRESS_BAR,
89
- )
90
- for chunk in iter(lambda: file_req.read(CHUNK_SIZE), b''):
91
- progress_bar.update(CHUNK_SIZE)
92
- zip_path.write(chunk)
93
- progress_bar.close()
94
-
95
-
96
- def extractZip(zip_file: BytesIO, folder_path: Path) -> None:
97
- with ZipFile(zip_file) as zf:
98
- zf.extractall(folder_path)
99
-
100
-
101
- class BrowserFetcher:
102
- def __init__(
103
- self, projectRoot: Union[Path, str] = None, platform: Platform = None, host: str = None,
104
- ):
105
- self.downloadsFolder = Path(projectRoot or __pyppeteer_home__) / 'local-chromium'
106
- self.downloadHost = host or DEFAULT_DOWNLOAD_HOST
107
- plat = platform or sys.platform # type: ignore
108
- if plat == 'darwin':
109
- plat = 'mac'
110
- elif plat == 'win32':
111
- # no really good way to detect system bittedness
112
- # (other options depend on the python interpreter bittedness == sys.bittedness)
113
- plat = plat.replace('32', str(struct.calcsize('P') * 8))
114
- assert plat in get_args(Platform), f'Unsupported platform: {platform}' # type: ignore
115
- logger.info(f'platform auto detected: {plat}')
116
- self._platform = cast(Platform, plat)
117
-
118
- @property
119
- def platform(self) -> Platform:
120
- return self._platform
121
-
122
- def canDownload(self, revision: str) -> bool:
123
- url = download_url(self.platform, self.downloadHost, revision)
124
- return request.urlopen(request.Request(url, method='HEAD')) == 200
125
-
126
- def download(self, revision: Optional[str] = None) -> RevisionInfo:
127
- revision = revision or os.environ.get('PYPPETEER_CHROMIUM_REVISION') or __chromium_revision__
128
- url = download_url(self.platform, self.downloadHost, revision)
129
- folder_path = self._get_folder_path(revision)
130
- if folder_path.exists():
131
- return self.revision_info(revision)
132
- os.makedirs(self.downloadsFolder, exist_ok=True)
133
- with BytesIO() as zip_file_obj:
134
- download_file(url, zip_file_obj)
135
- extractZip(zip_file_obj, folder_path)
136
- revision_info = self.revision_info(revision)
137
- if revision_info:
138
- os.chmod(revision_info['executablePath'], 0o755)
139
- return revision_info
140
-
141
- def local_revisions(self) -> List[Path]:
142
- if not self.downloadsFolder.exists():
143
- return []
144
- result = []
145
- for file in [x for x in self.downloadsFolder.iterdir() if x.is_dir()]:
146
- platform, revision = parse_folder_path(file)
147
- if platform != self._platform or not revision:
148
- continue
149
- result.append(Path(revision))
150
- return result
151
-
152
- def remove(self, revision: str) -> None:
153
- f_path = self._get_folder_path(revision)
154
- assert f_path.exists(), f'Failed to remove: revision {revision} doesn\'t exist on the disk'
155
- shutil.rmtree(f_path)
156
-
157
- def revision_info(self, revision: str) -> RevisionInfo:
158
- folder_path = self._get_folder_path(revision)
159
-
160
- archive_name = get_archive_name(self._platform, revision)
161
- if self._platform == 'mac':
162
- executable_path = folder_path / archive_name / 'Chromium.app' / 'Contents' / 'MacOS' / 'Chromium'
163
- elif self._platform == 'linux':
164
- executable_path = folder_path / archive_name / 'chrome'
165
- elif self._platform in ('win32', 'win64'):
166
- executable_path = folder_path / archive_name / 'chrome.exe'
167
- else:
168
- raise RuntimeError(f'Unsupported platform: {self._platform}')
169
-
170
- url = download_url(self._platform, self.downloadHost, revision)
171
- local = folder_path.exists()
172
-
173
- return {
174
- 'revision': revision,
175
- 'executablePath': executable_path,
176
- 'folderPath': folder_path,
177
- 'local': local,
178
- 'url': url,
179
- }
180
-
181
- def _get_folder_path(self, revision: str) -> Path:
182
- return self.downloadsFolder.joinpath(f'{self._platform}-{revision}')
183
-
184
- def can_download(self, revision: str) -> bool:
185
- url = download_url(self._platform, self.downloadHost, revision)
186
- http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where())
187
-
188
- try:
189
- res = http.request('HEAD', url)
190
- except urllib3.exceptions.HTTPError as error:
191
- logger.error(error)
192
- return False
193
-
194
- return res.status == 200
@@ -1,22 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
-
4
- """Commands for Pyppeteer."""
5
- import argparse
6
-
7
- from biolib.pyppeteer.pyppeteer.browser_fetcher import BrowserFetcher
8
-
9
-
10
- def install() -> None:
11
- """Download and Chromium/Firefox to specified folder"""
12
- #parser = argparse.ArgumentParser(description=install.__doc__)
13
- #parser.add_argument('-r', '--revision', action="store", type=str, default=None)
14
- #parser.add_argument('-p', '--product', action="store", type=str, default=None)
15
- #parser.add_argument('-l', '--location', action="store")
16
- #parsed = parser.parse_args()
17
- dl = BrowserFetcher(None) #parsed.location)
18
- dl.download(None) #parsed.revision)
19
-
20
-
21
- if __name__ == '__main__':
22
- install()