firecrawl-py 3.1.0__tar.gz → 3.1.1__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.
Potentially problematic release.
This version of firecrawl-py might be problematic. Click here for more details.
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/LICENSE +0 -0
- {firecrawl_py-3.1.0/firecrawl_py.egg-info → firecrawl_py-3.1.1}/PKG-INFO +6 -2
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__init__.py +2 -2
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/test_search_validation.py +47 -17
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/methods/search.py +12 -4
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1/firecrawl_py.egg-info}/PKG-INFO +6 -2
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl_py.egg-info/top_level.txt +1 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/tests/test_change_tracking.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/README.md +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/aio/test_aio_batch_scrape.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/aio/test_aio_crawl.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/aio/test_aio_extract.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/aio/test_aio_map.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/aio/test_aio_scrape.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/aio/test_aio_search.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/aio/test_aio_usage.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/aio/test_aio_watcher.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/conftest.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/test_async.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/test_batch_scrape.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/test_crawl.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/test_extract.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/test_map.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/test_scrape.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/test_search.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/test_usage.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/test_watcher.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/aio/test_aio_crawl_params.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/aio/test_aio_crawl_request_preparation.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/aio/test_aio_crawl_validation.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/aio/test_aio_map_request_preparation.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/aio/test_aio_scrape_request_preparation.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/aio/test_aio_search_request_preparation.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/aio/test_batch_request_preparation_async.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/aio/test_ensure_async.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/test_batch_request_preparation.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/test_crawl_params.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/test_crawl_request_preparation.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/test_crawl_validation.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/test_map_request_preparation.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/test_scrape_request_preparation.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/test_search_request_preparation.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/test_usage_types.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/test_webhook.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/utils/test_validation.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/watcher/test_ws_watcher.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/client.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/firecrawl.backup.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/types.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v1/__init__.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v1/client.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/__init__.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/client.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/client_async.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/methods/aio/__init__.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/methods/aio/batch.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/methods/aio/crawl.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/methods/aio/extract.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/methods/aio/map.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/methods/aio/scrape.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/methods/aio/search.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/methods/aio/usage.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/methods/batch.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/methods/crawl.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/methods/extract.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/methods/map.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/methods/scrape.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/methods/usage.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/types.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/utils/__init__.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/utils/error_handler.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/utils/get_version.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/utils/http_client.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/utils/http_client_async.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/utils/normalize.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/utils/validation.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/watcher.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/v2/watcher_async.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl_py.egg-info/SOURCES.txt +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl_py.egg-info/dependency_links.txt +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl_py.egg-info/requires.txt +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/pyproject.toml +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/setup.cfg +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/setup.py +0 -0
- {firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/tests/test_timeout_conversion.py +0 -0
|
File without changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: firecrawl-py
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.1
|
|
4
4
|
Summary: Python SDK for Firecrawl API
|
|
5
5
|
Home-page: https://github.com/firecrawl/firecrawl
|
|
6
6
|
Author: Mendable.ai
|
|
@@ -40,6 +40,10 @@ Requires-Dist: websockets
|
|
|
40
40
|
Requires-Dist: nest-asyncio
|
|
41
41
|
Requires-Dist: pydantic
|
|
42
42
|
Requires-Dist: aiohttp
|
|
43
|
+
Dynamic: author
|
|
44
|
+
Dynamic: home-page
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
Dynamic: requires-python
|
|
43
47
|
|
|
44
48
|
# Firecrawl Python SDK
|
|
45
49
|
|
|
@@ -17,7 +17,7 @@ from .v1 import (
|
|
|
17
17
|
V1ChangeTrackingOptions,
|
|
18
18
|
)
|
|
19
19
|
|
|
20
|
-
__version__ = "3.1.
|
|
20
|
+
__version__ = "3.1.1"
|
|
21
21
|
|
|
22
22
|
# Define the logger for the Firecrawl project
|
|
23
23
|
logger: logging.Logger = logging.getLogger("firecrawl")
|
|
@@ -84,4 +84,4 @@ __all__ = [
|
|
|
84
84
|
'V1JsonConfig',
|
|
85
85
|
'V1ScrapeOptions',
|
|
86
86
|
'V1ChangeTrackingOptions',
|
|
87
|
-
]
|
|
87
|
+
]
|
|
@@ -11,7 +11,7 @@ class TestSearchValidation:
|
|
|
11
11
|
request = SearchRequest(query="")
|
|
12
12
|
with pytest.raises(ValueError, match="Query cannot be empty"):
|
|
13
13
|
_validate_search_request(request)
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
request = SearchRequest(query=" ")
|
|
16
16
|
with pytest.raises(ValueError, match="Query cannot be empty"):
|
|
17
17
|
_validate_search_request(request)
|
|
@@ -22,12 +22,12 @@ class TestSearchValidation:
|
|
|
22
22
|
request = SearchRequest(query="test", limit=0)
|
|
23
23
|
with pytest.raises(ValueError, match="Limit must be positive"):
|
|
24
24
|
_validate_search_request(request)
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
# Negative limit
|
|
27
27
|
request = SearchRequest(query="test", limit=-1)
|
|
28
28
|
with pytest.raises(ValueError, match="Limit must be positive"):
|
|
29
29
|
_validate_search_request(request)
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
# Too high limit
|
|
32
32
|
request = SearchRequest(query="test", limit=101)
|
|
33
33
|
with pytest.raises(ValueError, match="Limit cannot exceed 100"):
|
|
@@ -39,12 +39,12 @@ class TestSearchValidation:
|
|
|
39
39
|
request = SearchRequest(query="test", timeout=0)
|
|
40
40
|
with pytest.raises(ValueError, match="Timeout must be positive"):
|
|
41
41
|
_validate_search_request(request)
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
# Negative timeout
|
|
44
44
|
request = SearchRequest(query="test", timeout=-1000)
|
|
45
45
|
with pytest.raises(ValueError, match="Timeout must be positive"):
|
|
46
46
|
_validate_search_request(request)
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
# Too high timeout
|
|
49
49
|
request = SearchRequest(query="test", timeout=300001)
|
|
50
50
|
with pytest.raises(ValueError, match="Timeout cannot exceed 300000ms"):
|
|
@@ -56,12 +56,12 @@ class TestSearchValidation:
|
|
|
56
56
|
request = SearchRequest(query="test", sources=["invalid_source"])
|
|
57
57
|
with pytest.raises(ValueError, match="Invalid source type"):
|
|
58
58
|
_validate_search_request(request)
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
# Invalid object source
|
|
61
61
|
request = SearchRequest(query="test", sources=[Source(type="invalid_source")])
|
|
62
62
|
with pytest.raises(ValueError, match="Invalid source type"):
|
|
63
63
|
_validate_search_request(request)
|
|
64
|
-
|
|
64
|
+
|
|
65
65
|
# Mixed valid/invalid sources
|
|
66
66
|
request = SearchRequest(query="test", sources=["web", "invalid_source"])
|
|
67
67
|
with pytest.raises(ValueError, match="Invalid source type"):
|
|
@@ -73,7 +73,7 @@ class TestSearchValidation:
|
|
|
73
73
|
request = SearchRequest(query="test", location="")
|
|
74
74
|
with pytest.raises(ValueError, match="Location must be a non-empty string"):
|
|
75
75
|
_validate_search_request(request)
|
|
76
|
-
|
|
76
|
+
|
|
77
77
|
# Whitespace location
|
|
78
78
|
request = SearchRequest(query="test", location=" ")
|
|
79
79
|
with pytest.raises(ValueError, match="Location must be a non-empty string"):
|
|
@@ -82,19 +82,49 @@ class TestSearchValidation:
|
|
|
82
82
|
def test_validate_invalid_tbs(self):
|
|
83
83
|
"""Test validation of invalid tbs values."""
|
|
84
84
|
invalid_tbs_values = ["invalid", "qdr:x", "yesterday", "last_week"]
|
|
85
|
-
|
|
85
|
+
|
|
86
86
|
for invalid_tbs in invalid_tbs_values:
|
|
87
87
|
request = SearchRequest(query="test", tbs=invalid_tbs)
|
|
88
88
|
with pytest.raises(ValueError, match="Invalid tbs value"):
|
|
89
89
|
_validate_search_request(request)
|
|
90
90
|
|
|
91
|
+
def test_validate_custom_date_ranges(self):
|
|
92
|
+
"""Test validation of custom date range formats."""
|
|
93
|
+
valid_custom_ranges = [
|
|
94
|
+
"cdr:1,cd_min:1/1/2024,cd_max:12/31/2024",
|
|
95
|
+
"cdr:1,cd_min:12/1/2024,cd_max:12/31/2024",
|
|
96
|
+
"cdr:1,cd_min:2/28/2023,cd_max:3/1/2023",
|
|
97
|
+
"cdr:1,cd_min:10/15/2023,cd_max:11/15/2023"
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
for valid_range in valid_custom_ranges:
|
|
101
|
+
request = SearchRequest(query="test", tbs=valid_range)
|
|
102
|
+
validated = _validate_search_request(request)
|
|
103
|
+
assert validated == request
|
|
104
|
+
|
|
105
|
+
def test_validate_invalid_custom_date_ranges(self):
|
|
106
|
+
"""Test validation of invalid custom date range formats."""
|
|
107
|
+
# Invalid custom date ranges
|
|
108
|
+
invalid_custom_ranges = [
|
|
109
|
+
"cdr:1,cd_min:2/28/2023", # Missing cd_max
|
|
110
|
+
"cdr:1,cd_max:2/28/2023", # Missing cd_min
|
|
111
|
+
"cdr:2,cd_min:1/1/2024,cd_max:12/31/2024", # Wrong cdr value
|
|
112
|
+
"cdr:cd_min:1/1/2024,cd_max:12/31/2024", # Missing :1
|
|
113
|
+
"custom:1,cd_min:1/1/2024,cd_max:12/31/2024" # Wrong prefix
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
for invalid_range in invalid_custom_ranges:
|
|
117
|
+
request = SearchRequest(query="test", tbs=invalid_range)
|
|
118
|
+
with pytest.raises(ValueError, match="Invalid"):
|
|
119
|
+
_validate_search_request(request)
|
|
120
|
+
|
|
91
121
|
def test_validate_valid_requests(self):
|
|
92
122
|
"""Test that valid requests pass validation."""
|
|
93
123
|
# Minimal valid request
|
|
94
124
|
request = SearchRequest(query="test")
|
|
95
125
|
validated = _validate_search_request(request)
|
|
96
126
|
assert validated == request
|
|
97
|
-
|
|
127
|
+
|
|
98
128
|
# Request with all optional parameters
|
|
99
129
|
request = SearchRequest(
|
|
100
130
|
query="test query",
|
|
@@ -107,7 +137,7 @@ class TestSearchValidation:
|
|
|
107
137
|
)
|
|
108
138
|
validated = _validate_search_request(request)
|
|
109
139
|
assert validated == request
|
|
110
|
-
|
|
140
|
+
|
|
111
141
|
# Request with object sources
|
|
112
142
|
request = SearchRequest(
|
|
113
143
|
query="test",
|
|
@@ -122,17 +152,17 @@ class TestSearchValidation:
|
|
|
122
152
|
request = SearchRequest(query="test", limit=100)
|
|
123
153
|
validated = _validate_search_request(request)
|
|
124
154
|
assert validated == request
|
|
125
|
-
|
|
155
|
+
|
|
126
156
|
# Maximum valid timeout
|
|
127
157
|
request = SearchRequest(query="test", timeout=300000)
|
|
128
158
|
validated = _validate_search_request(request)
|
|
129
159
|
assert validated == request
|
|
130
|
-
|
|
160
|
+
|
|
131
161
|
# Minimum valid limit
|
|
132
162
|
request = SearchRequest(query="test", limit=1)
|
|
133
163
|
validated = _validate_search_request(request)
|
|
134
164
|
assert validated == request
|
|
135
|
-
|
|
165
|
+
|
|
136
166
|
# Minimum valid timeout
|
|
137
167
|
request = SearchRequest(query="test", timeout=1)
|
|
138
168
|
validated = _validate_search_request(request)
|
|
@@ -191,16 +221,16 @@ class TestSearchRequestModel:
|
|
|
191
221
|
data1 = request1.model_dump(by_alias=True)
|
|
192
222
|
assert "ignore_invalid_urls" in data1 # No alias, uses snake_case
|
|
193
223
|
assert data1["ignore_invalid_urls"] is None
|
|
194
|
-
|
|
224
|
+
|
|
195
225
|
# Test with explicit False value
|
|
196
226
|
request2 = SearchRequest(
|
|
197
227
|
query="test",
|
|
198
228
|
ignore_invalid_urls=False,
|
|
199
229
|
scrape_options=ScrapeOptions(formats=["markdown"])
|
|
200
230
|
)
|
|
201
|
-
|
|
231
|
+
|
|
202
232
|
# Check that aliases are used in model_dump with by_alias=True
|
|
203
233
|
data2 = request2.model_dump(by_alias=True)
|
|
204
234
|
assert "ignore_invalid_urls" in data2 # No alias, uses snake_case
|
|
205
235
|
assert "scrape_options" in data2 # No alias, uses snake_case
|
|
206
|
-
assert data2["ignore_invalid_urls"] is False
|
|
236
|
+
assert data2["ignore_invalid_urls"] is False
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Search functionality for Firecrawl v2 API.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import re
|
|
5
6
|
from typing import Optional, Dict, Any, Union
|
|
6
7
|
from ..types import SearchRequest, SearchData, SearchResult, Document
|
|
7
8
|
from ..utils.normalize import normalize_document_input
|
|
@@ -119,11 +120,18 @@ def _validate_search_request(request: SearchRequest) -> SearchRequest:
|
|
|
119
120
|
# Validate tbs (time-based search, if provided)
|
|
120
121
|
if request.tbs is not None:
|
|
121
122
|
valid_tbs_values = {
|
|
122
|
-
"qdr:d", "qdr:w", "qdr:m", "qdr:y", # Google time filters
|
|
123
|
+
"qdr:h", "qdr:d", "qdr:w", "qdr:m", "qdr:y", # Google time filters
|
|
123
124
|
"d", "w", "m", "y" # Short forms
|
|
124
125
|
}
|
|
125
|
-
|
|
126
|
-
|
|
126
|
+
|
|
127
|
+
if request.tbs in valid_tbs_values:
|
|
128
|
+
pass # Valid predefined value
|
|
129
|
+
elif request.tbs.startswith("cdr:"):
|
|
130
|
+
custom_date_pattern = r"^cdr:1,cd_min:\d{1,2}/\d{1,2}/\d{4},cd_max:\d{1,2}/\d{1,2}/\d{4}$"
|
|
131
|
+
if not re.match(custom_date_pattern, request.tbs):
|
|
132
|
+
raise ValueError(f"Invalid custom date range format: {request.tbs}. Expected format: cdr:1,cd_min:MM/DD/YYYY,cd_max:MM/DD/YYYY")
|
|
133
|
+
else:
|
|
134
|
+
raise ValueError(f"Invalid tbs value: {request.tbs}. Valid values: {valid_tbs_values} or custom date range format: cdr:1,cd_min:MM/DD/YYYY,cd_max:MM/DD/YYYY")
|
|
127
135
|
|
|
128
136
|
# Validate scrape_options (if provided)
|
|
129
137
|
if request.scrape_options is not None:
|
|
@@ -166,4 +174,4 @@ def _prepare_search_request(request: SearchRequest) -> Dict[str, Any]:
|
|
|
166
174
|
data["scrapeOptions"] = scrape_data
|
|
167
175
|
data.pop("scrape_options", None)
|
|
168
176
|
|
|
169
|
-
return data
|
|
177
|
+
return data
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: firecrawl-py
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.1
|
|
4
4
|
Summary: Python SDK for Firecrawl API
|
|
5
5
|
Home-page: https://github.com/firecrawl/firecrawl
|
|
6
6
|
Author: Mendable.ai
|
|
@@ -40,6 +40,10 @@ Requires-Dist: websockets
|
|
|
40
40
|
Requires-Dist: nest-asyncio
|
|
41
41
|
Requires-Dist: pydantic
|
|
42
42
|
Requires-Dist: aiohttp
|
|
43
|
+
Dynamic: author
|
|
44
|
+
Dynamic: home-page
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
Dynamic: requires-python
|
|
43
47
|
|
|
44
48
|
# Firecrawl Python SDK
|
|
45
49
|
|
|
File without changes
|
|
File without changes
|
{firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/aio/test_aio_batch_scrape.py
RENAMED
|
File without changes
|
|
File without changes
|
{firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/aio/test_aio_extract.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/e2e/v2/aio/test_aio_watcher.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
|
|
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
|
{firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/test_crawl_params.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/test_usage_types.py
RENAMED
|
File without changes
|
{firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/methods/test_webhook.py
RENAMED
|
File without changes
|
{firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/utils/test_validation.py
RENAMED
|
File without changes
|
{firecrawl_py-3.1.0 → firecrawl_py-3.1.1}/firecrawl/__tests__/unit/v2/watcher/test_ws_watcher.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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|