From be5a10f4ece7eefbefc24042797629bbede06bef Mon Sep 17 00:00:00 2001 From: Bo Lopker Date: Sun, 22 Dec 2024 16:03:54 -0800 Subject: [PATCH 01/11] Add support for 3.13 with no GIL Signed-off-by: Bo Lopker --- Cargo.lock | 300 +++++++----------- packages/mrml-python/Cargo.toml | 2 +- packages/mrml-python/mrml.pyi | 17 +- packages/mrml-python/src/lib.rs | 16 +- .../mrml-python/tests/test_thread_safety.py | 163 ++++++++++ 5 files changed, 290 insertions(+), 208 deletions(-) create mode 100644 packages/mrml-python/tests/test_thread_safety.py diff --git a/Cargo.lock b/Cargo.lock index bc0a5b4d..6402621a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -123,7 +123,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -134,7 +134,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -176,7 +176,7 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tower", "tower-layer", @@ -199,7 +199,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 1.0.2", + "sync_wrapper", "tower-layer", "tower-service", "tracing", @@ -213,7 +213,7 @@ checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -242,7 +242,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -259,9 +259,9 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bstr" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" +checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8" dependencies = [ "memchr", "regex-automata 0.4.9", @@ -294,9 +294,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.3" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" dependencies = [ "shlex", ] @@ -371,7 +371,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -388,12 +388,12 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -403,19 +403,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f76990911f2267d837d9d0ad060aa63aaad170af40904b29461734c339030d4d" dependencies = [ "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] name = "console" -version = "0.15.8" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" dependencies = [ "encode_unicode", - "lazy_static", "libc", - "windows-sys 0.52.0", + "once_cell", + "windows-sys 0.59.0", ] [[package]] @@ -504,9 +504,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -523,9 +523,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" @@ -570,7 +570,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -587,7 +587,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -613,9 +613,9 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "enum-as-inner" @@ -626,7 +626,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -638,14 +638,14 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", @@ -653,9 +653,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" dependencies = [ "anstream", "anstyle", @@ -894,9 +894,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" dependencies = [ "bytes", "futures-channel", @@ -915,9 +915,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.3" +version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", "http", @@ -1065,7 +1065,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -1171,9 +1171,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.167" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "lightningcss" @@ -1280,9 +1280,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ "adler2", ] @@ -1403,9 +1403,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -1464,7 +1464,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1525,7 +1525,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -1609,9 +1609,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.22.6" +version = "0.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f402062616ab18202ae8319da13fa4279883a2b8a9d9f83f20dbade813ce1884" +checksum = "e484fd2c8b4cb67ab05a318f1fd6fa8f199fcc30819f08f07d200809dba26c15" dependencies = [ "cfg-if", "indoc", @@ -1627,9 +1627,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.22.6" +version = "0.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b14b5775b5ff446dd1056212d778012cbe8a0fbffd368029fd9e25b514479c38" +checksum = "dc0e0469a84f208e20044b98965e1561028180219e35352a2afaf2b942beff3b" dependencies = [ "once_cell", "target-lexicon", @@ -1637,9 +1637,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.22.6" +version = "0.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ab5bcf04a2cdcbb50c7d6105de943f543f9ed92af55818fd17b660390fc8636" +checksum = "eb1547a7f9966f6f1a0f0227564a9945fe36b90da5a93b3933fc3dc03fae372d" dependencies = [ "libc", "pyo3-build-config", @@ -1647,27 +1647,27 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.22.6" +version = "0.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fd24d897903a9e6d80b968368a34e1525aeb719d568dba8b3d4bfa5dc67d453" +checksum = "fdb6da8ec6fa5cedd1626c886fc8749bdcbb09424a86461eb8cdf096b7c33257" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] name = "pyo3-macros-backend" -version = "0.22.6" +version = "0.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c011a03ba1e50152b4b394b479826cad97e7a21eb52df179cd91ac411cbfbe" +checksum = "38a385202ff5a92791168b1136afae5059d3ac118457bb7bc304c197c2d33e7d" dependencies = [ "heck", "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -1683,7 +1683,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.5", + "thiserror 2.0.9", "tokio", "tracing", ] @@ -1702,7 +1702,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.5", + "thiserror 2.0.9", "tinyvec", "tracing", "web-time", @@ -1710,9 +1710,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.7" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" dependencies = [ "cfg_aliases", "libc", @@ -1783,9 +1783,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags", ] @@ -1865,7 +1865,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tokio-rustls", "tower-service", @@ -1906,9 +1906,9 @@ checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustls" -version = "0.23.19" +version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ "log", "once_cell", @@ -1930,9 +1930,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" dependencies = [ "web-time", ] @@ -1983,9 +1983,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] @@ -2003,13 +2003,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2020,14 +2020,14 @@ checksum = "e578a843d40b4189a4d66bba51d7684f57da5bd7c304c64e14bd63efbef49509" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" dependencies = [ "itoa", "memchr", @@ -2169,21 +2169,15 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "sync_wrapper" version = "1.0.2" @@ -2201,7 +2195,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2221,11 +2215,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.5" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643caef17e3128658ff44d85923ef2d28af81bb71e0d67bbfe1d76f19a73e053" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" dependencies = [ - "thiserror-impl 2.0.5", + "thiserror-impl 2.0.9", ] [[package]] @@ -2236,18 +2230,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] name = "thiserror-impl" -version = "2.0.5" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995d0bbc9995d1f19d28b7215a9352b0fc3cd3a2d2ec95c2cadc485cdedbcdde" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2282,9 +2276,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] @@ -2321,7 +2315,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2373,14 +2367,14 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper 0.1.2", + "sync_wrapper", "tokio", "tower-layer", "tower-service", @@ -2419,7 +2413,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2489,7 +2483,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2619,7 +2613,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", "wasm-bindgen-shared", ] @@ -2654,7 +2648,7 @@ checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2687,7 +2681,7 @@ checksum = "54171416ce73aa0b9c377b51cc3cb542becee1cd678204812e8392e5b0e4a031" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2758,7 +2752,7 @@ checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ "windows-result", "windows-strings", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2767,7 +2761,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2777,16 +2771,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ "windows-result", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -2795,7 +2780,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2804,22 +2789,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -2828,46 +2798,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -2880,48 +2832,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -2960,7 +2888,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", "synstructure", ] @@ -2982,7 +2910,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -3002,7 +2930,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", "synstructure", ] @@ -3031,5 +2959,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] diff --git a/packages/mrml-python/Cargo.toml b/packages/mrml-python/Cargo.toml index 6f7d1fb9..e6f4a417 100644 --- a/packages/mrml-python/Cargo.toml +++ b/packages/mrml-python/Cargo.toml @@ -20,4 +20,4 @@ mrml = { version = "4.0.1", path = "../mrml-core", features = [ "http-loader-ureq", "local-loader", ] } -pyo3 = { version = "0.22", features = ["extension-module"] } +pyo3 = { version = "0.23", features = ["extension-module"] } diff --git a/packages/mrml-python/mrml.pyi b/packages/mrml-python/mrml.pyi index e68440f9..289e3647 100644 --- a/packages/mrml-python/mrml.pyi +++ b/packages/mrml-python/mrml.pyi @@ -1,4 +1,4 @@ -from typing import Any, Dict, Optional, Set, Union, List +from typing import Any, Dict, List, Optional, Set, Union class NoopIncludeLoaderOptions: """No-operation loader options class, which requires no specific configuration.""" @@ -64,12 +64,12 @@ class ParserOptions: class RenderOptions: """RenderOptions configures rendering behavior, including whether to disable comments and how to handle social icons and fonts.""" - def __init__( - self, - disable_comments: bool = False, - social_icon_origin: Optional[str] = None, - fonts: Optional[Dict[str, str]] = None, - ) -> None: ... + + disable_comments: bool + social_icon_origin: Optional[str] + fonts: Optional[Dict[str, str]] + + def __init__(self) -> None: ... class Warning: @property @@ -86,7 +86,8 @@ class Output: @property def content(self) -> str: ... @property - def warnings(self) -> List[Warning] + def warnings(self) -> List[Warning]: ... + def __init__(self) -> None: ... def to_html( input: str, diff --git a/packages/mrml-python/src/lib.rs b/packages/mrml-python/src/lib.rs index 094f48d7..52c7b277 100644 --- a/packages/mrml-python/src/lib.rs +++ b/packages/mrml-python/src/lib.rs @@ -42,8 +42,8 @@ pub struct HttpIncludeLoaderOptions { list: HashSet, } -// #[pyclass] -#[derive(FromPyObject, Clone, Debug)] +#[pyclass] +#[derive(Clone, Debug)] pub enum ParserIncludeLoaderOptions { Noop(NoopIncludeLoaderOptions), Memory(MemoryIncludeLoaderOptions), @@ -79,17 +79,6 @@ impl ParserIncludeLoaderOptions { } } -impl IntoPy for ParserIncludeLoaderOptions { - fn into_py(self, py: Python<'_>) -> PyObject { - match self { - Self::Noop(inner) => inner.into_py(py), - Self::Memory(inner) => inner.into_py(py), - Self::Local(inner) => inner.into_py(py), - Self::Http(inner) => inner.into_py(py), - } - } -} - #[pyfunction] #[pyo3(name = "noop_loader")] pub fn noop_loader() -> ParserIncludeLoaderOptions { @@ -275,5 +264,6 @@ fn register(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(local_loader, m)?)?; m.add_function(wrap_pyfunction!(http_loader, m)?)?; m.add_function(wrap_pyfunction!(memory_loader, m)?)?; + m.gil_used(false)?; Ok(()) } diff --git a/packages/mrml-python/tests/test_thread_safety.py b/packages/mrml-python/tests/test_thread_safety.py new file mode 100644 index 00000000..44d76373 --- /dev/null +++ b/packages/mrml-python/tests/test_thread_safety.py @@ -0,0 +1,163 @@ +import concurrent.futures + +import mrml + + +def test_concurrent_simple_template(): + def worker(): + result = mrml.to_html("") + assert result.content.startswith("") + assert len(result.warnings) == 0 + return True + + with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: + futures = [executor.submit(worker) for _ in range(100)] + results = [f.result() for f in futures] + assert all(results) + + +def test_concurrent_memory_loader(): + def worker(): + parser_options = mrml.ParserOptions( + include_loader=mrml.memory_loader( + { + "hello-world.mjml": "Hello World!", + } + ) + ) + result = mrml.to_html( + '', + parser_options=parser_options, + ) + assert result.content.startswith("") + assert len(result.warnings) == 0 + return True + + with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: + futures = [executor.submit(worker) for _ in range(100)] + results = [f.result() for f in futures] + assert all(results) + + +def test_concurrent_local_loader(): + def worker(): + parser_options = mrml.ParserOptions( + include_loader=mrml.local_loader("./resources/partials") + ) + result = mrml.to_html( + '', + parser_options=parser_options, + ) + assert result.content.startswith("") + assert len(result.warnings) == 0 + return True + + with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: + futures = [executor.submit(worker) for _ in range(100)] + results = [f.result() for f in futures] + assert all(results) + + +def test_concurrent_http_loader(): + def worker(): + parser_options = mrml.ParserOptions( + include_loader=mrml.http_loader( + mode=mrml.HttpIncludeLoaderOptionsMode.Allow, + list=set(["https://gist.githubusercontent.com"]), + ) + ) + result = mrml.to_html( + """ + + + + """, + parser_options=parser_options, + ) + assert result.content.startswith("") + assert len(result.warnings) == 0 + return True + + with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: + futures = [ + executor.submit(worker) for _ in range(20) + ] # Fewer iterations for HTTP test + results = [f.result() for f in futures] + assert all(results) + + +def test_concurrent_mixed_operations(): + """Test different MRML operations running concurrently""" + + def worker_simple(): + result = mrml.to_html("") + assert result.content.startswith("") + return "simple" + + def worker_memory(): + parser_options = mrml.ParserOptions( + include_loader=mrml.memory_loader( + { + "hello-world.mjml": "Hello World!", + } + ) + ) + result = mrml.to_html( + '', + parser_options=parser_options, + ) + assert result.content.startswith("") + return "memory" + + def worker_local(): + parser_options = mrml.ParserOptions( + include_loader=mrml.local_loader("./resources/partials") + ) + result = mrml.to_html( + '', + parser_options=parser_options, + ) + assert result.content.startswith("") + return "local" + + workers = [worker_simple, worker_memory, worker_local] + + with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: + task_count = 100 + futures = [] + for _ in range(task_count): # 30 total operations + for worker in workers: + futures.append(executor.submit(worker)) + + results = [f.result() for f in futures] + assert len(results) == task_count * len(workers) + assert all(r in ["simple", "memory", "local"] for r in results) + + +def test_render_options_thread_safety(): + """Test concurrent access with different render options""" + + def worker(disable_comments: bool): + render_options = mrml.RenderOptions() + render_options.disable_comments = disable_comments + result = mrml.to_html( + "", + render_options=render_options, + ) + assert result.content.startswith("") + return (disable_comments, result.content) + + with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: + task_count = 100 + futures = [] + for i in range(task_count): + futures.append(executor.submit(worker, i % 2 == 0)) + results = [f.result() for f in futures] + assert len(results) == task_count + for result in results: + if result[0]: + assert "" not in result[1] + else: + assert "" in result[1] From 5cdd17d5424544fe1ece729c4c8aff01fe3e2d90 Mon Sep 17 00:00:00 2001 From: Bo Lopker Date: Sun, 22 Dec 2024 16:21:17 -0800 Subject: [PATCH 02/11] Install maturin via pip for speed, use no gil python for testing Signed-off-by: Bo Lopker --- .github/workflows/mrml-python-main.yml | 32 +++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/mrml-python-main.yml b/.github/workflows/mrml-python-main.yml index 315e7670..52bfb751 100644 --- a/.github/workflows/mrml-python-main.yml +++ b/.github/workflows/mrml-python-main.yml @@ -5,18 +5,18 @@ on: branches: - main paths: - - '.github/workflows/mrml-python-main.yml' - - 'Cargo.lock' - - 'Cargo.toml' - - 'packages/mrml-core/**' - - 'packages/mrml-python/**' + - ".github/workflows/mrml-python-main.yml" + - "Cargo.lock" + - "Cargo.toml" + - "packages/mrml-core/**" + - "packages/mrml-python/**" pull_request: paths: - - '.github/workflows/mrml-python-main.yml' - - 'Cargo.lock' - - 'Cargo.toml' - - 'packages/mrml-core/**' - - 'packages/mrml-python/**' + - ".github/workflows/mrml-python-main.yml" + - "Cargo.lock" + - "Cargo.toml" + - "packages/mrml-core/**" + - "packages/mrml-python/**" workflow_dispatch: permissions: @@ -33,9 +33,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + # Use deadsnakes until https://github.com/actions/setup-python/issues/771 is closed + - name: Setup Python + uses: deadsnakes/action@v3 with: - python-version: '3.10' + python-version: "3.13" + nogil: true - name: install cargo toolchain uses: actions-rs/toolchain@v1 @@ -43,15 +46,12 @@ jobs: toolchain: stable profile: minimal - - name: install maturin - run: cargo install maturin --locked - - name: init python venv run: | python3 -m pip install --upgrade pip python3 -m venv env source env/bin/activate - python3 -m pip install pytest + python3 -m pip install pytest maturin maturin develop python3 -m pytest working-directory: packages/mrml-python From 2b89060839a8d853b385bfdfdb1a0340ccafdf0f Mon Sep 17 00:00:00 2001 From: Bo Lopker Date: Sun, 22 Dec 2024 16:22:08 -0800 Subject: [PATCH 03/11] Fix deadsnakes action version Signed-off-by: Bo Lopker --- .github/workflows/mrml-python-main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mrml-python-main.yml b/.github/workflows/mrml-python-main.yml index 52bfb751..a791f4d6 100644 --- a/.github/workflows/mrml-python-main.yml +++ b/.github/workflows/mrml-python-main.yml @@ -35,7 +35,7 @@ jobs: # Use deadsnakes until https://github.com/actions/setup-python/issues/771 is closed - name: Setup Python - uses: deadsnakes/action@v3 + uses: deadsnakes/action@v3.2.0 with: python-version: "3.13" nogil: true From e3646817308ae225977173af6497392d9bbec2e7 Mon Sep 17 00:00:00 2001 From: Bo Lopker Date: Sun, 22 Dec 2024 16:56:42 -0800 Subject: [PATCH 04/11] Add 3.13 to release workflow Signed-off-by: Bo Lopker --- .github/workflows/mrml-python-release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/mrml-python-release.yml b/.github/workflows/mrml-python-release.yml index 32f64be2..13cd5b37 100644 --- a/.github/workflows/mrml-python-release.yml +++ b/.github/workflows/mrml-python-release.yml @@ -39,7 +39,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: - python-version: "3.10" + python-version: "3.13" - name: build wheels uses: PyO3/maturin-action@v1 with: @@ -63,7 +63,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: - python-version: "3.10" + python-version: "3.13" architecture: ${{ matrix.target }} - name: build wheels uses: PyO3/maturin-action@v1 @@ -87,7 +87,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: - python-version: "3.10" + python-version: "3.13" - name: build wheels uses: PyO3/maturin-action@v1 with: From aac4f79f84d0447273b59c06d900c7847ca7df49 Mon Sep 17 00:00:00 2001 From: Bo Lopker Date: Sun, 22 Dec 2024 19:03:27 -0800 Subject: [PATCH 05/11] Better tests, freeze all classes for better thread safety Signed-off-by: Bo Lopker --- packages/mrml-python/mrml.pyi | 18 ++-- packages/mrml-python/src/lib.rs | 43 +++++---- .../mrml-python/tests/test_thread_safety.py | 90 ++++++++----------- 3 files changed, 76 insertions(+), 75 deletions(-) diff --git a/packages/mrml-python/mrml.pyi b/packages/mrml-python/mrml.pyi index 289e3647..13d71b5b 100644 --- a/packages/mrml-python/mrml.pyi +++ b/packages/mrml-python/mrml.pyi @@ -64,12 +64,18 @@ class ParserOptions: class RenderOptions: """RenderOptions configures rendering behavior, including whether to disable comments and how to handle social icons and fonts.""" - - disable_comments: bool - social_icon_origin: Optional[str] - fonts: Optional[Dict[str, str]] - - def __init__(self) -> None: ... + def __init__( + self, + disable_comments: bool = False, + social_icon_origin: str | None = None, + fonts: Dict[str, str] | None = None, + ) -> None: ... + @property + def disable_comments(self) -> bool: ... + @property + def social_icon_origin(self) -> str | None: ... + @property + def fonts(self) -> Dict[str, str] | None: ... class Warning: @property diff --git a/packages/mrml-python/src/lib.rs b/packages/mrml-python/src/lib.rs index 52c7b277..f74a84ad 100644 --- a/packages/mrml-python/src/lib.rs +++ b/packages/mrml-python/src/lib.rs @@ -10,19 +10,19 @@ use mrml::prelude::parser::noop_loader::NoopIncludeLoader; use pyo3::exceptions::PyIOError; use pyo3::prelude::*; -#[pyclass] +#[pyclass(frozen)] #[derive(Clone, Debug, Default)] pub struct NoopIncludeLoaderOptions; -#[pyclass] +#[pyclass(frozen)] #[derive(Clone, Debug, Default)] pub struct MemoryIncludeLoaderOptions(HashMap); -#[pyclass] +#[pyclass(frozen)] #[derive(Clone, Debug, Default)] pub struct LocalIncludeLoaderOptions(PathBuf); -#[pyclass(eq, eq_int)] +#[pyclass(frozen, eq, eq_int)] #[derive(Clone, Debug, PartialEq, Eq)] pub enum HttpIncludeLoaderOptionsMode { Allow, @@ -35,14 +35,14 @@ impl Default for HttpIncludeLoaderOptionsMode { } } -#[pyclass] +#[pyclass(frozen)] #[derive(Clone, Debug, Default)] pub struct HttpIncludeLoaderOptions { mode: HttpIncludeLoaderOptionsMode, list: HashSet, } -#[pyclass] +#[pyclass(frozen)] #[derive(Clone, Debug)] pub enum ParserIncludeLoaderOptions { Noop(NoopIncludeLoaderOptions), @@ -119,10 +119,10 @@ pub fn http_loader( }) } -#[pyclass] +#[pyclass(frozen)] #[derive(Clone, Debug, Default)] pub struct ParserOptions { - #[pyo3(get, set)] + #[pyo3(get)] pub include_loader: ParserIncludeLoaderOptions, } @@ -144,22 +144,31 @@ impl From for mrml::prelude::parser::ParserOptions { } } -#[pyclass] +#[pyclass(frozen)] #[derive(Clone, Debug, Default)] pub struct RenderOptions { - #[pyo3(get, set)] + #[pyo3(get)] pub disable_comments: bool, - #[pyo3(get, set)] + #[pyo3(get)] pub social_icon_origin: Option, - #[pyo3(get, set)] + #[pyo3(get)] pub fonts: Option>, } #[pymethods] impl RenderOptions { #[new] - pub fn new() -> Self { - Self::default() + #[pyo3(signature = (disable_comments=false, social_icon_origin=None, fonts=None))] + pub fn new( + disable_comments: bool, + social_icon_origin: Option, + fonts: Option>, + ) -> Self { + Self { + disable_comments, + social_icon_origin, + fonts, + } } } @@ -182,10 +191,10 @@ impl From for mrml::prelude::render::RenderOptions { } } -#[pyclass] +#[pyclass(frozen)] #[derive(Clone, Debug, Default)] pub struct Warning { - #[pyo3(get, set)] + #[pyo3(get)] pub origin: Option, #[pyo3(get)] pub kind: &'static str, @@ -215,7 +224,7 @@ impl From for Warning { } } -#[pyclass] +#[pyclass(frozen)] #[derive(Clone, Debug, Default)] pub struct Output { #[pyo3(get)] diff --git a/packages/mrml-python/tests/test_thread_safety.py b/packages/mrml-python/tests/test_thread_safety.py index 44d76373..4c8bcc72 100644 --- a/packages/mrml-python/tests/test_thread_safety.py +++ b/packages/mrml-python/tests/test_thread_safety.py @@ -1,6 +1,7 @@ import concurrent.futures import mrml +import pytest def test_concurrent_simple_template(): @@ -17,14 +18,15 @@ def worker(): def test_concurrent_memory_loader(): - def worker(): - parser_options = mrml.ParserOptions( - include_loader=mrml.memory_loader( - { - "hello-world.mjml": "Hello World!", - } - ) + parser_options = mrml.ParserOptions( + include_loader=mrml.memory_loader( + { + "hello-world.mjml": "Hello World!", + } ) + ) + + def worker(): result = mrml.to_html( '', parser_options=parser_options, @@ -40,10 +42,11 @@ def worker(): def test_concurrent_local_loader(): + parser_options = mrml.ParserOptions( + include_loader=mrml.local_loader("./resources/partials") + ) + def worker(): - parser_options = mrml.ParserOptions( - include_loader=mrml.local_loader("./resources/partials") - ) result = mrml.to_html( '', parser_options=parser_options, @@ -59,13 +62,13 @@ def worker(): def test_concurrent_http_loader(): + http_loader = mrml.http_loader( + mode=mrml.HttpIncludeLoaderOptionsMode.Allow, + list=set(["https://gist.githubusercontent.com"]), + ) + parser_options = mrml.ParserOptions(include_loader=http_loader) + def worker(): - parser_options = mrml.ParserOptions( - include_loader=mrml.http_loader( - mode=mrml.HttpIncludeLoaderOptionsMode.Allow, - list=set(["https://gist.githubusercontent.com"]), - ) - ) result = mrml.to_html( """ @@ -90,6 +93,17 @@ def worker(): def test_concurrent_mixed_operations(): """Test different MRML operations running concurrently""" + memory_parser_options = mrml.ParserOptions( + include_loader=mrml.memory_loader( + { + "hello-world.mjml": "Hello World!", + } + ) + ) + + local_parser_options = mrml.ParserOptions( + include_loader=mrml.local_loader("./resources/partials") + ) def worker_simple(): result = mrml.to_html("") @@ -97,27 +111,17 @@ def worker_simple(): return "simple" def worker_memory(): - parser_options = mrml.ParserOptions( - include_loader=mrml.memory_loader( - { - "hello-world.mjml": "Hello World!", - } - ) - ) result = mrml.to_html( '', - parser_options=parser_options, + parser_options=memory_parser_options, ) assert result.content.startswith("") return "memory" def worker_local(): - parser_options = mrml.ParserOptions( - include_loader=mrml.local_loader("./resources/partials") - ) result = mrml.to_html( '', - parser_options=parser_options, + parser_options=local_parser_options, ) assert result.content.startswith("") return "local" @@ -137,27 +141,9 @@ def worker_local(): def test_render_options_thread_safety(): - """Test concurrent access with different render options""" - - def worker(disable_comments: bool): - render_options = mrml.RenderOptions() - render_options.disable_comments = disable_comments - result = mrml.to_html( - "", - render_options=render_options, - ) - assert result.content.startswith("") - return (disable_comments, result.content) - - with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: - task_count = 100 - futures = [] - for i in range(task_count): - futures.append(executor.submit(worker, i % 2 == 0)) - results = [f.result() for f in futures] - assert len(results) == task_count - for result in results: - if result[0]: - assert "" not in result[1] - else: - assert "" in result[1] + """Test mutation throws AttributeError""" + render_options = mrml.RenderOptions(disable_comments=True) + assert render_options.disable_comments + assert render_options.social_icon_origin is None + with pytest.raises(AttributeError) as _: + render_options.disable_comments = False From 98858782b3631bf55bee2fcbf3ca853a48ee823c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Drouet?= Date: Thu, 26 Dec 2024 17:41:44 +0100 Subject: [PATCH 06/11] ci(python): make sure it builds for python 3.10 and 3.13 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Drouet --- .github/workflows/mrml-python-main.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/mrml-python-main.yml b/.github/workflows/mrml-python-main.yml index a791f4d6..8f139510 100644 --- a/.github/workflows/mrml-python-main.yml +++ b/.github/workflows/mrml-python-main.yml @@ -26,18 +26,22 @@ jobs: testing: runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", "3.13"] + concurrency: - group: ${{ github.ref }}-mrml-python + group: ${{ github.ref }}-mrml-python-${{ matrix.python-version }} cancel-in-progress: true steps: - uses: actions/checkout@v4 # Use deadsnakes until https://github.com/actions/setup-python/issues/771 is closed - - name: Setup Python + - name: setup python uses: deadsnakes/action@v3.2.0 with: - python-version: "3.13" + python-version: ${{ matrix.python-version }} nogil: true - name: install cargo toolchain From d10d5ba77f01aab8309258ea723dfad6dac92195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Drouet?= Date: Thu, 26 Dec 2024 17:42:16 +0100 Subject: [PATCH 07/11] ci(python): use dadsnakes action and python 3.13 for release action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Drouet --- .github/workflows/mrml-python-release.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/mrml-python-release.yml b/.github/workflows/mrml-python-release.yml index 13cd5b37..71128871 100644 --- a/.github/workflows/mrml-python-release.yml +++ b/.github/workflows/mrml-python-release.yml @@ -37,9 +37,12 @@ jobs: manylinux: "auto" steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + # Use deadsnakes until https://github.com/actions/setup-python/issues/771 is closed + - name: setup python + uses: deadsnakes/action@v3.2.0 with: python-version: "3.13" + nogil: true" - name: build wheels uses: PyO3/maturin-action@v1 with: @@ -61,9 +64,12 @@ jobs: target: [x64, x86] steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + # Use deadsnakes until https://github.com/actions/setup-python/issues/771 is closed + - name: setup python + uses: deadsnakes/action@v3.2.0 with: python-version: "3.13" + nogil: true" architecture: ${{ matrix.target }} - name: build wheels uses: PyO3/maturin-action@v1 @@ -85,9 +91,12 @@ jobs: target: [x86_64, aarch64] steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + # Use deadsnakes until https://github.com/actions/setup-python/issues/771 is closed + - name: setup python + uses: deadsnakes/action@v3.2.0 with: python-version: "3.13" + nogil: true" - name: build wheels uses: PyO3/maturin-action@v1 with: From f4be79dc7c201f04b8808e8756204af5a53191f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Drouet?= Date: Thu, 26 Dec 2024 17:48:59 +0100 Subject: [PATCH 08/11] ci(python): only use deadsnakes action for 3.13 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Drouet --- .github/workflows/mrml-python-main.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/mrml-python-main.yml b/.github/workflows/mrml-python-main.yml index 8f139510..714fafca 100644 --- a/.github/workflows/mrml-python-main.yml +++ b/.github/workflows/mrml-python-main.yml @@ -37,8 +37,15 @@ jobs: steps: - uses: actions/checkout@v4 + - name: setup python + if: matrix.python-version != '3.13' + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + # Use deadsnakes until https://github.com/actions/setup-python/issues/771 is closed - name: setup python + if: matrix.python-version == '3.13' uses: deadsnakes/action@v3.2.0 with: python-version: ${{ matrix.python-version }} From bc9a6e76c599c569de87c9d37d289152624a2bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Drouet?= Date: Thu, 26 Dec 2024 20:32:59 +0100 Subject: [PATCH 09/11] ci(python): try to fix python 3.10 install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Drouet --- .github/workflows/mrml-python-main.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mrml-python-main.yml b/.github/workflows/mrml-python-main.yml index 714fafca..476aeca9 100644 --- a/.github/workflows/mrml-python-main.yml +++ b/.github/workflows/mrml-python-main.yml @@ -57,12 +57,15 @@ jobs: toolchain: stable profile: minimal + - name: install maturin + run: cargo install maturin --locked + - name: init python venv run: | - python3 -m pip install --upgrade pip + pip install --upgrade pip python3 -m venv env source env/bin/activate - python3 -m pip install pytest maturin + python3 -m pip install pytest maturin develop python3 -m pytest working-directory: packages/mrml-python From c0dd110ba5cd381ce8f9afb9b6b917db496946a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Drouet?= Date: Thu, 26 Dec 2024 20:49:43 +0100 Subject: [PATCH 10/11] build(python): set version in pyproject MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Drouet --- packages/mrml-python/pyproject.toml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/mrml-python/pyproject.toml b/packages/mrml-python/pyproject.toml index 2af64b0a..ed99a869 100644 --- a/packages/mrml-python/pyproject.toml +++ b/packages/mrml-python/pyproject.toml @@ -4,13 +4,14 @@ build-backend = "maturin" [project] name = "mrml" +version = "0.1.15" description = "A Python wrapper for MRML (Rust port of MJML)." readme = "readme.md" requires-python = ">=3.7" classifiers = [ - "Programming Language :: Rust", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", + "Programming Language :: Rust", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", ] [project.urls] From 4abfb63a22c1960f5bb77b743ea8985e479ad1b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Drouet?= Date: Thu, 26 Dec 2024 20:56:41 +0100 Subject: [PATCH 11/11] ci(python): move back maturin install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Drouet --- .github/workflows/mrml-python-main.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/mrml-python-main.yml b/.github/workflows/mrml-python-main.yml index 476aeca9..a1badbee 100644 --- a/.github/workflows/mrml-python-main.yml +++ b/.github/workflows/mrml-python-main.yml @@ -57,15 +57,12 @@ jobs: toolchain: stable profile: minimal - - name: install maturin - run: cargo install maturin --locked - - name: init python venv run: | pip install --upgrade pip python3 -m venv env source env/bin/activate - python3 -m pip install pytest + python3 -m pip install pytest maturin maturin develop python3 -m pytest working-directory: packages/mrml-python