scrapely-python 0.1.12__tar.gz → 0.1.14__tar.gz
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.
- {scrapely_python-0.1.12/src/scrapely_python.egg-info → scrapely_python-0.1.14}/PKG-INFO +1 -1
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/pyproject.toml +1 -1
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/__init__.py +1 -1
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/actor.py +27 -6
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/configuration.py +16 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/api_client.py +5 -1
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/client.py +9 -1
- {scrapely_python-0.1.12 → scrapely_python-0.1.14/src/scrapely_python.egg-info}/PKG-INFO +1 -1
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_apify_parity.py +50 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_parity.py +6 -1
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/LICENSE +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/LICENSE-APACHE +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/NOTICE +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/README.md +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/setup.cfg +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/_browser_locations.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/browser_configuration.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/cdp_retry.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/charging.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/charging_client.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/crypto/__init__.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/crypto/_secrets.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/errors.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/events/__init__.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/events/_types.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/events/event_manager.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/log.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/patch_browser_pool.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/pricing_types.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/proxy_configuration.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/py.typed +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/request_loaders/__init__.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/request_loaders/_scrapely_request_list.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/__init__.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/_file_system/__init__.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/_file_system/_key_value_store_client.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/_file_system/_storage_client.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/_metadata.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/patch_storage.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/scrapely_dataset_client.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/scrapely_kvs_client.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/scrapely_rq_client.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/scrapely_storage_client.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/smart_scrapely_storage_client.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/types.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/utils.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage_clients/__init__.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storages/__init__.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/types.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/webhook.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely_python.egg-info/SOURCES.txt +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely_python.egg-info/dependency_links.txt +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely_python.egg-info/requires.txt +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely_python.egg-info/top_level.txt +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_api_client_retries.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_browser_configuration.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_cdp_retry.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_charge_limit_guard.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_charge_retries.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_charging_parity.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_charging_pending.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_input_proxy_aliases.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_patch_browser_pool.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_proxy_configuration.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_run_control.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_secrets.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_storage.py +0 -0
- {scrapely_python-0.1.12 → scrapely_python-0.1.14}/tests/test_terminal_status_message.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "scrapely-python"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.14"
|
|
8
8
|
description = "Scrapely Python SDK - A toolkit for building Actors on the Scrapely platform"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT AND Apache-2.0"
|
|
@@ -213,6 +213,14 @@ class _ClassProperty:
|
|
|
213
213
|
return self.func(owner)
|
|
214
214
|
|
|
215
215
|
|
|
216
|
+
def _system_exit_code(exc: Any) -> int:
|
|
217
|
+
"""Process exit code carried by a SystemExit (sys.exit semantics)."""
|
|
218
|
+
code = getattr(exc, 'code', None)
|
|
219
|
+
if code is None:
|
|
220
|
+
return 0
|
|
221
|
+
return code if isinstance(code, int) else 1
|
|
222
|
+
|
|
223
|
+
|
|
216
224
|
class _ActorMeta(type):
|
|
217
225
|
"""Metaclass enabling async with Actor: by delegating to classmethods."""
|
|
218
226
|
|
|
@@ -226,7 +234,11 @@ class _ActorMeta(type):
|
|
|
226
234
|
return cls
|
|
227
235
|
|
|
228
236
|
async def __aexit__(cls, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
229
|
-
if exc_type is not None:
|
|
237
|
+
if exc_type is not None and issubclass(exc_type, SystemExit):
|
|
238
|
+
# Actor.exit()/fail()/sys.exit() inside `async with Actor:` is a deliberate
|
|
239
|
+
# exit, not a failure (Apify parity): keep its exit code, log nothing.
|
|
240
|
+
cls._exit_code = _system_exit_code(exc_val)
|
|
241
|
+
elif exc_type is not None:
|
|
230
242
|
cls._exit_code = 1
|
|
231
243
|
logger.error(f'Actor failed: {exc_val}')
|
|
232
244
|
await cls._shutdown()
|
|
@@ -286,7 +298,10 @@ class Actor(metaclass=_ActorMeta):
|
|
|
286
298
|
|
|
287
299
|
async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
288
300
|
cls = type(self)
|
|
289
|
-
if exc_type is not None:
|
|
301
|
+
if exc_type is not None and issubclass(exc_type, SystemExit):
|
|
302
|
+
# Deliberate exit via Actor.exit()/fail()/sys.exit(), not a failure.
|
|
303
|
+
cls._exit_code = _system_exit_code(exc_val)
|
|
304
|
+
elif exc_type is not None:
|
|
290
305
|
cls._exit_code = 1
|
|
291
306
|
logger.error(f'Actor failed: {exc_val}')
|
|
292
307
|
else:
|
|
@@ -652,12 +667,12 @@ class Actor(metaclass=_ActorMeta):
|
|
|
652
667
|
|
|
653
668
|
@classmethod
|
|
654
669
|
def is_at_home(cls) -> bool:
|
|
655
|
-
return cls.
|
|
670
|
+
return bool(cls._env_config().get('is_at_home', False))
|
|
656
671
|
|
|
657
672
|
@classmethod
|
|
658
673
|
def is_standby(cls) -> bool:
|
|
659
674
|
"""Return True when the actor run was started in standby mode (Node SDK ``isStandby`` parity)."""
|
|
660
|
-
return
|
|
675
|
+
return cls._env_config().get('meta_origin') == 'STANDBY'
|
|
661
676
|
|
|
662
677
|
@_ClassProperty
|
|
663
678
|
def is_paying(cls) -> bool:
|
|
@@ -721,7 +736,7 @@ class Actor(metaclass=_ActorMeta):
|
|
|
721
736
|
return cast(Dict[str, Any], cls._cached_input)
|
|
722
737
|
|
|
723
738
|
kvs = await cls.open_key_value_store()
|
|
724
|
-
input_key = cls.
|
|
739
|
+
input_key = cls._env_config().get('input_key', 'INPUT')
|
|
725
740
|
result = await kvs.get_value(input_key)
|
|
726
741
|
if isinstance(result, dict):
|
|
727
742
|
result = decrypt_secret_inputs(result)
|
|
@@ -848,7 +863,7 @@ class Actor(metaclass=_ActorMeta):
|
|
|
848
863
|
name = name_or_id
|
|
849
864
|
|
|
850
865
|
if alias is not None:
|
|
851
|
-
storages_json = cls.
|
|
866
|
+
storages_json = cls._env_config().get('actor_storages_json')
|
|
852
867
|
resolved = resolve_alias_from_storages_json(alias, storage_type, storages_json)
|
|
853
868
|
if resolved is not None:
|
|
854
869
|
id = resolved
|
|
@@ -1129,6 +1144,12 @@ class Actor(metaclass=_ActorMeta):
|
|
|
1129
1144
|
cls._config = Configuration.get_global_config()
|
|
1130
1145
|
return cls._config
|
|
1131
1146
|
|
|
1147
|
+
@classmethod
|
|
1148
|
+
def _env_config(cls) -> Configuration:
|
|
1149
|
+
# Apify parity: is_at_home() and friends read the environment even
|
|
1150
|
+
# before init(). Doesn't set cls._config, so init() state is unchanged.
|
|
1151
|
+
return cls._config if cls._config is not None else Configuration.get_global_config()
|
|
1152
|
+
|
|
1132
1153
|
@classmethod
|
|
1133
1154
|
def new_client(cls, token: Optional[str] = None, base_url: Optional[str] = None) -> ApiClient:
|
|
1134
1155
|
config = cls.get_config()
|
|
@@ -266,6 +266,22 @@ class Configuration:
|
|
|
266
266
|
value = self.get('standby_port')
|
|
267
267
|
return value if isinstance(value, int) else 4321
|
|
268
268
|
|
|
269
|
+
@property
|
|
270
|
+
def web_server_port(self) -> int:
|
|
271
|
+
"""Apify name for the container port (ACTOR_WEB_SERVER_PORT, default 4321)."""
|
|
272
|
+
value = self.get('container_port')
|
|
273
|
+
return value if isinstance(value, int) else 4321
|
|
274
|
+
|
|
275
|
+
@property
|
|
276
|
+
def web_server_url(self) -> str:
|
|
277
|
+
"""Apify name for the container URL (ACTOR_WEB_SERVER_URL)."""
|
|
278
|
+
return cast(str, self.get('container_url'))
|
|
279
|
+
|
|
280
|
+
@property
|
|
281
|
+
def standby_url(self) -> str:
|
|
282
|
+
"""Public standby URL (ACTOR_STANDBY_URL), falling back to the container URL."""
|
|
283
|
+
return cast(str, self.get('standby_url') or self.get('container_url'))
|
|
284
|
+
|
|
269
285
|
@property
|
|
270
286
|
def token(self) -> Optional[str]:
|
|
271
287
|
"""Get the authentication token."""
|
|
@@ -5,6 +5,7 @@ Base API client for Scrapely storage operations.
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
import asyncio
|
|
8
|
+
import json
|
|
8
9
|
import logging
|
|
9
10
|
import os
|
|
10
11
|
import random
|
|
@@ -311,6 +312,10 @@ class ApiClient:
|
|
|
311
312
|
request_headers = dict(headers or {})
|
|
312
313
|
if json_data is not None and 'Content-Type' not in request_headers:
|
|
313
314
|
request_headers['Content-Type'] = 'application/json'
|
|
315
|
+
if json_data is not None:
|
|
316
|
+
# Apify/crawlee parity: unknown objects (datetimes, LLM result
|
|
317
|
+
# objects, ...) are stored as strings instead of raising.
|
|
318
|
+
content = json.dumps(json_data, ensure_ascii=False, default=str).encode('utf-8')
|
|
314
319
|
|
|
315
320
|
if idempotent is None:
|
|
316
321
|
idempotent = method.upper() in IDEMPOTENT_METHODS
|
|
@@ -343,7 +348,6 @@ class ApiClient:
|
|
|
343
348
|
method,
|
|
344
349
|
url,
|
|
345
350
|
params=params,
|
|
346
|
-
json=json_data,
|
|
347
351
|
content=content,
|
|
348
352
|
headers=request_headers or None,
|
|
349
353
|
**request_kwargs,
|
|
@@ -6,6 +6,7 @@ Ports the patterns from the TypeScript ApiStorageClient.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
+
import os
|
|
9
10
|
import logging
|
|
10
11
|
import re
|
|
11
12
|
import uuid
|
|
@@ -358,7 +359,14 @@ class ApiStorageClient:
|
|
|
358
359
|
return cast(Dict[str, Any], await self.api_client.get_json(f'/v2/key-value-stores/{store_id}/keys', params=params))
|
|
359
360
|
|
|
360
361
|
def kvs_public_url(self, store_id: str, key: str) -> str:
|
|
361
|
-
|
|
362
|
+
# api_url is the container-internal API address; links handed to users
|
|
363
|
+
# must use the public base URL the platform injects.
|
|
364
|
+
public_base = (
|
|
365
|
+
os.environ.get('APIFY_API_PUBLIC_BASE_URL')
|
|
366
|
+
or os.environ.get('ACTOR_API_PUBLIC_BASE_URL')
|
|
367
|
+
or self.api_client.api_url
|
|
368
|
+
).rstrip('/')
|
|
369
|
+
return f'{public_base}{kvs_record_path(store_id, key)}'
|
|
362
370
|
|
|
363
371
|
# --- Request queue resource ops ---
|
|
364
372
|
|
|
@@ -9,6 +9,7 @@ update them when targeting a newer Apify version.
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
import importlib
|
|
12
|
+
import json
|
|
12
13
|
|
|
13
14
|
import pytest
|
|
14
15
|
|
|
@@ -83,3 +84,52 @@ def test_configuration_has_apify_global_accessor() -> None:
|
|
|
83
84
|
from scrapely import Configuration
|
|
84
85
|
|
|
85
86
|
assert Configuration.get_global_configuration() is Configuration.get_global_config()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_configuration_has_apify_web_server_names(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
90
|
+
from scrapely import Configuration
|
|
91
|
+
|
|
92
|
+
monkeypatch.setenv('ACTOR_WEB_SERVER_PORT', '5555')
|
|
93
|
+
monkeypatch.setenv('ACTOR_WEB_SERVER_URL', 'http://10.0.0.1:5555')
|
|
94
|
+
config = Configuration()
|
|
95
|
+
assert config.web_server_port == 5555
|
|
96
|
+
assert config.web_server_url == 'http://10.0.0.1:5555'
|
|
97
|
+
assert config.standby_url == 'http://10.0.0.1:5555'
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_is_at_home_reads_env_before_init(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
101
|
+
# Apify templates pick their port at import time, before Actor.init().
|
|
102
|
+
from scrapely import Actor, Configuration
|
|
103
|
+
|
|
104
|
+
monkeypatch.setenv('APIFY_IS_AT_HOME', '1')
|
|
105
|
+
monkeypatch.setenv('APIFY_META_ORIGIN', 'STANDBY')
|
|
106
|
+
Configuration.reset_global_state()
|
|
107
|
+
monkeypatch.setattr(Actor, '_config', None)
|
|
108
|
+
try:
|
|
109
|
+
assert Actor.is_at_home() is True
|
|
110
|
+
assert Actor.is_standby() is True
|
|
111
|
+
assert Actor._config is None
|
|
112
|
+
finally:
|
|
113
|
+
Configuration.reset_global_state()
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
async def test_json_body_stringifies_unknown_objects() -> None:
|
|
117
|
+
import httpx
|
|
118
|
+
|
|
119
|
+
from scrapely.storage.api_client import ApiClient
|
|
120
|
+
|
|
121
|
+
class AgentOutput:
|
|
122
|
+
def __str__(self) -> str:
|
|
123
|
+
return 'the answer'
|
|
124
|
+
|
|
125
|
+
bodies: list = []
|
|
126
|
+
|
|
127
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
128
|
+
bodies.append((request.headers['content-type'], request.content))
|
|
129
|
+
return httpx.Response(201, json={})
|
|
130
|
+
|
|
131
|
+
client = ApiClient('http://api.test', 'st_x', 'run1', transport=httpx.MockTransport(handler))
|
|
132
|
+
await client.post_json('/v2/datasets/d1/items', [{'answer': AgentOutput(), 'q': 'café'}])
|
|
133
|
+
content_type, body = bodies[0]
|
|
134
|
+
assert content_type == 'application/json'
|
|
135
|
+
assert json.loads(body) == [{'answer': 'the answer', 'q': 'café'}]
|
|
@@ -64,13 +64,18 @@ def test_actor_is_standby_reflects_meta_origin() -> None:
|
|
|
64
64
|
Actor._config = original
|
|
65
65
|
|
|
66
66
|
|
|
67
|
-
def test_actor_is_standby_without_config_is_false() -> None:
|
|
67
|
+
def test_actor_is_standby_without_config_is_false(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
68
|
+
# Before init() is_standby() reads the environment (Apify parity), so clear it.
|
|
69
|
+
monkeypatch.delenv('APIFY_META_ORIGIN', raising=False)
|
|
70
|
+
monkeypatch.delenv('ACTOR_META_ORIGIN', raising=False)
|
|
68
71
|
original = Actor._config
|
|
69
72
|
try:
|
|
70
73
|
Actor._config = None
|
|
74
|
+
scrapely.Configuration.reset_global_state()
|
|
71
75
|
assert Actor.is_standby() is False
|
|
72
76
|
finally:
|
|
73
77
|
Actor._config = original
|
|
78
|
+
scrapely.Configuration.reset_global_state()
|
|
74
79
|
|
|
75
80
|
|
|
76
81
|
def test_parity_helpers_exported_from_package_root() -> None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/_file_system/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/scrapely_dataset_client.py
RENAMED
|
File without changes
|
{scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/scrapely_kvs_client.py
RENAMED
|
File without changes
|
{scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/scrapely_rq_client.py
RENAMED
|
File without changes
|
{scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely/storage/scrapely_storage_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely_python.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
{scrapely_python-0.1.12 → scrapely_python-0.1.14}/src/scrapely_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|