lightningcss 0.3.1__tar.gz → 0.3.2__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.
@@ -87,6 +87,33 @@ jobs:
87
87
  name: wheels-${{ runner.os }}-${{ matrix.target }}
88
88
  path: dist/*
89
89
 
90
+ test:
91
+ name: Test wheels on ${{ matrix.os }} (${{ matrix.python-version }})
92
+ needs: linux
93
+ runs-on: ${{ matrix.os }}
94
+ strategy:
95
+ matrix:
96
+ os: [ubuntu-latest]
97
+ python-version: ['3.10']
98
+ steps:
99
+ - uses: actions/checkout@v4
100
+ - name: Set up Python ${{ matrix.python-version }}
101
+ uses: actions/setup-python@v5
102
+ with:
103
+ python-version: ${{ matrix.python-version }}
104
+ - name: Download x86_64 wheels
105
+ uses: actions/download-artifact@v4
106
+ with:
107
+ name: wheels-Linux-x86_64
108
+ path: dist
109
+ - name: Install wheel and dependencies
110
+ run: |
111
+ pip install --upgrade pip
112
+ pip install --no-index --find-links=dist lightningcss
113
+ pip install --group dev
114
+ - name: Run tests
115
+ run: pytest
116
+
90
117
  sdist:
91
118
  runs-on: ubuntu-latest
92
119
  steps:
@@ -8,19 +8,19 @@ version = "0.7.8"
8
8
  source = "registry+https://github.com/rust-lang/crates.io-index"
9
9
  checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
10
10
  dependencies = [
11
- "getrandom",
11
+ "getrandom 0.2.15",
12
12
  "once_cell",
13
13
  "version_check",
14
14
  ]
15
15
 
16
16
  [[package]]
17
17
  name = "ahash"
18
- version = "0.8.11"
18
+ version = "0.8.12"
19
19
  source = "registry+https://github.com/rust-lang/crates.io-index"
20
- checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
20
+ checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
21
21
  dependencies = [
22
22
  "cfg-if",
23
- "getrandom",
23
+ "getrandom 0.3.4",
24
24
  "once_cell",
25
25
  "serde",
26
26
  "version_check",
@@ -75,16 +75,26 @@ dependencies = [
75
75
  "wyz",
76
76
  ]
77
77
 
78
+ [[package]]
79
+ name = "browserslist-data"
80
+ version = "0.1.5"
81
+ source = "registry+https://github.com/rust-lang/crates.io-index"
82
+ checksum = "21d369bf3fe9811518eead42e2cdf9ed9915579242864297689894c0f1089712"
83
+ dependencies = [
84
+ "ahash 0.8.12",
85
+ "chrono",
86
+ ]
87
+
78
88
  [[package]]
79
89
  name = "browserslist-rs"
80
- version = "0.17.0"
90
+ version = "0.19.0"
81
91
  source = "registry+https://github.com/rust-lang/crates.io-index"
82
- checksum = "74c973b79d9b6b89854493185ab760c6ef8e54bcfad10ad4e33991e46b374ac8"
92
+ checksum = "8dd48a6ca358df4f7000e3fb5f08738b1b91a0e5d5f862e2f77b2b14647547f5"
83
93
  dependencies = [
84
- "ahash 0.8.11",
94
+ "ahash 0.8.12",
95
+ "browserslist-data",
85
96
  "chrono",
86
97
  "either",
87
- "indexmap",
88
98
  "itertools 0.13.0",
89
99
  "nom",
90
100
  "serde",
@@ -317,6 +327,18 @@ dependencies = [
317
327
  "wasi",
318
328
  ]
319
329
 
330
+ [[package]]
331
+ name = "getrandom"
332
+ version = "0.3.4"
333
+ source = "registry+https://github.com/rust-lang/crates.io-index"
334
+ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
335
+ dependencies = [
336
+ "cfg-if",
337
+ "libc",
338
+ "r-efi",
339
+ "wasip2",
340
+ ]
341
+
320
342
  [[package]]
321
343
  name = "hashbrown"
322
344
  version = "0.12.3"
@@ -378,12 +400,6 @@ dependencies = [
378
400
  "serde",
379
401
  ]
380
402
 
381
- [[package]]
382
- name = "indoc"
383
- version = "2.0.6"
384
- source = "registry+https://github.com/rust-lang/crates.io-index"
385
- checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
386
-
387
403
  [[package]]
388
404
  name = "itertools"
389
405
  version = "0.10.5"
@@ -432,11 +448,11 @@ checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
432
448
 
433
449
  [[package]]
434
450
  name = "lightningcss"
435
- version = "1.0.0-alpha.65"
451
+ version = "1.0.0-alpha.71"
436
452
  source = "registry+https://github.com/rust-lang/crates.io-index"
437
- checksum = "c84f971730745f4aaac013b6cf4328baf1548efc973c0d95cfd843a3c1ca07af"
453
+ checksum = "cb6314c2f0590ac93c86099b98bb7ba8abcf759bfd89604ffca906472bb54937"
438
454
  dependencies = [
439
- "ahash 0.8.11",
455
+ "ahash 0.8.12",
440
456
  "bitflags",
441
457
  "browserslist-rs",
442
458
  "const-str",
@@ -444,17 +460,18 @@ dependencies = [
444
460
  "cssparser-color",
445
461
  "dashmap",
446
462
  "data-encoding",
447
- "getrandom",
463
+ "getrandom 0.3.4",
448
464
  "indexmap",
449
465
  "itertools 0.10.5",
450
466
  "lazy_static",
451
467
  "lightningcss-derive",
452
468
  "parcel_selectors",
453
469
  "parcel_sourcemap",
454
- "paste",
470
+ "pastey",
455
471
  "pathdiff",
456
472
  "rayon",
457
473
  "serde",
474
+ "serde-content",
458
475
  "smallvec",
459
476
  ]
460
477
 
@@ -498,15 +515,6 @@ version = "2.7.4"
498
515
  source = "registry+https://github.com/rust-lang/crates.io-index"
499
516
  checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
500
517
 
501
- [[package]]
502
- name = "memoffset"
503
- version = "0.9.1"
504
- source = "registry+https://github.com/rust-lang/crates.io-index"
505
- checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
506
- dependencies = [
507
- "autocfg",
508
- ]
509
-
510
518
  [[package]]
511
519
  name = "minimal-lexical"
512
520
  version = "0.2.1"
@@ -546,9 +554,9 @@ checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4"
546
554
 
547
555
  [[package]]
548
556
  name = "parcel_selectors"
549
- version = "0.28.1"
557
+ version = "0.28.2"
550
558
  source = "registry+https://github.com/rust-lang/crates.io-index"
551
- checksum = "dccbc6fb560df303a44e511618256029410efbc87779018f751ef12c488271fe"
559
+ checksum = "54fd03f1ad26cb6b3ec1b7414fa78a3bd639e7dbb421b1a60513c96ce886a196"
552
560
  dependencies = [
553
561
  "bitflags",
554
562
  "cssparser",
@@ -588,10 +596,10 @@ dependencies = [
588
596
  ]
589
597
 
590
598
  [[package]]
591
- name = "paste"
592
- version = "1.0.15"
599
+ name = "pastey"
600
+ version = "0.1.1"
593
601
  source = "registry+https://github.com/rust-lang/crates.io-index"
594
- checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
602
+ checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec"
595
603
 
596
604
  [[package]]
597
605
  name = "pathdiff"
@@ -694,35 +702,32 @@ dependencies = [
694
702
 
695
703
  [[package]]
696
704
  name = "pyo3"
697
- version = "0.27.2"
705
+ version = "0.28.2"
698
706
  source = "registry+https://github.com/rust-lang/crates.io-index"
699
- checksum = "ab53c047fcd1a1d2a8820fe84f05d6be69e9526be40cb03b73f86b6b03e6d87d"
707
+ checksum = "cf85e27e86080aafd5a22eae58a162e133a589551542b3e5cee4beb27e54f8e1"
700
708
  dependencies = [
701
- "indoc",
702
709
  "libc",
703
- "memoffset",
704
710
  "once_cell",
705
711
  "portable-atomic",
706
712
  "pyo3-build-config",
707
713
  "pyo3-ffi",
708
714
  "pyo3-macros",
709
- "unindent",
710
715
  ]
711
716
 
712
717
  [[package]]
713
718
  name = "pyo3-build-config"
714
- version = "0.27.2"
719
+ version = "0.28.2"
715
720
  source = "registry+https://github.com/rust-lang/crates.io-index"
716
- checksum = "b455933107de8642b4487ed26d912c2d899dec6114884214a0b3bb3be9261ea6"
721
+ checksum = "8bf94ee265674bf76c09fa430b0e99c26e319c945d96ca0d5a8215f31bf81cf7"
717
722
  dependencies = [
718
723
  "target-lexicon",
719
724
  ]
720
725
 
721
726
  [[package]]
722
727
  name = "pyo3-ffi"
723
- version = "0.27.2"
728
+ version = "0.28.2"
724
729
  source = "registry+https://github.com/rust-lang/crates.io-index"
725
- checksum = "1c85c9cbfaddf651b1221594209aed57e9e5cff63c4d11d1feead529b872a089"
730
+ checksum = "491aa5fc66d8059dd44a75f4580a2962c1862a1c2945359db36f6c2818b748dc"
726
731
  dependencies = [
727
732
  "libc",
728
733
  "pyo3-build-config",
@@ -730,9 +735,9 @@ dependencies = [
730
735
 
731
736
  [[package]]
732
737
  name = "pyo3-macros"
733
- version = "0.27.2"
738
+ version = "0.28.2"
734
739
  source = "registry+https://github.com/rust-lang/crates.io-index"
735
- checksum = "0a5b10c9bf9888125d917fb4d2ca2d25c8df94c7ab5a52e13313a07e050a3b02"
740
+ checksum = "f5d671734e9d7a43449f8480f8b38115df67bef8d21f76837fa75ee7aaa5e52e"
736
741
  dependencies = [
737
742
  "proc-macro2",
738
743
  "pyo3-macros-backend",
@@ -742,9 +747,9 @@ dependencies = [
742
747
 
743
748
  [[package]]
744
749
  name = "pyo3-macros-backend"
745
- version = "0.27.2"
750
+ version = "0.28.2"
746
751
  source = "registry+https://github.com/rust-lang/crates.io-index"
747
- checksum = "03b51720d314836e53327f5871d4c0cfb4fb37cc2c4a11cc71907a86342c40f9"
752
+ checksum = "22faaa1ce6c430a1f71658760497291065e6450d7b5dc2bcf254d49f66ee700a"
748
753
  dependencies = [
749
754
  "heck",
750
755
  "proc-macro2",
@@ -755,7 +760,7 @@ dependencies = [
755
760
 
756
761
  [[package]]
757
762
  name = "python-lightningcss"
758
- version = "0.3.1"
763
+ version = "0.3.2"
759
764
  dependencies = [
760
765
  "browserslist-rs",
761
766
  "lightningcss",
@@ -771,6 +776,12 @@ dependencies = [
771
776
  "proc-macro2",
772
777
  ]
773
778
 
779
+ [[package]]
780
+ name = "r-efi"
781
+ version = "5.3.0"
782
+ source = "registry+https://github.com/rust-lang/crates.io-index"
783
+ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
784
+
774
785
  [[package]]
775
786
  name = "radium"
776
787
  version = "0.7.0"
@@ -891,18 +902,37 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
891
902
 
892
903
  [[package]]
893
904
  name = "serde"
894
- version = "1.0.219"
905
+ version = "1.0.228"
895
906
  source = "registry+https://github.com/rust-lang/crates.io-index"
896
- checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
907
+ checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
908
+ dependencies = [
909
+ "serde_core",
910
+ "serde_derive",
911
+ ]
912
+
913
+ [[package]]
914
+ name = "serde-content"
915
+ version = "0.1.2"
916
+ source = "registry+https://github.com/rust-lang/crates.io-index"
917
+ checksum = "3753ca04f350fa92d00b6146a3555e63c55388c9ef2e11e09bce2ff1c0b509c6"
918
+ dependencies = [
919
+ "serde",
920
+ ]
921
+
922
+ [[package]]
923
+ name = "serde_core"
924
+ version = "1.0.228"
925
+ source = "registry+https://github.com/rust-lang/crates.io-index"
926
+ checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
897
927
  dependencies = [
898
928
  "serde_derive",
899
929
  ]
900
930
 
901
931
  [[package]]
902
932
  name = "serde_derive"
903
- version = "1.0.219"
933
+ version = "1.0.228"
904
934
  source = "registry+https://github.com/rust-lang/crates.io-index"
905
- checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
935
+ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
906
936
  dependencies = [
907
937
  "proc-macro2",
908
938
  "quote",
@@ -984,9 +1014,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
984
1014
 
985
1015
  [[package]]
986
1016
  name = "target-lexicon"
987
- version = "0.13.2"
1017
+ version = "0.13.5"
988
1018
  source = "registry+https://github.com/rust-lang/crates.io-index"
989
- checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
1019
+ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
990
1020
 
991
1021
  [[package]]
992
1022
  name = "thiserror"
@@ -1035,12 +1065,6 @@ version = "1.12.0"
1035
1065
  source = "registry+https://github.com/rust-lang/crates.io-index"
1036
1066
  checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
1037
1067
 
1038
- [[package]]
1039
- name = "unindent"
1040
- version = "0.2.4"
1041
- source = "registry+https://github.com/rust-lang/crates.io-index"
1042
- checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
1043
-
1044
1068
  [[package]]
1045
1069
  name = "uuid"
1046
1070
  version = "1.16.0"
@@ -1065,6 +1089,15 @@ version = "0.11.0+wasi-snapshot-preview1"
1065
1089
  source = "registry+https://github.com/rust-lang/crates.io-index"
1066
1090
  checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
1067
1091
 
1092
+ [[package]]
1093
+ name = "wasip2"
1094
+ version = "1.0.2+wasi-0.2.9"
1095
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1096
+ checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
1097
+ dependencies = [
1098
+ "wit-bindgen",
1099
+ ]
1100
+
1068
1101
  [[package]]
1069
1102
  name = "wasm-bindgen"
1070
1103
  version = "0.2.100"
@@ -1202,6 +1235,12 @@ version = "0.52.6"
1202
1235
  source = "registry+https://github.com/rust-lang/crates.io-index"
1203
1236
  checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
1204
1237
 
1238
+ [[package]]
1239
+ name = "wit-bindgen"
1240
+ version = "0.51.0"
1241
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1242
+ checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
1243
+
1205
1244
  [[package]]
1206
1245
  name = "wyz"
1207
1246
  version = "0.5.1"
@@ -1213,18 +1252,18 @@ dependencies = [
1213
1252
 
1214
1253
  [[package]]
1215
1254
  name = "zerocopy"
1216
- version = "0.7.35"
1255
+ version = "0.8.42"
1217
1256
  source = "registry+https://github.com/rust-lang/crates.io-index"
1218
- checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
1257
+ checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3"
1219
1258
  dependencies = [
1220
1259
  "zerocopy-derive",
1221
1260
  ]
1222
1261
 
1223
1262
  [[package]]
1224
1263
  name = "zerocopy-derive"
1225
- version = "0.7.35"
1264
+ version = "0.8.42"
1226
1265
  source = "registry+https://github.com/rust-lang/crates.io-index"
1227
- checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
1266
+ checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f"
1228
1267
  dependencies = [
1229
1268
  "proc-macro2",
1230
1269
  "quote",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "python-lightningcss"
3
- version = "0.3.1"
3
+ version = "0.3.2"
4
4
  edition = "2021"
5
5
  readme = "README.md"
6
6
 
@@ -10,6 +10,6 @@ name = "lightningcss"
10
10
  crate-type = ["cdylib"]
11
11
 
12
12
  [dependencies]
13
- pyo3 = { version = "0.27.2", features = ["extension-module"] }
14
- browserslist-rs = "0.17.0"
15
- lightningcss = { version = "1.0.0-alpha.65", features = ["browserslist"] }
13
+ pyo3 = { version = "0.28.2", features = ["extension-module", "abi3-py37"] }
14
+ browserslist-rs = "0.19.0"
15
+ lightningcss = { version = "1.0.0-alpha.71", features = ["browserslist"] }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lightningcss
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: Apache Software License
@@ -9,14 +9,6 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
9
9
  Classifier: Programming Language :: Python :: Implementation :: PyPy
10
10
  Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Programming Language :: Python :: 3 :: Only
12
- Classifier: Programming Language :: Python :: 3.7
13
- Classifier: Programming Language :: Python :: 3.8
14
- Classifier: Programming Language :: Python :: 3.9
15
- Classifier: Programming Language :: Python :: 3.10
16
- Classifier: Programming Language :: Python :: 3.11
17
- Classifier: Programming Language :: Python :: 3.12
18
- Classifier: Programming Language :: Python :: 3.13
19
- Classifier: Programming Language :: Python :: 3.14
20
12
  Classifier: Topic :: Internet :: WWW/HTTP
21
13
  Classifier: Topic :: Software Development :: Pre-processors
22
14
  License-File: LICENSE
@@ -82,20 +74,21 @@ output_css = lightningcss.process_stylesheet(
82
74
  )
83
75
  ```
84
76
 
77
+ The `filename` keyword parameter is only used for displaying error messages from
78
+ the parser. When using `browsers_list`, lightningcss will try to transpile the
79
+ code to be compatible with the specified
80
+ [browserslist target](https://browsersl.ist/).
81
+
85
82
  This package also supports creating a CSS bundle where all `@import` rules are
86
83
  resolved into a single stylesheet:
87
84
 
88
85
  ```py
89
86
  bundled_css = lightningcss.bundle_css(
90
87
  "main.css",
91
- filename = "main.css",
92
88
  browsers_list = ["defaults"],
93
89
  minify = False,
94
90
  )
95
91
  ```
96
92
 
97
- All resources referenced via `@import` are resolved relative to the main file. The
98
- `filename` keyword parameter is only used for displaying error messages from the
99
- parser. When using `browsers_list`, lightningcss will try to transpile the code
100
- to be compatible with the specified [browserslist target](https://browsersl.ist/).
93
+ All resources referenced via `@import` are resolved relative to the main file.
101
94
 
@@ -52,19 +52,20 @@ output_css = lightningcss.process_stylesheet(
52
52
  )
53
53
  ```
54
54
 
55
+ The `filename` keyword parameter is only used for displaying error messages from
56
+ the parser. When using `browsers_list`, lightningcss will try to transpile the
57
+ code to be compatible with the specified
58
+ [browserslist target](https://browsersl.ist/).
59
+
55
60
  This package also supports creating a CSS bundle where all `@import` rules are
56
61
  resolved into a single stylesheet:
57
62
 
58
63
  ```py
59
64
  bundled_css = lightningcss.bundle_css(
60
65
  "main.css",
61
- filename = "main.css",
62
66
  browsers_list = ["defaults"],
63
67
  minify = False,
64
68
  )
65
69
  ```
66
70
 
67
- All resources referenced via `@import` are resolved relative to the main file. The
68
- `filename` keyword parameter is only used for displaying error messages from the
69
- parser. When using `browsers_list`, lightningcss will try to transpile the code
70
- to be compatible with the specified [browserslist target](https://browsersl.ist/).
71
+ All resources referenced via `@import` are resolved relative to the main file.
@@ -12,7 +12,7 @@ def calc_parser_flags(
12
12
  deep_selector_combinator: bool = False
13
13
  ) -> ParserFlags:
14
14
  """
15
- Calculates the `parser_flags` argument of `process_stylesheet()`.
15
+ Calculates the `parser_flags` argument of `process_stylesheet()` and `bundle_css()`.
16
16
  """
17
17
 
18
18
  def process_stylesheet(
@@ -42,7 +42,40 @@ def process_stylesheet(
42
42
  :param browsers_list: An optional list of browserslist targets to be used
43
43
  to determine automatic prefixing and transpilation. If it is not
44
44
  specified, no prefixing/transpilation will occur.
45
- :param minify: Is True, the final output will be minified. Otherwise, it
45
+ :param minify: If True, the final output will be minified. Otherwise, it
46
46
  will be pretty-printed.
47
47
  :return: A string containing a processed CSS stylesheet.
48
48
  """
49
+
50
+ def bundle_css(
51
+ path: str,
52
+ /,
53
+ error_recovery: bool = False,
54
+ parser_flags: ParserFlags = ParserFlags(0),
55
+ unused_symbols: set[str] | None = None,
56
+ browsers_list: list[str] | None = None,
57
+ minify: bool = True
58
+ ) -> str:
59
+ """
60
+ Processes the supplied CSS stylesheet file and returns the bundle as a string.
61
+
62
+ Resolves all `@import` rules to create a single CSS bundle. The resources
63
+ referenced via `@import` are resolved relative to the main file.
64
+
65
+ :param path: A string containing the path of the stylesheet file to process.
66
+ :param error_recovery: Whether or not to omit broken CSS rather than
67
+ producing a parse error. Enable with caution!
68
+ :param parser_flags: An optional flag created by `calc_parser_flags()`.
69
+ See that function for more details.
70
+ :param unused_symbols: An optional set of known unused symbols, like
71
+ classnames, ids, or keyframe names, to be removed from the output.
72
+ Note that symbols should be specified in bare form, i.e.
73
+ `unused_symbols={'a', 'b'}`, not `unused_symbols={'.a', '#b'}`, and
74
+ will remove both ids and classes if they share a name. Use with caution!
75
+ :param browsers_list: An optional list of browserslist targets to be used
76
+ to determine automatic prefixing and transpilation. If it is not
77
+ specified, no prefixing/transpilation will occur.
78
+ :param minify: If True, the final output will be minified. Otherwise, it
79
+ will be pretty-printed.
80
+ :return: A string containing the CSS bundle.
81
+ """
@@ -22,14 +22,6 @@ classifiers = [
22
22
  "Programming Language :: Python :: Implementation :: PyPy",
23
23
  "Programming Language :: Python :: 3",
24
24
  "Programming Language :: Python :: 3 :: Only",
25
- "Programming Language :: Python :: 3.7",
26
- "Programming Language :: Python :: 3.8",
27
- "Programming Language :: Python :: 3.9",
28
- "Programming Language :: Python :: 3.10",
29
- "Programming Language :: Python :: 3.11",
30
- "Programming Language :: Python :: 3.12",
31
- "Programming Language :: Python :: 3.13",
32
- "Programming Language :: Python :: 3.14",
33
25
  "Topic :: Internet :: WWW/HTTP",
34
26
  "Topic :: Software Development :: Pre-processors",
35
27
  ]
@@ -37,6 +29,10 @@ classifiers = [
37
29
  [project.urls]
38
30
  Source = "https://github.com/pydsigner/python-lightningcss"
39
31
 
32
+ [dependency-groups]
33
+ dev = [
34
+ "pytest>=9.0.2",
35
+ ]
40
36
 
41
37
  [tool.maturin]
42
38
  features = ["pyo3/extension-module"]
@@ -1,11 +1,11 @@
1
1
  use std::collections::HashSet;
2
2
  use std::path::Path;
3
3
 
4
- use pyo3::exceptions::PyValueError;
4
+ use pyo3::exceptions::{PyIOError, PyValueError};
5
5
  use pyo3::prelude::*;
6
6
 
7
7
  use browserslist::Error as BrowserslistError;
8
- use lightningcss::bundler::{Bundler, FileProvider};
8
+ use lightningcss::bundler::{Bundler, FileProvider, BundleErrorKind};
9
9
  use lightningcss::stylesheet::{
10
10
  MinifyOptions, ParserFlags, ParserOptions, PrinterOptions, StyleSheet,
11
11
  };
@@ -49,7 +49,7 @@ fn process_stylesheet(code: &str,
49
49
 
50
50
  let targets = match mk_targets(browsers_list) {
51
51
  Ok(val) => val,
52
- Err(e) => {return Err(PyValueError::new_err(format!("browsers_list failed validation: {}", e.to_string())))}
52
+ Err(e) => {return Err(PyValueError::new_err(format!("Validation of browsers_list failed: {}", e.to_string())))}
53
53
  };
54
54
  let mut stylesheet = match StyleSheet::parse(code, mk_parser_options(filename, error_recovery, parser_flags)) {
55
55
  Ok(val) => val,
@@ -76,11 +76,11 @@ fn calc_parser_flags(nesting: bool, custom_media: bool, deep_selector_combinator
76
76
  return flags;
77
77
  }
78
78
 
79
- fn mk_parser_options(filename: &str,
80
- error_recovery: bool,
81
- parser_flags: u8) -> ParserOptions {
79
+ fn mk_parser_options<'o, 'i>(filename: &'o str,
80
+ error_recovery: bool,
81
+ parser_flags: u8) -> ParserOptions<'o, 'i> {
82
82
  return ParserOptions {
83
- filename: filename.to_string(),
83
+ filename: filename.into(),
84
84
  error_recovery: error_recovery,
85
85
  flags: ParserFlags::from_bits_truncate(parser_flags),
86
86
  ..Default::default()
@@ -116,7 +116,7 @@ fn mk_printer_options<'a>(targets: &Targets,
116
116
  /// Bundles a CSS file and returns as a string.
117
117
  #[pyfunction]
118
118
  #[pyo3(signature = (
119
- path="",
119
+ path,
120
120
  /,
121
121
  error_recovery=false,
122
122
  parser_flags=0,
@@ -142,7 +142,23 @@ fn bundle_css(
142
142
  ..Default::default()
143
143
  },
144
144
  );
145
- let mut stylesheet = bundler.bundle(Path::new(path)).unwrap();
145
+
146
+ let mut stylesheet = match bundler.bundle(Path::new(&path)) {
147
+ Ok(s) => s,
148
+ Err(e) => {
149
+ let message = e.to_string();
150
+ match e.kind {
151
+ // Resolver errors, probably related to file I/O
152
+ BundleErrorKind::ResolverError(_) => {
153
+ return Err(PyIOError::new_err(format!("Bundling failed: {}", message)));
154
+ }
155
+ // Parser and logical errors
156
+ _ => {
157
+ return Err(PyValueError::new_err(format!("Bundling failed: {}", message)));
158
+ }
159
+ }
160
+ }
161
+ };
146
162
 
147
163
  let targets = match mk_targets(browsers_list) {
148
164
  Ok(val) => val,
@@ -173,11 +189,12 @@ fn bundle_css(
173
189
  }
174
190
 
175
191
  /// A python wrapper for core functionality of lightningcss.
176
- #[pymodule]
177
- #[pyo3(name = "lightningcss")]
178
- fn pylightningcss(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
179
- m.add_function(wrap_pyfunction!(process_stylesheet, m)?)?;
180
- m.add_function(wrap_pyfunction!(calc_parser_flags, m)?)?;
181
- m.add_function(wrap_pyfunction!(bundle_css, m)?)?;
182
- Ok(())
192
+ #[pymodule(name = "lightningcss")]
193
+ mod py_lightningcss {
194
+ #[pymodule_export]
195
+ use super::calc_parser_flags;
196
+ #[pymodule_export]
197
+ use super::process_stylesheet;
198
+ #[pymodule_export]
199
+ use super::bundle_css;
183
200
  }
@@ -0,0 +1,5 @@
1
+ * {
2
+ box-sizing: border-box;
3
+ }
4
+
5
+ something invalid
@@ -0,0 +1,5 @@
1
+ @import "normalize.css" layer(normalize);
2
+
3
+ a {
4
+ color: blue;
5
+ }
@@ -0,0 +1,3 @@
1
+ * {
2
+ box-sizing: border-box;
3
+ }
@@ -0,0 +1,30 @@
1
+ from pathlib import Path
2
+ import pytest
3
+ import lightningcss as lcss
4
+
5
+ TEST_DATA_DIR = Path(__file__).parent / "data"
6
+ MAIN_CSS_PATH = TEST_DATA_DIR / "main.css"
7
+ NORMALIZE_CSS_PATH = TEST_DATA_DIR / "normalize.css"
8
+ MISSING_CSS_PATH = TEST_DATA_DIR / "not-there.css"
9
+ INVALID_CSS_PATH = TEST_DATA_DIR / "invalid.css"
10
+
11
+
12
+ def test_minify():
13
+ expected = "@layer normalize{*{box-sizing:border-box}}a{color:#00f}"
14
+
15
+ result = lcss.bundle_css(str(MAIN_CSS_PATH))
16
+ assert result == expected
17
+
18
+ def test_pretty_print():
19
+ expected = "* {\n box-sizing: border-box;\n}\n"
20
+
21
+ result = lcss.bundle_css(str(NORMALIZE_CSS_PATH), minify=False)
22
+ assert result == expected
23
+
24
+ def test_file_not_found():
25
+ with pytest.raises(OSError):
26
+ lcss.bundle_css(str(MISSING_CSS_PATH))
27
+
28
+ def test_parse_error():
29
+ with pytest.raises(ValueError):
30
+ lcss.bundle_css(str(INVALID_CSS_PATH))
@@ -0,0 +1,33 @@
1
+ import lightningcss as lcss
2
+ import pytest
3
+
4
+
5
+ def test_minify():
6
+ code = ".content { margin-inline: 3vw; padding: 1rem 2rem 1rem 2rem; }"
7
+ expected = ".content{margin-inline:3vw;padding:1rem 2rem}"
8
+
9
+ result = lcss.process_stylesheet(code)
10
+ assert result == expected
11
+
12
+ def test_pretty_print():
13
+ code = ".content { margin: 3vw; }"
14
+ expected = ".content {\n margin: 3vw;\n}\n"
15
+
16
+ result = lcss.process_stylesheet(code, minify=False)
17
+ assert result == expected
18
+
19
+ def test_parse_error():
20
+ code = "img { display: block; } nonsense }{ non-terminated"
21
+
22
+ with pytest.raises(ValueError):
23
+ lcss.process_stylesheet(code)
24
+
25
+ def test_error_recovery():
26
+ code = "img { display: block; } nonsense }{ non-terminated"
27
+ expected = "img{display:block}"
28
+
29
+ with pytest.raises(ValueError):
30
+ lcss.process_stylesheet(code, error_recovery=False)
31
+
32
+ result = lcss.process_stylesheet(code, error_recovery=True)
33
+ assert result == expected
File without changes
File without changes