py-fastplus 0.2.0__tar.gz → 0.2.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 (25) hide show
  1. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/.github/workflows/Publish.yml +6 -0
  2. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/Cargo.lock +1 -1
  3. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/Cargo.toml +1 -1
  4. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/PKG-INFO +1 -1
  5. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/src/field.rs +3 -0
  6. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/src/operator.rs +65 -11
  7. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/.githooks/pre-commit +0 -0
  8. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/.github/workflows/Commit.yml +0 -0
  9. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/.gitignore +0 -0
  10. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/LICENSE +0 -0
  11. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/README.md +0 -0
  12. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/examples/parse_demo.rs +0 -0
  13. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/pyproject.toml +0 -0
  14. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/python/fastplus/__about__.py +0 -0
  15. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/python/fastplus/__init__.py +0 -0
  16. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/python/fastplus/core.pyi +0 -0
  17. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/python/fastplus/parser.py +0 -0
  18. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/python/tests/test_all.py +0 -0
  19. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/src/ast.rs +0 -0
  20. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/src/fastplus.pest +0 -0
  21. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/src/lib.rs +0 -0
  22. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/src/parser.rs +0 -0
  23. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/src/python.rs +0 -0
  24. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/src/python_macro.rs +0 -0
  25. {py_fastplus-0.2.0 → py_fastplus-0.2.2}/uv.lock +0 -0
@@ -187,6 +187,12 @@ jobs:
187
187
  uses: actions/attest@v4
188
188
  with:
189
189
  subject-path: 'wheels-*/*'
190
+ - name: Recreate latest release
191
+ if: ${{ steps.release-tag.outputs.tag == 'dev-latest' || steps.release-tag.outputs.tag == 'main-latest' }}
192
+ env:
193
+ GH_TOKEN: ${{ github.token }}
194
+ RELEASE_TAG: ${{ steps.release-tag.outputs.tag }}
195
+ run: gh release delete "$RELEASE_TAG" --yes || true
190
196
  - name: Create or update GitHub Release
191
197
  uses: softprops/action-gh-release@v3
192
198
  with:
@@ -4,7 +4,7 @@ version = 4
4
4
 
5
5
  [[package]]
