unitforge 0.4.1__tar.gz → 0.4.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.
Files changed (87) hide show
  1. {unitforge-0.4.1 → unitforge-0.4.2}/Cargo.lock +14 -38
  2. {unitforge-0.4.1 → unitforge-0.4.2}/Cargo.toml +4 -4
  3. {unitforge-0.4.1 → unitforge-0.4.2}/PKG-INFO +3 -1
  4. {unitforge-0.4.1 → unitforge-0.4.2}/install_hooks.sh +0 -0
  5. {unitforge-0.4.1 → unitforge-0.4.2}/src/impl_macros.rs +1 -1
  6. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/acceleration.rs +1 -1
  7. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/angle.rs +1 -1
  8. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/angular_acceleration.rs +1 -1
  9. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/angular_velocity.rs +1 -1
  10. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/area.rs +1 -1
  11. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/area_of_moment.rs +1 -1
  12. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/charge.rs +1 -1
  13. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/compliance.rs +1 -1
  14. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/density.rs +1 -1
  15. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/distance.rs +1 -1
  16. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/force.rs +1 -1
  17. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/force_area.rs +1 -1
  18. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/force_distance.rs +1 -1
  19. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/force_div_distance_power_four.rs +1 -1
  20. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/force_per_volume.rs +1 -1
  21. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/force_stress.rs +1 -1
  22. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/force_volume.rs +1 -1
  23. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/inverse_angle.rs +1 -1
  24. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/inverse_area.rs +1 -1
  25. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/inverse_distance.rs +1 -1
  26. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/inverse_stress.rs +1 -1
  27. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/mass.rs +1 -1
  28. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/mass_div_time_squared_volume.rs +1 -1
  29. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/mass_per_distance.rs +1 -1
  30. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/rotational_stiffness.rs +1 -1
  31. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/stiffness.rs +1 -1
  32. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/strain.rs +1 -1
  33. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/stress.rs +1 -1
  34. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/stress_squared.rs +1 -1
  35. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/time.rs +1 -1
  36. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/velocity.rs +1 -1
  37. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/velocity_squared.rs +1 -1
  38. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/voltage.rs +1 -1
  39. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities/volume.rs +1 -1
  40. {unitforge-0.4.1 → unitforge-0.4.2}/src/quantities.template.rs +20 -11
  41. {unitforge-0.4.1 → unitforge-0.4.2}/src/small_linalg/bindings/matrix3_py.template.rs +10 -8
  42. {unitforge-0.4.1 → unitforge-0.4.2}/src/small_linalg/bindings/vector3_py.template.rs +1 -1
  43. {unitforge-0.4.1 → unitforge-0.4.2}/test.sh +0 -0
  44. {unitforge-0.4.1 → unitforge-0.4.2}/unitforge_macros/Cargo.toml +1 -1
  45. unitforge-0.4.1/python/unitforge/__init__.pyi +0 -1776
  46. unitforge-0.4.1/python/unitforge/py.typed +0 -0
  47. {unitforge-0.4.1 → unitforge-0.4.2}/.gitignore +0 -0
  48. {unitforge-0.4.1 → unitforge-0.4.2}/.gitlab-ci.yml +0 -0
  49. {unitforge-0.4.1 → unitforge-0.4.2}/Readme.md +0 -0
  50. {unitforge-0.4.1 → unitforge-0.4.2}/Readme_py.md +0 -0
  51. {unitforge-0.4.1 → unitforge-0.4.2}/pyproject.toml +0 -0
  52. {unitforge-0.4.1 → unitforge-0.4.2}/python/unitforge/__init__.py +0 -0
  53. {unitforge-0.4.1 → unitforge-0.4.2}/scripts/generate_python_stubs.py +0 -0
  54. {unitforge-0.4.1 → unitforge-0.4.2}/src/internal.rs +0 -0
  55. {unitforge-0.4.1 → unitforge-0.4.2}/src/lib.rs +0 -0
  56. {unitforge-0.4.1 → unitforge-0.4.2}/src/prelude.rs +0 -0
  57. {unitforge-0.4.1 → unitforge-0.4.2}/src/relations.rs +0 -0
  58. {unitforge-0.4.1 → unitforge-0.4.2}/src/small_linalg/matrix2.rs +0 -0
  59. {unitforge-0.4.1 → unitforge-0.4.2}/src/small_linalg/matrix2x3.rs +0 -0
  60. {unitforge-0.4.1 → unitforge-0.4.2}/src/small_linalg/matrix3.rs +0 -0
  61. {unitforge-0.4.1 → unitforge-0.4.2}/src/small_linalg/matrix3x2.rs +0 -0
  62. {unitforge-0.4.1 → unitforge-0.4.2}/src/small_linalg/vector2.rs +0 -0
  63. {unitforge-0.4.1 → unitforge-0.4.2}/src/small_linalg/vector3.rs +0 -0
  64. {unitforge-0.4.1 → unitforge-0.4.2}/tests/common/mod.rs +0 -0
  65. {unitforge-0.4.1 → unitforge-0.4.2}/tests/matrix2.rs +0 -0
  66. {unitforge-0.4.1 → unitforge-0.4.2}/tests/matrix2x3.rs +0 -0
  67. {unitforge-0.4.1 → unitforge-0.4.2}/tests/matrix3.rs +0 -0
  68. {unitforge-0.4.1 → unitforge-0.4.2}/tests/matrix3x2.rs +0 -0
  69. {unitforge-0.4.1 → unitforge-0.4.2}/tests/ndarray_dot.rs +0 -0
  70. {unitforge-0.4.1 → unitforge-0.4.2}/tests/quantities.rs +0 -0
  71. {unitforge-0.4.1 → unitforge-0.4.2}/tests/quantity_core/construction.rs +0 -0
  72. {unitforge-0.4.1 → unitforge-0.4.2}/tests/quantity_core/enum_iter.rs +0 -0
  73. {unitforge-0.4.1 → unitforge-0.4.2}/tests/quantity_core/metadata.rs +0 -0
  74. {unitforge-0.4.1 → unitforge-0.4.2}/tests/quantity_core/normalization.rs +0 -0
  75. {unitforge-0.4.1 → unitforge-0.4.2}/tests/quantity_core/relations.rs +0 -0
  76. {unitforge-0.4.1 → unitforge-0.4.2}/tests/quantity_core/runtime_quantity.rs +0 -0
  77. {unitforge-0.4.1 → unitforge-0.4.2}/tests/quantity_core/scalar_edges.rs +0 -0
  78. {unitforge-0.4.1 → unitforge-0.4.2}/tests/quantity_core.rs +0 -0
  79. {unitforge-0.4.1 → unitforge-0.4.2}/tests/quantity_serde.rs +0 -0
  80. {unitforge-0.4.1 → unitforge-0.4.2}/tests/small_linalg_edge_cases.rs +0 -0
  81. {unitforge-0.4.1 → unitforge-0.4.2}/tests/small_linalg_interfaces.rs +0 -0
  82. {unitforge-0.4.1 → unitforge-0.4.2}/tests/test_quantities.py +0 -0
  83. {unitforge-0.4.1 → unitforge-0.4.2}/tests/test_small_linalg.py +0 -0
  84. {unitforge-0.4.1 → unitforge-0.4.2}/tests/typecheck/mypy_smoke.py +0 -0
  85. {unitforge-0.4.1 → unitforge-0.4.2}/tests/vector2.rs +0 -0
  86. {unitforge-0.4.1 → unitforge-0.4.2}/tests/vector3.rs +0 -0
  87. {unitforge-0.4.1 → unitforge-0.4.2}/unitforge_macros/src/lib.rs +0 -0
