8
8
9
9
from tinycss2 import ( # isort:skip
10
10
parse_blocks_contents , parse_component_value_list , parse_declaration_list ,
11
- parse_one_component_value , parse_one_declaration , parse_one_rule , parse_rule_list ,
12
- parse_stylesheet , parse_stylesheet_bytes , serialize )
11
+ parse_one_component_value , parse_one_declaration , parse_one_rule ,
12
+ parse_rule_list , parse_stylesheet , parse_stylesheet_bytes , serialize )
13
13
from tinycss2 .ast import ( # isort:skip
14
- AtKeywordToken , AtRule , Comment , CurlyBracketsBlock , Declaration , DimensionToken ,
15
- FunctionBlock , HashToken , IdentToken , LiteralToken , NumberToken , ParenthesesBlock ,
16
- ParseError , PercentageToken , QualifiedRule , SquareBracketsBlock , StringToken ,
17
- UnicodeRangeToken , URLToken , WhitespaceToken )
18
- from tinycss2 .color3 import RGBA , parse_color
19
- from tinycss2 .nth import parse_nth
14
+ AtKeywordToken , AtRule , Comment , CurlyBracketsBlock , Declaration ,
15
+ DimensionToken , FunctionBlock , HashToken , IdentToken , LiteralToken ,
16
+ NumberToken , ParenthesesBlock , ParseError , PercentageToken , QualifiedRule ,
17
+ SquareBracketsBlock , StringToken , UnicodeRangeToken , URLToken ,
18
+ WhitespaceToken )
19
+ from tinycss2 .color3 import RGBA # isort:skip
20
+ from tinycss2 .color3 import parse_color as parse_color3 # isort:skip
21
+ from tinycss2 .color4 import Color # isort:skip
22
+ from tinycss2 .color4 import parse_color as parse_color4 # isort:skip
23
+ from tinycss2 .nth import parse_nth # isort:skip
20
24
21
25
22
26
def generic (func ):
@@ -69,7 +73,14 @@ def numeric(t):
69
73
QualifiedRule : lambda r : [
70
74
'qualified rule' , to_json (r .prelude ), to_json (r .content )],
71
75
72
- RGBA : lambda v : [round (c , 10 ) for c in v ],
76
+ RGBA : lambda v : [round (c , 6 ) for c in v ],
77
+ Color : lambda v : [
78
+ v .space ,
79
+ [round (c , 6 ) for c in v .params ],
80
+ v .function_name ,
81
+ [None if arg is None else round (arg , 6 ) for arg in v .args ],
82
+ v .alpha ,
83
+ ],
73
84
}
74
85
75
86
@@ -93,7 +104,7 @@ def test(css, expected):
93
104
return decorator
94
105
95
106
96
- SKIP = dict ( skip_comments = True , skip_whitespace = True )
107
+ SKIP = { ' skip_comments' : True , ' skip_whitespace' : True }
97
108
98
109
99
110
@json_test ()
@@ -136,29 +147,247 @@ def test_one_rule(input):
136
147
return parse_one_rule (input , skip_comments = True )
137
148
138
149
139
- @json_test ()
140
- def test_color3 (input ):
141
- return parse_color (input )
142
-
143
-
144
150
@json_test (filename = 'An+B.json' )
145
151
def test_nth (input ):
146
152
return parse_nth (input )
147
153
148
154
149
- # Do not use @pytest.mark.parametrize because it is slow with that many values.
150
- def test_color3_hsl ():
151
- for css , expected in load_json ('color3_hsl.json' ):
152
- assert to_json (parse_color (css )) == expected
155
+ def _number (value ):
156
+ if value is None :
157
+ return 'none'
158
+ value = round (value + 0.0000001 , 6 )
159
+ return str (int (value ) if value .is_integer () else value )
160
+
161
+
162
+ def test_color_currentcolor_3 ():
163
+ for value in ('currentcolor' , 'currentColor' , 'CURRENTCOLOR' ):
164
+ assert parse_color3 (value ) == 'currentColor'
165
+
166
+
167
+ def test_color_currentcolor_4 ():
168
+ for value in ('currentcolor' , 'currentColor' , 'CURRENTCOLOR' ):
169
+ assert parse_color4 (value ) == 'currentcolor'
170
+
171
+
172
+ @json_test ()
173
+ def test_color_function_4 (input ):
174
+ if not (color := parse_color4 (input )):
175
+ return None
176
+ (* coordinates , alpha ) = color
177
+ result = f'color({ color .space } '
178
+ for coordinate in coordinates :
179
+ result += f' { _number (coordinate )} '
180
+ if alpha != 1 :
181
+ result += f' / { _number (alpha )} '
182
+ result += ')'
183
+ return result
184
+
153
185
186
+ @json_test ()
187
+ def test_color_hexadecimal_3 (input ):
188
+ if not (color := parse_color3 (input )):
189
+ return None
190
+ (* coordinates , alpha ) = color
191
+ result = f'rgb{ "a" if alpha != 1 else "" } ('
192
+ result += f'{ ", " .join (_number (coordinate * 255 ) for coordinate in coordinates )} '
193
+ if alpha != 1 :
194
+ result += f', { _number (alpha )} '
195
+ result += ')'
196
+ return result
197
+
198
+
199
+ @json_test ()
200
+ def test_color_hexadecimal_4 (input ):
201
+ if not (color := parse_color4 (input )):
202
+ return None
203
+ assert color .space == 'srgb'
204
+ (* coordinates , alpha ) = color
205
+ result = f'rgb{ "a" if alpha != 1 else "" } ('
206
+ result += f'{ ", " .join (_number (coordinate * 255 ) for coordinate in coordinates )} '
207
+ if alpha != 1 :
208
+ result += f', { _number (alpha )} '
209
+ result += ')'
210
+ return result
211
+
212
+
213
+ @json_test (filename = 'color_hexadecimal_3.json' )
214
+ def test_color_hexadecimal_3_with_4 (input ):
215
+ if not (color := parse_color4 (input )):
216
+ return None
217
+ assert color .space == 'srgb'
218
+ (* coordinates , alpha ) = color
219
+ result = f'rgb{ "a" if alpha != 1 else "" } ('
220
+ result += f'{ ", " .join (_number (coordinate * 255 ) for coordinate in coordinates )} '
221
+ if alpha != 1 :
222
+ result += f', { _number (alpha )} '
223
+ result += ')'
224
+ return result
225
+
226
+
227
+ @json_test ()
228
+ def test_color_hsl_3 (input ):
229
+ if not (color := parse_color3 (input )):
230
+ return None
231
+ (* coordinates , alpha ) = color
232
+ result = f'rgb{ "a" if alpha != 1 else "" } ('
233
+ result += f'{ ", " .join (_number (coordinate * 255 ) for coordinate in coordinates )} '
234
+ if alpha != 1 :
235
+ result += f', { _number (alpha )} '
236
+ result += ')'
237
+ return result
238
+
239
+
240
+ @json_test (filename = 'color_hsl_3.json' )
241
+ def test_color_hsl_3_with_4 (input ):
242
+ if not (color := parse_color4 (input )):
243
+ return None
244
+ assert color .space == 'hsl'
245
+ (* coordinates , alpha ) = color .to ('srgb' )
246
+ result = f'rgb{ "a" if alpha != 1 else "" } ('
247
+ result += f'{ ", " .join (_number (coordinate * 255 ) for coordinate in coordinates )} '
248
+ if alpha != 1 :
249
+ result += f', { _number (alpha )} '
250
+ result += ')'
251
+ return result
252
+
253
+
254
+ @json_test ()
255
+ def test_color_hsl_4 (input ):
256
+ if not (color := parse_color4 (input )):
257
+ return None
258
+ assert color .space == 'hsl'
259
+ (* coordinates , alpha ) = color .to ('srgb' )
260
+ result = f'rgb{ "a" if alpha != 1 else "" } ('
261
+ result += f'{ ", " .join (_number (coordinate * 255 ) for coordinate in coordinates )} '
262
+ if alpha != 1 :
263
+ result += f', { _number (alpha )} '
264
+ result += ')'
265
+ return result
154
266
155
- def test_color3_keywords ():
156
- for css , expected in load_json ('color3_keywords.json' ):
157
- result = parse_color (css )
158
- if result is not None :
159
- r , g , b , a = result
160
- result = [r * 255 , g * 255 , b * 255 , a ]
161
- assert result == expected
267
+
268
+ @json_test ()
269
+ def test_color_hwb_4 (input ):
270
+ if not (color := parse_color4 (input )):
271
+ return None
272
+ assert color .space == 'hwb'
273
+ (* coordinates , alpha ) = color .to ('srgb' )
274
+ result = f'rgb{ "a" if alpha != 1 else "" } ('
275
+ result += f'{ ", " .join (_number (coordinate * 255 ) for coordinate in coordinates )} '
276
+ if alpha != 1 :
277
+ result += f', { _number (alpha )} '
278
+ result += ')'
279
+ return result
280
+
281
+
282
+ @json_test ()
283
+ def test_color_keywords_3 (input ):
284
+ if not (color := parse_color3 (input )):
285
+ return None
286
+ elif isinstance (color , str ):
287
+ return color
288
+ (* coordinates , alpha ) = color
289
+ result = f'rgb{ "a" if alpha != 1 else "" } ('
290
+ result += f'{ ", " .join (_number (coordinate * 255 ) for coordinate in coordinates )} '
291
+ if alpha != 1 :
292
+ result += f', { _number (alpha )} '
293
+ result += ')'
294
+ return result
295
+
296
+
297
+ @json_test (filename = 'color_keywords_3.json' )
298
+ def test_color_keywords_3_with_4 (input ):
299
+ if not (color := parse_color4 (input )):
300
+ return None
301
+ elif isinstance (color , str ):
302
+ return color
303
+ assert color .space == 'srgb'
304
+ (* coordinates , alpha ) = color
305
+ result = f'rgb{ "a" if alpha != 1 else "" } ('
306
+ result += f'{ ", " .join (_number (coordinate * 255 ) for coordinate in coordinates )} '
307
+ if alpha != 1 :
308
+ result += f', { _number (alpha )} '
309
+ result += ')'
310
+ return result
311
+
312
+
313
+ @json_test ()
314
+ def test_color_keywords_4 (input ):
315
+ if not (color := parse_color4 (input )):
316
+ return None
317
+ elif isinstance (color , str ):
318
+ return color
319
+ assert color .space == 'srgb'
320
+ (* coordinates , alpha ) = color
321
+ result = f'rgb{ "a" if alpha != 1 else "" } ('
322
+ result += f'{ ", " .join (_number (coordinate * 255 ) for coordinate in coordinates )} '
323
+ if alpha != 1 :
324
+ result += f', { _number (alpha )} '
325
+ result += ')'
326
+ return result
327
+
328
+
329
+ @json_test ()
330
+ def test_color_lab_4 (input ):
331
+ if not (color := parse_color4 (input )):
332
+ return None
333
+ elif isinstance (color , str ):
334
+ return color
335
+ assert color .space == 'lab'
336
+ (* coordinates , alpha ) = color
337
+ result = f'{ color .space } ('
338
+ result += f'{ " " .join (_number (coordinate ) for coordinate in coordinates )} '
339
+ if alpha != 1 :
340
+ result += f' / { _number (alpha )} '
341
+ result += ')'
342
+ return result
343
+
344
+
345
+ @json_test ()
346
+ def test_color_oklab_4 (input ):
347
+ if not (color := parse_color4 (input )):
348
+ return None
349
+ elif isinstance (color , str ):
350
+ return color
351
+ assert color .space == 'oklab'
352
+ (* coordinates , alpha ) = color
353
+ result = f'{ color .space } ('
354
+ result += f'{ " " .join (_number (coordinate ) for coordinate in coordinates )} '
355
+ if alpha != 1 :
356
+ result += f' / { _number (alpha )} '
357
+ result += ')'
358
+ return result
359
+
360
+
361
+ @json_test ()
362
+ def test_color_lch_4 (input ):
363
+ if not (color := parse_color4 (input )):
364
+ return None
365
+ elif isinstance (color , str ):
366
+ return color
367
+ assert color .space == 'lch'
368
+ (* coordinates , alpha ) = color
369
+ result = f'{ color .space } ('
370
+ result += f'{ " " .join (_number (coordinate ) for coordinate in coordinates )} '
371
+ if alpha != 1 :
372
+ result += f' / { _number (alpha )} '
373
+ result += ')'
374
+ return result
375
+
376
+
377
+ @json_test ()
378
+ def test_color_oklch_4 (input ):
379
+ if not (color := parse_color4 (input )):
380
+ return None
381
+ elif isinstance (color , str ):
382
+ return color
383
+ assert color .space == 'oklch'
384
+ (* coordinates , alpha ) = color
385
+ result = f'{ color .space } ('
386
+ result += f'{ " " .join (_number (coordinate ) for coordinate in coordinates )} '
387
+ if alpha != 1 :
388
+ result += f' / { _number (alpha )} '
389
+ result += ')'
390
+ return result
162
391
163
392
164
393
@json_test ()
@@ -205,7 +434,8 @@ def test_parse_declaration_value_color():
205
434
source = 'color:#369'
206
435
declaration = parse_one_declaration (source )
207
436
(value_token ,) = declaration .value
208
- assert parse_color (value_token ) == (.2 , .4 , .6 , 1 )
437
+ assert parse_color3 (value_token ) == (.2 , .4 , .6 , 1 )
438
+ assert parse_color4 (value_token ) == (.2 , .4 , .6 , 1 )
209
439
assert declaration .serialize () == source
210
440
211
441
0 commit comments