6
6
  name = "fastplus"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  dependencies = [
9
9
  "pest",
10
10
  "pest_derive",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "fastplus"
3
- version = "0.2.0"
3
+ version = "0.2.2"
4
4
  edition = "2024"
5
5
  readme = "README.md"
6
6
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: py-fastplus
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  License-File: LICENSE
@@ -218,6 +218,7 @@ impl Constant {
218
218
  | (Constant::Driver(_), Constant::Driver(_))
219
219
  | (Constant::Range(_), Constant::Range(_))
220
220
  | (Constant::Array(_), Constant::Array(_))
221
+ | (Constant::Array(_), Constant::Range(_))
221
222
  | (Constant::Set(_), Constant::Set(_))
222
223
  | (Constant::String(_), Constant::String(_)) => true,
223
224
  _ => false,
@@ -495,6 +496,8 @@ mod tests {
495
496
  assert!(Constant::Ratio(0.0).fit(&Constant::Zero));
496
497
  assert!(Constant::Ratio(0.0).fit(&Constant::One));
497
498
  assert!(!Constant::Ratio(0.0).fit(&Constant::PositiveInteger(2)));
499
+ assert!(Constant::Array(Vec::new()).fit(&Constant::Range(0.1)));
500
+ assert!(!Constant::Range(0.1).fit(&Constant::Array(Vec::new())));
498
501
 
499
502
  let expected = HashSet::from([1, 2, 3]);
500
503
  let actual = Constant::EnumInteger {
@@ -85,10 +85,7 @@ impl Operator {
85
85
  };
86
86
 
87
87
  let actual = Field::Constant(value.clone());
88
- let bucket_nan = self.name == "bucket"
89
- && matches!(name.as_str(), "range" | "buckets")
90
- && is_nan_constant(value);
91
- if !spec.param_type.fit(&actual) && !bucket_nan {
88
+ if !spec.param_type.fit(&actual) {
92
89
  return Err(OperatorCheckError::InvalidKeywordType {
93
90
  name: name.clone(),
94
91
  expected: Box::new(spec.param_type.clone()),
@@ -142,8 +139,34 @@ impl Operator {
142
139
  }
143
140
  }
144
141
  "bucket" => {
145
- if let (Some(range), Some(buckets)) = (kw_args.get("range"), kw_args.get("buckets"))
142
+ let range = kw_args.get("range").or_else(|| {
143
+ self.kw_args
144
+ .get("range")
145
+ .and_then(|spec| spec.default_value.as_ref())
146
+ });
147
+ let buckets = kw_args.get("buckets").or_else(|| {
148
+ self.kw_args
149
+ .get("buckets")
150
+ .and_then(|spec| spec.default_value.as_ref())
151
+ });
152
+ if let Some(buckets) = buckets
153
+ && !is_nan_constant(buckets)
154
+ && matches!(buckets, Constant::Range(_))
155
+ {
156
+ return Err(OperatorCheckError::InvalidExpression(
157
+ "bucket requires buckets to be an Array, not a Range, consider use the range param".to_string(),
158
+ ));
159
+ }
160
+ if let Some(Constant::Array(values)) = buckets
161
+ && !values
162
+ .windows(2)
163
+ .all(|pair| pair[0].is_finite() && pair[1].is_finite() && pair[1] > pair[0])
146
164
  {
165
+ return Err(OperatorCheckError::InvalidExpression(
166
+ "bucket requires buckets to be strictly increasing".to_string(),
167
+ ));
168
+ }
169
+ if let (Some(range), Some(buckets)) = (range, buckets) {
147
170
  let range_is_nan = is_nan_constant(range);
148
171
  let buckets_is_nan = is_nan_constant(buckets);
149
172
  if range_is_nan == buckets_is_nan {
@@ -1181,8 +1204,8 @@ define_operator_registry! {
1181
1204
  "bucket",
1182
1205
  [Matrix],
1183
1206
  {
1184
- "range" => (Range, None),
1185
- "buckets" => (Array, None),
1207
+ "range" => (Range, Some(Constant::NaN)),
1208
+ "buckets" => (Array, Some(Constant::NaN)),
1186
1209
  "skipBoth" => (Boolean, Some(Constant::Boolean(false))),
1187
1210
  "NaNGroup" => (Boolean, Some(Constant::Boolean(false))),
1188
1211
  },
@@ -1197,7 +1220,7 @@ define_operator_registry! {
1197
1220
  {
1198
1221
  "lower" => (Number, None),
1199
1222
  "upper" => (Number, None),
1200
- "inverse" => (Boolean, None),
1223
+ "inverse" => (Boolean, Some(Constant::Boolean(false))),
1201
1224
  "mask" => (Mask, Some(Constant::NaN)),
1202
1225
  },
1203
1226
  1,
@@ -1474,6 +1497,12 @@ mod tests {
1474
1497
  ));
1475
1498
 
1476
1499
  let bucket = get_operator("bucket").unwrap();
1500
+ assert!(matches!(
1501
+ bucket.apply(&[Field::Matrix], &HashMap::new()),
1502
+ Err(OperatorCheckError::InvalidExpression(message))
1503
+ if message.contains("exactly one")
1504
+ ));
1505
+
1477
1506
  let mut bucket_kwargs = HashMap::new();
1478
1507
  bucket_kwargs.insert("range".to_string(), Constant::Range(0.1));
1479
1508
  bucket_kwargs.insert("buckets".to_string(), Constant::Array(vec![0.0, 1.0]));
@@ -1483,17 +1512,42 @@ mod tests {
1483
1512
  if message.contains("exactly one")
1484
1513
  ));
1485
1514
 
1515
+ bucket_kwargs.insert("range".to_string(), Constant::Range(0.1));
1516
+ bucket_kwargs.insert("buckets".to_string(), Constant::Range(0.1));
1517
+ assert!(matches!(
1518
+ bucket.apply(&[Field::Matrix], &bucket_kwargs),
1519
+ Err(OperatorCheckError::InvalidExpression(message))
1520
+ if message.contains("Array, not a Range")
1521
+ ));
1522
+
1523
+ bucket_kwargs.insert("range".to_string(), Constant::Range(0.1));
1524
+ bucket_kwargs.insert("buckets".to_string(), Constant::Array(vec![0.0, 0.0, 1.0]));
1525
+ assert!(matches!(
1526
+ bucket.apply(&[Field::Matrix], &bucket_kwargs),
1527
+ Err(OperatorCheckError::InvalidExpression(message))
1528
+ if message.contains("strictly increasing")
1529
+ ));
1530
+
1531
+ bucket_kwargs.insert("buckets".to_string(), Constant::Array(vec![1.0, 0.0]));
1532
+ assert!(matches!(
1533
+ bucket.apply(&[Field::Matrix], &bucket_kwargs),
1534
+ Err(OperatorCheckError::InvalidExpression(message))
1535
+ if message.contains("strictly increasing")
1536
+ ));
1537
+
1486
1538
  bucket_kwargs.insert("range".to_string(), Constant::NaN);
1487
1539
  assert!(matches!(
1488
1540
  bucket.apply(&[Field::Matrix], &bucket_kwargs),
1489
- Ok(Field::Group)
1541
+ Err(OperatorCheckError::InvalidKeywordType { name, .. })
1542
+ if name == "range"
1490
1543
  ));
1491
1544
 
1545
+ bucket_kwargs.insert("range".to_string(), Constant::Range(0.1));
1492
1546
  bucket_kwargs.insert("buckets".to_string(), Constant::NaN);
1493
1547
  assert!(matches!(
1494
1548
  bucket.apply(&[Field::Matrix], &bucket_kwargs),
1495
- Err(OperatorCheckError::InvalidExpression(message))
1496
- if message.contains("exactly one")
1549
+ Err(OperatorCheckError::InvalidKeywordType { name, .. })
1550
+ if name == "buckets"
1497
1551
  ));
1498
1552
 
1499
1553
  let clamp = get_operator("clamp").unwrap();
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes