intuned-runtime 1.1.0__py3-none-any.whl → 1.1.2__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.
@@ -3,7 +3,7 @@ import os
3
3
 
4
4
  import arguably
5
5
 
6
- from runtime.browser import launch_chromium
6
+ from runtime.browser import launch_browser
7
7
  from runtime.browser.storage_state import get_storage_state
8
8
 
9
9
 
@@ -21,7 +21,7 @@ async def browser__save_state(
21
21
  output_path (str): Path to save browser state to.
22
22
  """
23
23
 
24
- async with launch_chromium(
24
+ async with launch_browser(
25
25
  cdp_address=cdp_address,
26
26
  ) as (context, _):
27
27
  storage_state = await get_storage_state(context)
@@ -3,7 +3,7 @@ import os
3
3
 
4
4
  import arguably
5
5
 
6
- from runtime.browser import launch_chromium
6
+ from runtime.browser import launch_browser
7
7
  from runtime.browser.storage_state import set_storage_state
8
8
  from runtime.run.intuned_settings import load_intuned_settings
9
9
  from runtime.types.run_types import StorageState
@@ -26,7 +26,7 @@ async def project__auth_session__load(
26
26
  if not intuned_settings.auth_sessions.enabled:
27
27
  raise Exception("Auth sessions are not enabled")
28
28
 
29
- async with launch_chromium(
29
+ async with launch_browser(
30
30
  cdp_address=cdp_address,
31
31
  ) as (context, _):
32
32
  auth_session_path = os.path.join(os.getcwd(), auth_session_path)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: intuned-runtime
3
- Version: 1.1.0
3
+ Version: 1.1.2
4
4
  Summary: Runtime commands for Intuned platform Python scrapers
5
5
  License: Elastic-2.0
6
6
  Keywords: runtime,intuned
@@ -17,6 +17,8 @@ Classifier: Programming Language :: Python :: 3.12
17
17
  Classifier: Programming Language :: Python :: 3.13
18
18
  Requires-Dist: aiofiles (>=24.1.0,<25.0.0)
19
19
  Requires-Dist: arguably (>=1.3.0,<2.0.0)
20
+ Requires-Dist: browserforge[all]
21
+ Requires-Dist: camoufox[geoip] (>=0.4.11,<0.5.0)
20
22
  Requires-Dist: gitpython (>=3.1.43,<4.0.0)
21
23
  Requires-Dist: httpx (>=0.23.0,<1)
22
24
  Requires-Dist: more-termcolor (>=1.1.3,<2.0.0)
@@ -40,13 +40,13 @@ intuned_internal_cli/commands/ai_source/__init__.py,sha256=lg7owgcK8owNn2a4VBUP9
40
40
  intuned_internal_cli/commands/ai_source/ai_source.py,sha256=2woQtCmhxKvLfEz832eUoCT9gMsuSvEE6rMnHSYXC7w,138
41
41
  intuned_internal_cli/commands/ai_source/deploy.py,sha256=NpomuP_2mo5SLKe7BZoY5H0Pp36aDtkYU_CyihqOvdI,2457
42
42
  intuned_internal_cli/commands/browser/__init__.py,sha256=AuVbvh7aSBTFKYvewXZyPoIvfBTe2uHiPcnaAkzapas,95
43
- intuned_internal_cli/commands/browser/save_state.py,sha256=eHKfvBfeFR_U9VQbsjOnIZjWepyDjNn9NL3naDYWP2s,841
43
+ intuned_internal_cli/commands/browser/save_state.py,sha256=_gfspwLkk6j1zBzqY1Qr7KnEMjGP6x10Q2IvKdfjyuI,839
44
44
  intuned_internal_cli/commands/init.py,sha256=8rWBenWZfwNtLxOBqhEMbOATyQNEnmDUmrFJ1xBGyxI,4384
45
45
  intuned_internal_cli/commands/project/__init__.py,sha256=t97wvhSenerYRdbSeCKXqHASA6EWA3lc1hnRhF9baOE,734
46
46
  intuned_internal_cli/commands/project/auth_session/__init__.py,sha256=gt7mlaW6xmqAc_4-pfF_FiecsR51C6fqCaq_NFbcbwA,300
47
47
  intuned_internal_cli/commands/project/auth_session/check.py,sha256=AFILp7m34nAO_RD3IfRpuJm5Zh0wnCRtBXqIrerdbwo,4565
48
48
  intuned_internal_cli/commands/project/auth_session/create.py,sha256=r-eYu3uLUo2mzF836CbVgu4oBzcIIDekzzFwwekxmg0,3374
49
- intuned_internal_cli/commands/project/auth_session/load.py,sha256=UUvg9Vyj15xiR44XlJzojLoFm5esv-o4E3qA3JqnBsE,1201
49
+ intuned_internal_cli/commands/project/auth_session/load.py,sha256=Y0V6bFZQeHq_lTtR-rQvM9SSbExWhVVMFu-Uykl-9k4,1199
50
50
  intuned_internal_cli/commands/project/project.py,sha256=_MSh6Xor2Cbh-ItifwgOPq_BP8UDuKB7S6w796FULKQ,137
51
51
  intuned_internal_cli/commands/project/run.py,sha256=FDYYkU24aURYbljyYLFo8wLF-nvb86EVr9gMEjAfeE0,12274
52
52
  intuned_internal_cli/commands/project/run_interface.py,sha256=4RyR8WZriIF7Va4z1wt-q6zZDQOI31n62Ho2dyimzUY,8717
@@ -63,12 +63,15 @@ runtime/__init__.py,sha256=87gDXuxUv_kGzQfuB1mh6DF-dDysJN8r684c7jGnHxc,144
63
63
  runtime/backend_functions/__init__.py,sha256=j2EaK4FK8bmdFtqc5FxtFwx1KhIn_7qKPChrrAhJI3s,119
64
64
  runtime/backend_functions/_call_backend_function.py,sha256=zuaf4mwYHSm5RTedhMdU66jAMAzdPYPMmXJE_V1xoyk,2869
65
65
  runtime/backend_functions/get_auth_session_parameters.py,sha256=pOvB7XiWpphEuBpazdKALw9EWgBU1PeY3gkzBfVLpkc,869
66
- runtime/browser/__init__.py,sha256=CRBpMS319LBz2FLxDjjCvQdOUCgHLIrQFscr_Zi5Hm0,160
67
- runtime/browser/launch_chromium.py,sha256=OVaE8ezjxCYA1NUSDdd3FczrfNCpG_528Vmsv4S6QGU,7916
66
+ runtime/browser/__init__.py,sha256=EPWfa4ZmdR8GJqh2qcsx1ZvHmCYiUYrQ-zeHYVapH9s,285
67
+ runtime/browser/helpers.py,sha256=b1Xp005adbl7ZeJrSEYgH2OPzrZEHxTPgGTsnS3OqS0,554
68
+ runtime/browser/launch_browser.py,sha256=f71hLUDbIBEv5hhQVOQFTXleUm_X1kmEpp0kTx0SqZo,966
69
+ runtime/browser/launch_camoufox.py,sha256=TBOAwwipNGlbtMdFYnGkVM0ppLU44vWNkMGZA5uPZCE,1787
70
+ runtime/browser/launch_chromium.py,sha256=QY9Mxw8FImT_W23cT2zjTAeLvApzVHA_YSu0b77nfeA,7813
68
71
  runtime/browser/storage_state.py,sha256=fwLg8sP-H-vgt_6AJKNl03CpgyMVCQWWcN2cqswTQMs,3603
69
72
  runtime/context/__init__.py,sha256=hg8ejm4bJy4tNkwmZ9lKgYJx6bU7OgOdBS684Uv5XGg,73
70
73
  runtime/context/context.py,sha256=pl_0x77_d5CiAznz1qGSk6o9cW-msNvlCt-2eFoMKlA,1739
71
- runtime/env.py,sha256=h4BJI-XVSZKgtTxjkzj2HsyN3DlY5Ml9GZqeH4CKDE8,238
74
+ runtime/env.py,sha256=OXxzLpM56AJVlX0gmG7Ph82xAfqZboW3kv2232lzXb4,306
72
75
  runtime/errors/__init__.py,sha256=oqiBSvT_yFLQ3hG0AbCUA3WYFaxkTDVkDMSy59xvBCo,688
73
76
  runtime/errors/auth_session_errors.py,sha256=6b4XTI8UCDHDPX4jEA8_HyrNUp4VZ1TrEA8DRh6Z3rM,228
74
77
  runtime/errors/run_api_errors.py,sha256=LdmOEHoUk7wjWSk0HQYqslfJNNmxVgga_0bankzvX-s,3341
@@ -80,7 +83,7 @@ runtime/helpers/get_auth_session_parameters.py,sha256=7bopGhJ7vjKAn_UxnHSAah-k2r
80
83
  runtime/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
84
  runtime/run/__init__.py,sha256=zxMYVb7hn147YTrhMLsrcX6-KTd71HLrYHstJOWeWXQ,52
82
85
  runtime/run/intuned_settings.py,sha256=vy2-ktEzUfUp5Z90dp3l7jPKHNjgB-8GSMDgAY-rYaU,1074
83
- runtime/run/playwright_constructs.py,sha256=UZvP502fk4Hk8xtI9jMlyJ7jHLJsWt2SZyZjhet7L1A,576
86
+ runtime/run/playwright_constructs.py,sha256=EIfnRlAi1k1wRiTT2OpPFVmrWwEeeiryuORibaLD1Xw,573
84
87
  runtime/run/pydantic_encoder.py,sha256=wJCljwwINSICvCJ0i2izp2RLkQ15nYglUQCyyjM40Jk,332
85
88
  runtime/run/run_api.py,sha256=iYekBi-mkBuBNvLIBXQ6RWvEDN7JhjSlX3i7a2td2P8,8952
86
89
  runtime/run/traces.py,sha256=fKzh11LqV47ujgq_9I2tdp-dgld566wffWaHwU_4gis,1123
@@ -89,8 +92,8 @@ runtime/types/payload.py,sha256=sty8HgDEn3nJbZrwEOMCXyuG7_ICGDwlBIIWSON5ABY,124
89
92
  runtime/types/run_types.py,sha256=-j-XKXfRkzlyoW-Doe0og2jbqMMQWjOTIUqRFEc8lHA,4582
90
93
  runtime_helpers/__init__.py,sha256=XBrEiE9yNC8Lgn8NgIkqNXbI6e4ap237E83Zj_nlhCQ,249
91
94
  runtime_helpers/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
- intuned_runtime-1.1.0.dist-info/LICENSE,sha256=9LIjQdgyU_ptzNIfItNCR7VmEHqYnrY1f1XwOreKFI0,3714
93
- intuned_runtime-1.1.0.dist-info/METADATA,sha256=SO-KZ2dpNlLDzqEQBZcOMC8_oie3r2wyw2D9ZSigXWQ,5217
94
- intuned_runtime-1.1.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
95
- intuned_runtime-1.1.0.dist-info/entry_points.txt,sha256=ToMS2cqDeRmF1FGkflwoeD-Xz6jJV5p1zIbw9G7IxMg,85
96
- intuned_runtime-1.1.0.dist-info/RECORD,,
95
+ intuned_runtime-1.1.2.dist-info/LICENSE,sha256=9LIjQdgyU_ptzNIfItNCR7VmEHqYnrY1f1XwOreKFI0,3714
96
+ intuned_runtime-1.1.2.dist-info/METADATA,sha256=HP4J-g2b6h37GwRyjtMffGhuHNP1yQfJogzxfr_aiHc,5299
97
+ intuned_runtime-1.1.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
98
+ intuned_runtime-1.1.2.dist-info/entry_points.txt,sha256=ToMS2cqDeRmF1FGkflwoeD-Xz6jJV5p1zIbw9G7IxMg,85
99
+ intuned_runtime-1.1.2.dist-info/RECORD,,
@@ -1,4 +1,6 @@
1
+ from .launch_browser import launch_browser
2
+ from .launch_camoufox import launch_camoufox
1
3
  from .launch_chromium import dangerous_launch_chromium
2
4
  from .launch_chromium import launch_chromium
3
5
 
4
- __all__ = ["launch_chromium", "dangerous_launch_chromium"]
6
+ __all__ = ["launch_chromium", "dangerous_launch_chromium", "launch_camoufox", "launch_browser"]
@@ -0,0 +1,21 @@
1
+ import os
2
+ from typing import Optional
3
+ from typing import TYPE_CHECKING
4
+
5
+ from playwright.async_api import ProxySettings
6
+
7
+ if TYPE_CHECKING:
8
+ from playwright.async_api import ProxySettings
9
+
10
+
11
+ def get_proxy_env() -> Optional["ProxySettings"]:
12
+ server = os.getenv("PROXY_SERVER")
13
+ username = os.getenv("PROXY_USERNAME")
14
+ password = os.getenv("PROXY_PASSWORD")
15
+ if server is None or username is None or password is None:
16
+ return None
17
+ return {
18
+ "server": server,
19
+ "username": username,
20
+ "password": password,
21
+ }
@@ -0,0 +1,31 @@
1
+ from contextlib import asynccontextmanager
2
+
3
+ from playwright.async_api import ProxySettings
4
+
5
+ from runtime.env import get_browser_type
6
+
7
+ from .launch_camoufox import launch_camoufox
8
+ from .launch_chromium import launch_chromium
9
+
10
+
11
+ @asynccontextmanager
12
+ async def launch_browser(
13
+ proxy: ProxySettings | None = None,
14
+ headless: bool = False,
15
+ *,
16
+ cdp_address: str | None = None,
17
+ ):
18
+ browser_type = get_browser_type()
19
+ match browser_type:
20
+ case "camoufox":
21
+ async with launch_camoufox(headless=headless, proxy=proxy) as (context, page):
22
+ try:
23
+ yield context, page
24
+ finally:
25
+ await context.close()
26
+ case "chromium" | _:
27
+ async with launch_chromium(headless=headless, cdp_address=cdp_address, proxy=proxy) as (context, page):
28
+ try:
29
+ yield context, page
30
+ finally:
31
+ await context.close()
@@ -0,0 +1,63 @@
1
+ import logging
2
+ import os
3
+ from contextlib import asynccontextmanager
4
+ from typing import Any
5
+ from typing import AsyncGenerator
6
+ from typing import Tuple
7
+
8
+ import anyio
9
+ from playwright.async_api import Browser
10
+ from playwright.async_api import BrowserContext
11
+ from playwright.async_api import Page
12
+
13
+ from .helpers import get_proxy_env
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ async def create_user_dir():
19
+ # Create a temporary directory
20
+ playwright_temp_dir = anyio.Path(await anyio.mkdtemp(prefix="pw-"))
21
+ user_dir = playwright_temp_dir / "userdir"
22
+
23
+ return await user_dir.absolute()
24
+
25
+
26
+ @asynccontextmanager
27
+ async def launch_camoufox(
28
+ headless: bool = True,
29
+ timeout: int = 10,
30
+ **kwargs: Any,
31
+ ) -> AsyncGenerator[Tuple[BrowserContext, Page], None]:
32
+ from camoufox.async_api import AsyncCamoufox
33
+
34
+ dir = await create_user_dir()
35
+ if kwargs.get("proxy") is None:
36
+ proxy_env = get_proxy_env()
37
+ else:
38
+ proxy_env = kwargs.get("proxy")
39
+ kwargs.pop("proxy", None)
40
+ async with AsyncCamoufox(
41
+ main_world_eval=True,
42
+ headless=headless,
43
+ config={"forceScopeAccess": True}, # required
44
+ disable_coop=True,
45
+ geoip=True,
46
+ proxy=proxy_env,
47
+ persistent_context=True,
48
+ user_data_dir=dir,
49
+ i_know_what_im_doing=True,
50
+ ) as camoufox:
51
+ if isinstance(camoufox, Browser):
52
+ context = await camoufox.new_context()
53
+ else:
54
+ context = camoufox
55
+ context.set_default_timeout(timeout * 1000)
56
+
57
+ async def remove_dir_after_close(*_: Any, **__: Any) -> None:
58
+ if not dir:
59
+ return
60
+ os.system(f"rm -rf {os.path.realpath(dir)}")
61
+
62
+ context.once("close", remove_dir_after_close)
63
+ yield context, context.pages[0]
@@ -4,30 +4,14 @@ import logging
4
4
  import os
5
5
  from contextlib import asynccontextmanager
6
6
  from typing import Any
7
- from typing import Optional
8
- from typing import TYPE_CHECKING
9
7
 
10
8
  import anyio
11
9
 
12
- if TYPE_CHECKING:
13
- from playwright.async_api import ProxySettings
10
+ from .helpers import get_proxy_env
14
11
 
15
12
  logger = logging.getLogger(__name__)
16
13
 
17
14
 
18
- def get_proxy_env() -> Optional["ProxySettings"]:
19
- server = os.getenv("PROXY_SERVER")
20
- username = os.getenv("PROXY_USERNAME")
21
- password = os.getenv("PROXY_PASSWORD")
22
- if server is None or username is None or password is None:
23
- return None
24
- return {
25
- "server": server,
26
- "username": username,
27
- "password": password,
28
- }
29
-
30
-
31
15
  chromium_launch_args_to_ignore = [
32
16
  "--disable-field-trial-config",
33
17
  "--disable-background-networking",
@@ -85,16 +69,6 @@ async def create_user_dir_with_preferences():
85
69
  return await user_dir.absolute(), await playwright_temp_dir.absolute()
86
70
 
87
71
 
88
- extra_args = [
89
- "--no-first-run",
90
- "--disable-sync",
91
- "--disable-translate",
92
- "--disable-features=TranslateUI",
93
- "--disable-features=NetworkService",
94
- "--lang=en",
95
- "--disable-blink-features=AutomationControlled",
96
- ]
97
-
98
72
  default_user_agent = (
99
73
  "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36"
100
74
  )
@@ -110,6 +84,15 @@ async def launch_chromium(
110
84
  from playwright.async_api import async_playwright
111
85
  from playwright.async_api import Browser
112
86
 
87
+ extra_args = [
88
+ "--no-first-run",
89
+ "--disable-sync",
90
+ "--disable-translate",
91
+ "--disable-features=TranslateUI",
92
+ "--disable-features=NetworkService",
93
+ "--lang=en",
94
+ "--disable-blink-features=AutomationControlled",
95
+ ]
113
96
  async with async_playwright() as playwright:
114
97
  if cdp_address is not None:
115
98
  browser: Browser = await playwright.chromium.connect_over_cdp(cdp_address)
@@ -117,7 +100,10 @@ async def launch_chromium(
117
100
  user_preferences_dir = None
118
101
  dir_to_clean = None
119
102
  else:
120
- user_preferences_dir, dir_to_clean = await create_user_dir_with_preferences()
103
+ (
104
+ user_preferences_dir,
105
+ dir_to_clean,
106
+ ) = await create_user_dir_with_preferences()
121
107
  if kwargs.get("proxy") is None:
122
108
  proxy_env = get_proxy_env()
123
109
  else:
@@ -172,6 +158,15 @@ async def dangerous_launch_chromium(
172
158
  from playwright.async_api import async_playwright
173
159
  from playwright.async_api import Browser
174
160
 
161
+ extra_args = [
162
+ "--no-first-run",
163
+ "--disable-sync",
164
+ "--disable-translate",
165
+ "--disable-features=TranslateUI",
166
+ "--disable-features=NetworkService",
167
+ "--lang=en",
168
+ "--disable-blink-features=AutomationControlled",
169
+ ]
175
170
  playwright = await async_playwright().start()
176
171
  if cdp_url is not None:
177
172
  logging.info(f"Connecting to cdp: {cdp_url}")
runtime/env.py CHANGED
@@ -11,3 +11,7 @@ def get_project_id():
11
11
 
12
12
  def get_functions_domain():
13
13
  return os.environ.get("FUNCTIONS_DOMAIN")
14
+
15
+
16
+ def get_browser_type():
17
+ return os.environ.get("BROWSER_TYPE")
@@ -3,8 +3,7 @@ from typing import TYPE_CHECKING
3
3
 
4
4
  if TYPE_CHECKING:
5
5
  from playwright.async_api import ProxySettings
6
-
7
- from ..browser import launch_chromium
6
+ from ..browser import launch_browser
8
7
 
9
8
 
10
9
  @asynccontextmanager
@@ -14,7 +13,7 @@ async def get_production_playwright_constructs(
14
13
  *,
15
14
  cdp_address: str | None = None,
16
15
  ):
17
- async with launch_chromium(headless=headless, cdp_address=cdp_address, proxy=proxy) as (context, page):
16
+ async with launch_browser(headless=headless, cdp_address=cdp_address, proxy=proxy) as (context, page):
18
17
  try:
19
18
  yield context, page
20
19
  finally: