firecrawl 4.5.0__tar.gz → 4.6.0__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 might be problematic. Click here for more details.
- {firecrawl-4.5.0 → firecrawl-4.6.0}/PKG-INFO +1 -1
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__init__.py +1 -1
- firecrawl-4.6.0/firecrawl/__tests__/unit/v2/methods/test_branding.py +214 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/types.py +20 -1
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/utils/normalize.py +7 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl.egg-info/PKG-INFO +1 -1
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl.egg-info/SOURCES.txt +1 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/LICENSE +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/README.md +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/aio/test_aio_batch_scrape.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/aio/test_aio_crawl.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/aio/test_aio_extract.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/aio/test_aio_map.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/aio/test_aio_scrape.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/aio/test_aio_search.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/aio/test_aio_usage.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/aio/test_aio_watcher.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/conftest.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/test_async.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/test_batch_scrape.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/test_crawl.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/test_extract.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/test_map.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/test_scrape.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/test_search.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/test_usage.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/e2e/v2/test_watcher.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/aio/test_aio_crawl_params.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/aio/test_aio_crawl_request_preparation.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/aio/test_aio_crawl_validation.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/aio/test_aio_map_request_preparation.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/aio/test_aio_scrape_request_preparation.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/aio/test_aio_search_request_preparation.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/aio/test_batch_request_preparation_async.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/aio/test_ensure_async.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/test_batch_request_preparation.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/test_crawl_params.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/test_crawl_request_preparation.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/test_crawl_validation.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/test_map_request_preparation.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/test_pagination.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/test_scrape_request_preparation.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/test_search_request_preparation.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/test_search_validation.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/test_usage_types.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/test_webhook.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/utils/test_validation.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/watcher/test_ws_watcher.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/client.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/firecrawl.backup.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/types.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v1/__init__.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v1/client.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/__init__.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/client.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/client_async.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/methods/aio/__init__.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/methods/aio/batch.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/methods/aio/crawl.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/methods/aio/extract.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/methods/aio/map.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/methods/aio/scrape.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/methods/aio/search.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/methods/aio/usage.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/methods/batch.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/methods/crawl.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/methods/extract.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/methods/map.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/methods/scrape.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/methods/search.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/methods/usage.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/utils/__init__.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/utils/error_handler.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/utils/get_version.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/utils/http_client.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/utils/http_client_async.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/utils/validation.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/watcher.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/v2/watcher_async.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl.egg-info/dependency_links.txt +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl.egg-info/requires.txt +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl.egg-info/top_level.txt +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/pyproject.toml +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/setup.cfg +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/setup.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/tests/test_api_key_handling.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/tests/test_change_tracking.py +0 -0
- {firecrawl-4.5.0 → firecrawl-4.6.0}/tests/test_timeout_conversion.py +0 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from unittest.mock import Mock, MagicMock
|
|
3
|
+
from firecrawl.v2.methods.scrape import scrape
|
|
4
|
+
from firecrawl.v2.types import ScrapeOptions, Document
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestBrandingFormat:
|
|
8
|
+
"""Unit tests for branding format support."""
|
|
9
|
+
|
|
10
|
+
def test_scrape_with_branding_format_returns_branding_data(self):
|
|
11
|
+
"""Test that scraping with branding format returns branding data."""
|
|
12
|
+
mock_response = Mock()
|
|
13
|
+
mock_response.ok = True
|
|
14
|
+
mock_response.json.return_value = {
|
|
15
|
+
"success": True,
|
|
16
|
+
"data": {
|
|
17
|
+
"markdown": "# Example",
|
|
18
|
+
"branding": {
|
|
19
|
+
"colorScheme": "light",
|
|
20
|
+
"colors": {
|
|
21
|
+
"primary": "#E11D48",
|
|
22
|
+
"secondary": "#3B82F6",
|
|
23
|
+
"accent": "#F59E0B"
|
|
24
|
+
},
|
|
25
|
+
"typography": {
|
|
26
|
+
"fontFamilies": {
|
|
27
|
+
"primary": "Inter",
|
|
28
|
+
"heading": "Poppins"
|
|
29
|
+
},
|
|
30
|
+
"fontSizes": {
|
|
31
|
+
"h1": "2.5rem",
|
|
32
|
+
"body": "1rem"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"spacing": {
|
|
36
|
+
"baseUnit": 8
|
|
37
|
+
},
|
|
38
|
+
"components": {
|
|
39
|
+
"buttonPrimary": {
|
|
40
|
+
"background": "#E11D48",
|
|
41
|
+
"textColor": "#FFFFFF",
|
|
42
|
+
"borderRadius": "0.5rem"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
mock_client = Mock()
|
|
50
|
+
mock_client.post.return_value = mock_response
|
|
51
|
+
|
|
52
|
+
result = scrape(mock_client, "https://example.com", ScrapeOptions(formats=["branding"]))
|
|
53
|
+
|
|
54
|
+
assert result.branding is not None
|
|
55
|
+
assert result.branding.color_scheme == "light"
|
|
56
|
+
assert result.branding.colors["primary"] == "#E11D48"
|
|
57
|
+
assert result.branding.typography["fontFamilies"]["primary"] == "Inter"
|
|
58
|
+
assert result.branding.spacing["baseUnit"] == 8
|
|
59
|
+
assert result.branding.components["buttonPrimary"]["background"] == "#E11D48"
|
|
60
|
+
|
|
61
|
+
def test_scrape_with_branding_and_markdown_formats_returns_both(self):
|
|
62
|
+
"""Test that scraping with both branding and markdown formats returns both."""
|
|
63
|
+
mock_response = Mock()
|
|
64
|
+
mock_response.ok = True
|
|
65
|
+
mock_response.json.return_value = {
|
|
66
|
+
"success": True,
|
|
67
|
+
"data": {
|
|
68
|
+
"markdown": "# Example Content",
|
|
69
|
+
"branding": {
|
|
70
|
+
"colorScheme": "dark",
|
|
71
|
+
"colors": {
|
|
72
|
+
"primary": "#10B981"
|
|
73
|
+
},
|
|
74
|
+
"typography": {
|
|
75
|
+
"fontFamilies": {
|
|
76
|
+
"primary": "Roboto"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
mock_client = Mock()
|
|
84
|
+
mock_client.post.return_value = mock_response
|
|
85
|
+
|
|
86
|
+
result = scrape(mock_client, "https://example.com", ScrapeOptions(formats=["markdown", "branding"]))
|
|
87
|
+
|
|
88
|
+
assert result.markdown == "# Example Content"
|
|
89
|
+
assert result.branding is not None
|
|
90
|
+
assert result.branding.color_scheme == "dark"
|
|
91
|
+
assert result.branding.colors["primary"] == "#10B981"
|
|
92
|
+
|
|
93
|
+
def test_scrape_without_branding_format_does_not_return_branding(self):
|
|
94
|
+
"""Test that scraping without branding format does not return branding."""
|
|
95
|
+
mock_response = Mock()
|
|
96
|
+
mock_response.ok = True
|
|
97
|
+
mock_response.json.return_value = {
|
|
98
|
+
"success": True,
|
|
99
|
+
"data": {
|
|
100
|
+
"markdown": "# Example"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
mock_client = Mock()
|
|
105
|
+
mock_client.post.return_value = mock_response
|
|
106
|
+
|
|
107
|
+
result = scrape(mock_client, "https://example.com", ScrapeOptions(formats=["markdown"]))
|
|
108
|
+
|
|
109
|
+
assert result.markdown == "# Example"
|
|
110
|
+
assert result.branding is None
|
|
111
|
+
|
|
112
|
+
def test_branding_format_with_all_nested_fields(self):
|
|
113
|
+
"""Test branding format with all nested fields populated."""
|
|
114
|
+
mock_response = Mock()
|
|
115
|
+
mock_response.ok = True
|
|
116
|
+
mock_response.json.return_value = {
|
|
117
|
+
"success": True,
|
|
118
|
+
"data": {
|
|
119
|
+
"branding": {
|
|
120
|
+
"colorScheme": "light",
|
|
121
|
+
"logo": "https://example.com/logo.png",
|
|
122
|
+
"fonts": [
|
|
123
|
+
{"family": "Inter", "weight": 400},
|
|
124
|
+
{"family": "Poppins", "weight": 700}
|
|
125
|
+
],
|
|
126
|
+
"colors": {
|
|
127
|
+
"primary": "#E11D48",
|
|
128
|
+
"background": "#FFFFFF"
|
|
129
|
+
},
|
|
130
|
+
"typography": {
|
|
131
|
+
"fontFamilies": {"primary": "Inter"},
|
|
132
|
+
"fontStacks": {"body": ["Inter", "sans-serif"]},
|
|
133
|
+
"fontSizes": {"h1": "2.5rem"},
|
|
134
|
+
"lineHeights": {"body": 1.5},
|
|
135
|
+
"fontWeights": {"regular": 400}
|
|
136
|
+
},
|
|
137
|
+
"spacing": {
|
|
138
|
+
"baseUnit": 8,
|
|
139
|
+
"padding": {"sm": 8, "md": 16}
|
|
140
|
+
},
|
|
141
|
+
"components": {
|
|
142
|
+
"buttonPrimary": {
|
|
143
|
+
"background": "#E11D48",
|
|
144
|
+
"textColor": "#FFFFFF"
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"icons": {
|
|
148
|
+
"style": "outline",
|
|
149
|
+
"primaryColor": "#E11D48"
|
|
150
|
+
},
|
|
151
|
+
"images": {
|
|
152
|
+
"logo": "https://example.com/logo.png",
|
|
153
|
+
"favicon": "https://example.com/favicon.ico"
|
|
154
|
+
},
|
|
155
|
+
"animations": {
|
|
156
|
+
"transitionDuration": "200ms",
|
|
157
|
+
"easing": "ease-in-out"
|
|
158
|
+
},
|
|
159
|
+
"layout": {
|
|
160
|
+
"grid": {"columns": 12, "maxWidth": "1200px"},
|
|
161
|
+
"headerHeight": "64px"
|
|
162
|
+
},
|
|
163
|
+
"tone": {
|
|
164
|
+
"voice": "professional",
|
|
165
|
+
"emojiUsage": "minimal"
|
|
166
|
+
},
|
|
167
|
+
"personality": {
|
|
168
|
+
"tone": "professional",
|
|
169
|
+
"energy": "medium",
|
|
170
|
+
"targetAudience": "developers"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
mock_client = Mock()
|
|
177
|
+
mock_client.post.return_value = mock_response
|
|
178
|
+
|
|
179
|
+
result = scrape(mock_client, "https://example.com", ScrapeOptions(formats=["branding"]))
|
|
180
|
+
|
|
181
|
+
assert result.branding is not None
|
|
182
|
+
assert result.branding.color_scheme == "light"
|
|
183
|
+
assert result.branding.logo == "https://example.com/logo.png"
|
|
184
|
+
assert len(result.branding.fonts) == 2
|
|
185
|
+
assert result.branding.typography["fontStacks"]["body"] == ["Inter", "sans-serif"]
|
|
186
|
+
assert result.branding.spacing["padding"] == {"sm": 8, "md": 16}
|
|
187
|
+
assert result.branding.icons["style"] == "outline"
|
|
188
|
+
assert result.branding.images["favicon"] == "https://example.com/favicon.ico"
|
|
189
|
+
assert result.branding.animations["easing"] == "ease-in-out"
|
|
190
|
+
assert result.branding.layout["grid"]["columns"] == 12
|
|
191
|
+
assert result.branding.personality["tone"] == "professional"
|
|
192
|
+
|
|
193
|
+
def test_branding_colorscheme_normalization(self):
|
|
194
|
+
"""Test that colorScheme is normalized to color_scheme."""
|
|
195
|
+
mock_response = Mock()
|
|
196
|
+
mock_response.ok = True
|
|
197
|
+
mock_response.json.return_value = {
|
|
198
|
+
"success": True,
|
|
199
|
+
"data": {
|
|
200
|
+
"branding": {
|
|
201
|
+
"colorScheme": "dark",
|
|
202
|
+
"colors": {"primary": "#000000"}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
mock_client = Mock()
|
|
208
|
+
mock_client.post.return_value = mock_response
|
|
209
|
+
|
|
210
|
+
result = scrape(mock_client, "https://example.com", ScrapeOptions(formats=["branding"]))
|
|
211
|
+
|
|
212
|
+
assert result.branding is not None
|
|
213
|
+
assert result.branding.color_scheme == "dark"
|
|
214
|
+
assert not hasattr(result.branding, "colorScheme")
|
|
@@ -124,6 +124,24 @@ class AttributeResult(BaseModel):
|
|
|
124
124
|
attribute: str
|
|
125
125
|
values: List[str]
|
|
126
126
|
|
|
127
|
+
class BrandingProfile(BaseModel):
|
|
128
|
+
"""Branding information extracted from a website."""
|
|
129
|
+
model_config = {"extra": "allow"}
|
|
130
|
+
|
|
131
|
+
color_scheme: Optional[Literal["light", "dark"]] = None
|
|
132
|
+
logo: Optional[str] = None
|
|
133
|
+
fonts: Optional[List[Dict[str, Any]]] = None
|
|
134
|
+
colors: Optional[Dict[str, str]] = None
|
|
135
|
+
typography: Optional[Dict[str, Any]] = None
|
|
136
|
+
spacing: Optional[Dict[str, Any]] = None
|
|
137
|
+
components: Optional[Dict[str, Any]] = None
|
|
138
|
+
icons: Optional[Dict[str, str]] = None
|
|
139
|
+
images: Optional[Dict[str, Optional[str]]] = None
|
|
140
|
+
animations: Optional[Dict[str, str]] = None
|
|
141
|
+
layout: Optional[Dict[str, Any]] = None
|
|
142
|
+
tone: Optional[Dict[str, str]] = None
|
|
143
|
+
personality: Optional[Dict[str, Any]] = None
|
|
144
|
+
|
|
127
145
|
class Document(BaseModel):
|
|
128
146
|
"""A scraped document."""
|
|
129
147
|
markdown: Optional[str] = None
|
|
@@ -138,6 +156,7 @@ class Document(BaseModel):
|
|
|
138
156
|
actions: Optional[Dict[str, Any]] = None
|
|
139
157
|
warning: Optional[str] = None
|
|
140
158
|
change_tracking: Optional[Dict[str, Any]] = None
|
|
159
|
+
branding: Optional[BrandingProfile] = None
|
|
141
160
|
|
|
142
161
|
@property
|
|
143
162
|
def metadata_typed(self) -> DocumentMetadata:
|
|
@@ -199,7 +218,7 @@ CategoryOption = Union[str, Category]
|
|
|
199
218
|
|
|
200
219
|
FormatString = Literal[
|
|
201
220
|
# camelCase versions (API format)
|
|
202
|
-
"markdown", "html", "rawHtml", "links", "images", "screenshot", "summary", "changeTracking", "json", "attributes",
|
|
221
|
+
"markdown", "html", "rawHtml", "links", "images", "screenshot", "summary", "changeTracking", "json", "attributes", "branding",
|
|
203
222
|
# snake_case versions (user-friendly)
|
|
204
223
|
"raw_html", "change_tracking"
|
|
205
224
|
]
|
|
@@ -83,6 +83,7 @@ def normalize_document_input(doc: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
83
83
|
Normalize a raw Document dict from the API into the Python SDK's expected shape:
|
|
84
84
|
- Convert top-level keys rawHtml->raw_html, changeTracking->change_tracking
|
|
85
85
|
- Convert metadata keys from camelCase to snake_case
|
|
86
|
+
- Convert branding.colorScheme to branding.color_scheme
|
|
86
87
|
"""
|
|
87
88
|
normalized = dict(doc)
|
|
88
89
|
|
|
@@ -102,6 +103,12 @@ def normalize_document_input(doc: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
102
103
|
# Fallback to mapped dict if model construction fails for any reason
|
|
103
104
|
normalized["metadata"] = mapped
|
|
104
105
|
|
|
106
|
+
# Normalize branding top-level camelCase keys
|
|
107
|
+
branding = normalized.get("branding")
|
|
108
|
+
if isinstance(branding, dict):
|
|
109
|
+
if "colorScheme" in branding and "color_scheme" not in branding:
|
|
110
|
+
branding["color_scheme"] = branding.pop("colorScheme")
|
|
111
|
+
|
|
105
112
|
return normalized
|
|
106
113
|
|
|
107
114
|
|
|
@@ -30,6 +30,7 @@ firecrawl/__tests__/e2e/v2/aio/test_aio_search.py
|
|
|
30
30
|
firecrawl/__tests__/e2e/v2/aio/test_aio_usage.py
|
|
31
31
|
firecrawl/__tests__/e2e/v2/aio/test_aio_watcher.py
|
|
32
32
|
firecrawl/__tests__/unit/v2/methods/test_batch_request_preparation.py
|
|
33
|
+
firecrawl/__tests__/unit/v2/methods/test_branding.py
|
|
33
34
|
firecrawl/__tests__/unit/v2/methods/test_crawl_params.py
|
|
34
35
|
firecrawl/__tests__/unit/v2/methods/test_crawl_request_preparation.py
|
|
35
36
|
firecrawl/__tests__/unit/v2/methods/test_crawl_validation.py
|
|
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-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/aio/test_aio_crawl_params.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/aio/test_ensure_async.py
RENAMED
|
File without changes
|
|
File without changes
|
{firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/test_crawl_params.py
RENAMED
|
File without changes
|
|
File without changes
|
{firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/test_crawl_validation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{firecrawl-4.5.0 → firecrawl-4.6.0}/firecrawl/__tests__/unit/v2/methods/test_search_validation.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|