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,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()
|