@@ -23,12 +23,6 @@ version = "0.5.0"
23
23
  source = "registry+https://github.com/rust-lang/crates.io-index"
24
24
  checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
25
25
 
26
- [[package]]
27
- name = "indoc"
28
- version = "2.0.6"
29
- source = "registry+https://github.com/rust-lang/crates.io-index"
30
- checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
31
-
32
26
  [[package]]
33
27
  name = "inventory"
34
28
  version = "0.3.20"
@@ -66,15 +60,6 @@ version = "2.7.4"
66
60
  source = "registry+https://github.com/rust-lang/crates.io-index"
67
61
  checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
68
62
 
69
- [[package]]
70
- name = "memoffset"
71
- version = "0.9.1"
72
- source = "registry+https://github.com/rust-lang/crates.io-index"
73
- checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
74
- dependencies = [
75
- "autocfg",
76
- ]
77
-
78
63
  [[package]]
79
64
  name = "ndarray"
80
65
  version = "0.16.1"
@@ -120,9 +105,9 @@ dependencies = [
120
105
 
121
106
  [[package]]
122
107
  name = "numpy"
123
- version = "0.26.0"
108
+ version = "0.28.0"
124
109
  source = "registry+https://github.com/rust-lang/crates.io-index"
125
- checksum = "9b2dba356160b54f5371b550575b78130a54718b4c6e46b3f33a6da74a27e78b"
110
+ checksum = "778da78c64ddc928ebf5ad9df5edf0789410ff3bdbf3619aed51cd789a6af1e2"
126
111
  dependencies = [
127
112
  "libc",
128
113
  "ndarray",
@@ -166,36 +151,33 @@ dependencies = [
166
151
 
167
152
  [[package]]
168
153
  name = "pyo3"
169
- version = "0.26.0"
154
+ version = "0.28.3"
170
155
  source = "registry+https://github.com/rust-lang/crates.io-index"
171
- checksum = "7ba0117f4212101ee6544044dae45abe1083d30ce7b29c4b5cbdfa2354e07383"
156
+ checksum = "91fd8e38a3b50ed1167fb981cd6fd60147e091784c427b8f7183a7ee32c31c12"
172
157
  dependencies = [
173
- "indoc",
174
158
  "inventory",
175
159
  "libc",
176
- "memoffset",
177
160
  "once_cell",
178
161
  "portable-atomic",
179
162
  "pyo3-build-config",
180
163
  "pyo3-ffi",
181
164
  "pyo3-macros",
182
- "unindent",
183
165
  ]
184
166
 
185
167
  [[package]]
186
168
  name = "pyo3-build-config"
187
- version = "0.26.0"
169
+ version = "0.28.3"
188
170
  source = "registry+https://github.com/rust-lang/crates.io-index"
189
- checksum = "4fc6ddaf24947d12a9aa31ac65431fb1b851b8f4365426e182901eabfb87df5f"
171
+ checksum = "e368e7ddfdeb98c9bca7f8383be1648fd84ab466bf2bc015e94008db6d35611e"
190
172
  dependencies = [
191
173
  "target-lexicon",
192
174
  ]
193
175
 
194
176
  [[package]]
195
177
  name = "pyo3-ffi"
196
- version = "0.26.0"
178
+ version = "0.28.3"
197
179
  source = "registry+https://github.com/rust-lang/crates.io-index"
198
- checksum = "025474d3928738efb38ac36d4744a74a400c901c7596199e20e45d98eb194105"
180
+ checksum = "7f29e10af80b1f7ccaf7f69eace800a03ecd13e883acfacc1e5d0988605f651e"
199
181
  dependencies = [
200
182
  "libc",
201
183
  "pyo3-build-config",
@@ -203,9 +185,9 @@ dependencies = [
203
185
 
204
186
  [[package]]
205
187
  name = "pyo3-macros"
206
- version = "0.26.0"
188
+ version = "0.28.3"
207
189
  source = "registry+https://github.com/rust-lang/crates.io-index"
208
- checksum = "2e64eb489f22fe1c95911b77c44cc41e7c19f3082fc81cce90f657cdc42ffded"
190
+ checksum = "df6e520eff47c45997d2fc7dd8214b25dd1310918bbb2642156ef66a67f29813"
209
191
  dependencies = [
210
192
  "proc-macro2",
211
193
  "pyo3-macros-backend",
@@ -215,9 +197,9 @@ dependencies = [
215
197
 
216
198
  [[package]]
217
199
  name = "pyo3-macros-backend"
218
- version = "0.26.0"
200
+ version = "0.28.3"
219
201
  source = "registry+https://github.com/rust-lang/crates.io-index"
220
- checksum = "100246c0ecf400b475341b8455a9213344569af29a3c841d29270e53102e0fcf"
202
+ checksum = "c4cdc218d835738f81c2338f822078af45b4afdf8b2e33cbb5916f108b813acb"
221
203
  dependencies = [
222
204
  "heck",
223
205
  "proc-macro2",
@@ -361,15 +343,9 @@ version = "1.0.18"
361
343
  source = "registry+https://github.com/rust-lang/crates.io-index"
362
344
  checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
363
345
 
364
- [[package]]
365
- name = "unindent"
366
- version = "0.2.4"
367
- source = "registry+https://github.com/rust-lang/crates.io-index"
368
- checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
369
-
370
346
  [[package]]
371
347
  name = "unitforge"
372
- version = "0.4.1"
348
+ version = "0.4.2"
373
349
  dependencies = [
374
350
  "ndarray",
375
351
  "num-traits",
@@ -384,7 +360,7 @@ dependencies = [
384
360
 
385
361
  [[package]]
386
362
  name = "unitforge_macros"
387
- version = "0.4.1"
363
+ version = "0.4.2"
388
364
  dependencies = [
389
365
  "regex",
390
366
  ]
@@ -4,7 +4,7 @@ crate-type = ["cdylib", "rlib"]
4
4
 
5
5
  [package]
6
6
  name = "unitforge"
7
- version = "0.4.1"
7
+ version = "0.4.2"
8
8
  edition = "2021"
9
9
  authors = ["Dr.Q team <info@askdrq.com>", "Henrik Stromberg <henrik@askdrq.com>"]
10
10
  description = "A library for unit and quantity consistent computations in Rust"
@@ -19,11 +19,11 @@ ndarray = { version = "0.16" }
19
19
  num-traits = "0.2.19"
20
20
  serde = { version = "1", optional = true, features = ["derive"] }
21
21
  serde_json = { version = "1.0.140", optional = true }
22
- pyo3 = { version = "0.26.0", features = ["extension-module", "auto-initialize", "multiple-pymethods"], optional = true }
23
- numpy = { version = "0.26.0", optional = true }
22
+ pyo3 = { version = "0.28.3", features = ["extension-module", "auto-initialize", "multiple-pymethods"], optional = true }
23
+ numpy = { version = "0.28.0", optional = true }
24
24
  strum = { version = "0.28.0", optional = true }
25
25
  strum_macros = { version = "0.28.0", optional = true }
26
- unitforge_macros = { version = "0.4.1", path = "unitforge_macros" }
26
+ unitforge_macros = { version = "0.4.2", path = "unitforge_macros" }
27
27
 
28
28
  [features]
29
29
  serde = ["dep:serde", "dep:serde_json", "ndarray/serde"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unitforge
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -9,7 +9,9 @@ Classifier: Topic :: Scientific/Engineering :: Physics
9
9
  Requires-Dist: numpy>=2.2.0
10
10
  Summary: A library for unit and quantity consistent computations in Rust
11
11
  Keywords: units,quantities,simulation,physics
12
+ Author: Dr.Q team <info@askdrq.com>, Henrik Stromberg <henrik@askdrq.com>
12
13
  Author-email: "Dr.Q team" <info@askdrq.com>, Henrik Stromberg <henrik@askdrq.com>
14
+ License: MIT
13
15
  Requires-Python: >=3.7
14
16
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
15
17
  Project-URL: Repository, https://gitlab.com/henrikjstromberg/unitforge
File without changes
@@ -27,7 +27,7 @@ macro_rules! impl_quantity {
27
27
  use $crate::Quantity;
28
28
 
29
29
  #[cfg(feature = "pyo3")]
30
- #[pyclass(module = "unitforge")]
30
+ #[pyclass(module = "unitforge", from_py_object)]
31
31
  #[repr(C)]
32
32
  #[derive(Copy, Clone)]
33
33
  pub struct $type {
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum AccelerationUnit {
8
8
  m_ssq,
9
9
  cm_ssq,
@@ -6,7 +6,7 @@ use std::f64::consts::PI;
6
6
  #[cfg_attr(feature = "strum", derive(EnumIter))]
7
7
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8
8
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
9
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
9
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
10
10
  pub enum AngleUnit {
11
11
  rad,
12
12
  deg,
@@ -5,7 +5,7 @@ use std::f64::consts::PI;
5
5
  #[cfg_attr(feature = "strum", derive(EnumIter))]
6
6
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7
7
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
8
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
8
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
9
9
  pub enum AngularAccelerationUnit {
10
10
  rad_ssq,
11
11
  deg_ssq,
@@ -5,7 +5,7 @@ use std::f64::consts::PI;
5
5
  #[cfg_attr(feature = "strum", derive(EnumIter))]
6
6
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7
7
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
8
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
8
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
9
9
  pub enum AngularVelocityUnit {
10
10
  rad_s,
11
11
  deg_s,
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum AreaUnit {
8
8
  kmsq,
9
9
  msq,
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum AreaOfMomentUnit {
8
8
  mhc,
9
9
  }
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum ChargeUnit {
8
8
  C,
9
9
  }
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum ComplianceUnit {
8
8
  m_N,
9
9
  }
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum DensityUnit {
8
8
  kg_dmcb,
9
9
  kg_mcb,
@@ -4,7 +4,7 @@ use crate::quantities::*;
4
4
  #[cfg_attr(feature = "strum", derive(EnumIter))]
5
5
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6
6
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
7
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
7
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
8
8
  pub enum DistanceUnit {
9
9
  km,
10
10
  m,
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum ForceUnit {
8
8
  GN,
9
9
  MN,
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum ForceAreaUnit {
8
8
  Nmsq,
9
9
  }
@@ -4,7 +4,7 @@ use crate::quantities::*;
4
4
  #[cfg_attr(feature = "strum", derive(EnumIter))]
5
5
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6
6
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
7
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
7
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
8
8
  pub enum ForceDistanceUnit {
9
9
  Nm,
10
10
  Ndm,
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum ForcePerDistancePowerFourUnit {
8
8
  N_mmhc,
9
9
  N_mhc,
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum ForcePerVolumeUnit {
8
8
  N_mcb,
9
9
  N_mmcb,
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum ForceStressUnit {
8
8
  Nsq_msq,
9
9
  }
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum ForceVolumeUnit {
8
8
  Nmcb,
9
9
  }
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum InverseAngleUnit {
8
8
  _rad,
9
9
  }
@@ -4,7 +4,7 @@ use crate::Area;
4
4
  #[cfg_attr(feature = "strum", derive(EnumIter))]
5
5
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6
6
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
7
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
7
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
8
8
  pub enum InverseAreaUnit {
9
9
  _msq,
10
10
  }
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum InverseDistanceUnit {
8
8
  _km,
9
9
  _m,
@@ -4,7 +4,7 @@ use crate::Stress;
4
4
  #[cfg_attr(feature = "strum", derive(EnumIter))]
5
5
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6
6
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
7
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
7
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
8
8
  pub enum InverseStressUnit {
9
9
  _Pa,
10
10
  }
@@ -4,7 +4,7 @@ use crate::quantities::*;
4
4
  #[cfg_attr(feature = "strum", derive(EnumIter))]
5
5
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6
6
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
7
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
7
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
8
8
  pub enum MassUnit {
9
9
  mg,
10
10
  g,
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum MassDivTimeSquaredVolumeUnit {
8
8
  kg_ssqmq,
9
9
  }
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum MassPerDistanceUnit {
8
8
  kg_m,
9
9
  }
@@ -4,7 +4,7 @@ use crate::PhysicsUnit;
4
4
  #[cfg_attr(feature = "strum", derive(EnumIter))]
5
5
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6
6
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
7
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
7
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
8
8
  pub enum RotationalStiffnessUnit {
9
9
  Nmm_deg,
10
10
  Nm_deg,
@@ -4,7 +4,7 @@ use crate::PhysicsUnit;
4
4
  #[cfg_attr(feature = "strum", derive(EnumIter))]
5
5
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6
6
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
7
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
7
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
8
8
  pub enum StiffnessUnit {
9
9
  N_mm,
10
10
  kN_mm,
@@ -4,7 +4,7 @@ use crate::{Distance, PhysicsUnit, Stress};
4
4
  #[cfg_attr(feature = "strum", derive(EnumIter))]
5
5
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6
6
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
7
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
7
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
8
8
  pub enum StrainUnit {
9
9
  m_m,
10
10
  dm_m,
@@ -4,7 +4,7 @@ use crate::quantities::*;
4
4
  #[cfg_attr(feature = "strum", derive(EnumIter))]
5
5
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6
6
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
7
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
7
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
8
8
  pub enum StressUnit {
9
9
  Pa,
10
10
  kPa,
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum StressSquaredUnit {
8
8
  Nsq_mmhc,
9
9
  }
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum TimeUnit {
8
8
  ns,
9
9
  us,
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum VelocityUnit {
8
8
  km_s,
9
9
  m_s,
@@ -4,7 +4,7 @@ use crate::quantities::*;
4
4
  #[cfg_attr(feature = "strum", derive(EnumIter))]
5
5
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6
6
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
7
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
7
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
8
8
  pub enum VelocitySquaredUnit {
9
9
  msq_ssq,
10
10
  }
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum VoltageUnit {
8
8
  V,
9
9
  kV,
@@ -3,7 +3,7 @@ use crate::impl_macros::macros::*;
3
3
  #[cfg_attr(feature = "strum", derive(EnumIter))]
4
4
  #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5
5
  #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq)]
6
- #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int))]
6
+ #[cfg_attr(feature = "pyo3", pyclass(eq, eq_int, from_py_object))]
7
7
  pub enum VolumeUnit {
8
8
  kmcb,
9
9
  mcb,
@@ -288,6 +288,10 @@ pub mod pyo3_capsule_api {
288
288
  pub const UNITFORGE_API_VERSION: u64 = 1;
289
289
  pub const CAPSULE_NAME: &str = "_UNITFORGE_API";
290
290
 
291
+ fn capsule_name() -> CString {
292
+ CString::new(CAPSULE_NAME).expect("capsule name must not contain null bytes")
293
+ }
294
+
291
295
  #[repr(C)]
292
296
  #[derive(Clone, Copy, Debug)]
293
297
  pub struct QuantityRepr {
@@ -625,26 +629,31 @@ pub mod pyo3_capsule_api {
625
629
  let capsule = PyCapsule::new_with_destructor(
626
630
  py,
627
631
  api,
628
- Some(CString::new(CAPSULE_NAME).unwrap()),
632
+ Some(capsule_name()),
629
633
  |_api, _ctx| {},
630
634
  )?;
631
635
  m.add(CAPSULE_NAME, capsule)?;
632
636
  Ok(())
633
637
  }
634
638
 
635
- pub fn get_api<'py>(py: Python<'py>, module: &Bound<'py, PyModule>) -> PyResult<&'py UnitforgeApiV1> {
636
- let capsule = module.getattr(CAPSULE_NAME)?.cast_into::<PyCapsule>()?;
637
- if !capsule.is_valid() {
639
+ pub fn get_api<'py>(
640
+ py: Python<'py>,
641
+ module: &Bound<'py, PyModule>,
642
+ ) -> PyResult<&'py UnitforgeApiV1> {
643
+ let capsule = module
644
+ .getattr(CAPSULE_NAME)?
645
+ .cast_into::<PyCapsule>()?;
646
+ let capsule_name = capsule_name();
647
+ let capsule_name = Some(capsule_name.as_c_str());
648
+
649
+ if !capsule.is_valid_checked(capsule_name) {
638
650
  return Err(PyValueError::new_err(format!(
639
651
  "Invalid capsule in unitforge module at attribute '{CAPSULE_NAME}'"
640
652
  )));
641
653
  }
642
- let ptr = capsule.pointer();
643
- if ptr.is_null() {
644
- return Err(PyValueError::new_err(format!(
645
- "Null pointer in unitforge capsule '{CAPSULE_NAME}'"
646
- )));
647
- }
648
- unsafe { Ok(&*ptr.cast::<UnitforgeApiV1>()) }
654
+
655
+ let ptr = capsule.pointer_checked(capsule_name)?;
656
+
657
+ unsafe { Ok(&*ptr.cast::<UnitforgeApiV1>().as_ptr()) }
649
658
  }
650
659
  }
@@ -2,8 +2,8 @@ use numpy::{PyReadonlyArray2, PyArray2};
2
2
  use num_traits::Zero;
3
3
  use crate::small_linalg::Matrix3;
4
4
 
5
- #[pyclass(module = "unitforge", eq)]
6
- #[derive(PartialEq)]
5
+ #[pyclass(module = "unitforge", eq, from_py_object)]
6
+ #[derive(PartialEq, Clone)]
7
7
  #[pyo3(name = "Matrix3")]
8
8
  pub struct Matrix3Py {
9
9
  pub data: [[Quantity; 3]; 3]
@@ -117,13 +117,15 @@ impl Matrix3Py {
117
117
  }
118
118
 
119
119
  for row in lst.iter() {
120
- let sublist = row.downcast::<PyList>()?;
120
+ let sublist = row.cast::<PyList>()?;
121
+
121
122
  if sublist.len() != 3 {
122
123
  return Err(PyValueError::new_err(
123
124
  "Each sub list must contain exactly 3 elements",
124
125
  ));
125
126
  }
126
127
  }
128
+
127
129
  let rust_unit = match unit {
128
130
  Some(py_unit) => {
129
131
  Unit::from_py_any(py_unit).map_err(|e| PyValueError::new_err(e.to_string()))?
@@ -135,7 +137,7 @@ impl Matrix3Py {
135
137
  let mut data = [[Quantity::FloatQuantity(0.0); 3]; 3];
136
138
  for (i, row) in lst.iter().enumerate() {
137
139
  let sublist = row
138
- .downcast::<PyList>()
140
+ .cast::<PyList>()
139
141
  .map_err(|_| PyValueError::new_err(format!("Row {i} is not a list")))?;
140
142
 
141
143
  for (j, elem) in sublist.iter().enumerate() {
@@ -146,12 +148,12 @@ impl Matrix3Py {
146
148
  "Element at row {i} column {j} is not convertible to float"
147
149
  ))
148
150
  })?;
149
- data[i][j] = rust_unit.to_quantity(val)
151
+
152
+ data[i][j] = rust_unit.to_quantity(val);
150
153
  }
151
154
  }
152
- Ok(Matrix3Py {
153
- data
154
- })
155
+
156
+ Ok(Matrix3Py { data })
155
157
  }
156
158
 
157
159
  #[pyo3(signature = (unit=None))]