triplexanalytics 0.2.2__tar.gz → 0.4.0__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 (88) hide show
  1. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/Cargo.lock +3 -0
  2. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/PKG-INFO +9 -2
  3. {triplexanalytics-0.2.2/packages/triplex-python → triplexanalytics-0.4.0}/README.md +8 -1
  4. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/bucket.rs +4 -62
  5. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/lib.rs +16 -3
  6. triplexanalytics-0.4.0/crates/triplex-anonymizer/src/recipe.rs +584 -0
  7. triplexanalytics-0.4.0/crates/triplex-anonymizer/tests/salt.rs +61 -0
  8. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-datasetcard/Cargo.toml +2 -0
  9. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-datasetcard/README.md +2 -0
  10. triplexanalytics-0.4.0/crates/triplex-datasetcard/src/generalize.rs +67 -0
  11. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-datasetcard/src/lib.rs +26 -8
  12. triplexanalytics-0.4.0/crates/triplex-datasetcard/src/report.rs +323 -0
  13. triplexanalytics-0.4.0/crates/triplex-datasetcard/tests/report.rs +197 -0
  14. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-schemacast/src/contract.rs +36 -36
  15. triplexanalytics-0.4.0/crates/triplex-schemacast/tests/contract_yaml.rs +34 -0
  16. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0/packages/triplex-python}/README.md +8 -1
  17. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/pyproject.toml +1 -1
  18. triplexanalytics-0.2.2/crates/triplex-anonymizer/src/recipe.rs +0 -264
  19. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/Cargo.toml +0 -0
  20. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/Cargo.toml +0 -0
  21. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/README.md +0 -0
  22. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/fpe.rs +0 -0
  23. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/mapping.rs +0 -0
  24. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/mechanism.rs +0 -0
  25. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/partial_mask.rs +0 -0
  26. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/bayesnet/cells.rs +0 -0
  27. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/bayesnet/dp.rs +0 -0
  28. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/bayesnet/mod.rs +0 -0
  29. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/bayesnet/model.rs +0 -0
  30. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/bayesnet/score.rs +0 -0
  31. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/bayesnet/structure.rs +0 -0
  32. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/copula.rs +0 -0
  33. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/dp/accountant.rs +0 -0
  34. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/dp/histogram.rs +0 -0
  35. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/dp/kendall.rs +0 -0
  36. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/dp/mod.rs +0 -0
  37. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/dp/noise.rs +0 -0
  38. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/dp/report_html.rs +0 -0
  39. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/dp/suggest.rs +0 -0
  40. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/metrics.rs +0 -0
  41. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/mod.rs +0 -0
  42. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/numeric.rs +0 -0
  43. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/report_html.rs +0 -0
  44. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/report_script.rs +0 -0
  45. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/synthesize/sketch.rs +0 -0
  46. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/src/tokenize.rs +0 -0
  47. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/tests/bayesnet.rs +0 -0
  48. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/tests/dp.rs +0 -0
  49. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/tests/sketch.rs +0 -0
  50. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/tests/synthesis.rs +0 -0
  51. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-anonymizer/tests/synthesis_bytes.rs +0 -0
  52. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-core/Cargo.toml +0 -0
  53. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-core/README.md +0 -0
  54. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-core/src/error.rs +0 -0
  55. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-core/src/lib.rs +0 -0
  56. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-core/src/numeric.rs +0 -0
  57. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-datasetcard/examples/demo.rs +0 -0
  58. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-datasetcard/src/ebm.rs +0 -0
  59. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-datasetcard/src/suda.rs +0 -0
  60. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/Cargo.toml +0 -0
  61. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/README.md +0 -0
  62. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/formats/arrow_ipc_sink.rs +0 -0
  63. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/formats/arrow_ipc_source.rs +0 -0
  64. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/formats/csv_sink.rs +0 -0
  65. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/formats/csv_source.rs +0 -0
  66. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/formats/delimited.rs +0 -0
  67. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/formats/format.rs +0 -0
  68. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/formats/jsonl_sink.rs +0 -0
  69. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/formats/jsonl_source.rs +0 -0
  70. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/formats/mod.rs +0 -0
  71. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/formats/parquet_sink.rs +0 -0
  72. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/formats/parquet_source.rs +0 -0
  73. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/formats/tsv_sink.rs +0 -0
  74. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/formats/tsv_source.rs +0 -0
  75. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/lib.rs +0 -0
  76. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/shared/distribution.rs +0 -0
  77. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/shared/mod.rs +0 -0
  78. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/shared/sample.rs +0 -0
  79. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-io/src/shared/statistics.rs +0 -0
  80. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-schemacast/Cargo.toml +0 -0
  81. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-schemacast/README.md +0 -0
  82. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-schemacast/src/convert.rs +0 -0
  83. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-schemacast/src/lib.rs +0 -0
  84. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/crates/triplex-schemacast/src/semantic.rs +0 -0
  85. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/packages/triplex-python/Cargo.toml +0 -0
  86. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/packages/triplex-python/src/lib.rs +0 -0
  87. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/packages/triplex-python/tests/test_triplex.py +0 -0
  88. {triplexanalytics-0.2.2 → triplexanalytics-0.4.0}/python/triplex/__init__.py +0 -0
@@ -1389,6 +1389,7 @@ version = "0.0.0"
1389
1389
  dependencies = [
1390
1390
  "serde_json",
1391
1391
  "triplex-anonymizer",
1392
+ "triplex-datasetcard",
1392
1393
  "triplex-driftguard",
1393
1394
  "triplex-modelcard",
1394
1395
  "triplex-schemacast",
@@ -1425,6 +1426,8 @@ dependencies = [
1425
1426
  "serde",
1426
1427
  "serde_json",
1427
1428
  "triplex-core",
1429
+ "triplex-io",
1430
+ "triplex-schemacast",
1428
1431
  ]
1429
1432
 
1430
1433
  [[package]]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: triplexanalytics
3
- Version: 0.2.2
3
+ Version: 0.4.0
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: Intended Audience :: Science/Research
@@ -30,7 +30,14 @@ Triplex Analytics in plain Python: infer and check schema contracts, anonymize a
30
30
  synthetic data. No notebook, no browser, no server. The engine is the same native code the
31
31
  `triplex` command line runs.
32
32
 
33
- Not published yet. Install from a source checkout (needs the Rust toolchain):
33
+ ```sh
34
+ pip install triplexanalytics
35
+ ```
36
+
37
+ The distribution is called `triplexanalytics`; the import is `import triplex`. Wheels cover Linux
38
+ (x86_64 and aarch64), macOS and Windows, for Python 3.9 and later.
39
+
40
+ To build from a source checkout instead (needs the Rust toolchain):
34
41
 
35
42
  ```sh
36
43
  cd packages/triplex-python
@@ -4,7 +4,14 @@ Triplex Analytics in plain Python: infer and check schema contracts, anonymize a
4
4
  synthetic data. No notebook, no browser, no server. The engine is the same native code the
5
5
  `triplex` command line runs.
6
6
 
7
- Not published yet. Install from a source checkout (needs the Rust toolchain):
7
+ ```sh
8
+ pip install triplexanalytics
9
+ ```
10
+
11
+ The distribution is called `triplexanalytics`; the import is `import triplex`. Wheels cover Linux
12
+ (x86_64 and aarch64), macOS and Windows, for Python 3.9 and later.
13
+
14
+ To build from a source checkout instead (needs the Rust toolchain):
8
15
 
9
16
  ```sh
10
17
  cd packages/triplex-python
@@ -1,11 +1,14 @@
1
1
  //! Numeric generalization/bucketing — the Tier 1 k-anonymity
2
- //! mechanism. The named risk models a
2
+ //! mechanism. The bucketing itself (`bucket_value`, `bucket_numeric`) lives in
3
+ //! `triplex-datasetcard`, so masking and risk scoring generalize a number the
4
+ //! same way; this module wraps it as a masking mechanism. The named risk models a
3
5
  //! bucketed column can be checked against (`RiskModel`/`evaluate_risk_model`
4
6
  //! and friends) live in `triplex-datasetcard`,
5
7
  //! since scoring risk needs to run independently of any recipe, before a
6
8
  //! masking mechanism is even chosen.
7
9
 
8
10
  use crate::mechanism::Mechanism;
11
+ use triplex_datasetcard::bucket_value;
9
12
 
10
13
  pub(crate) struct Bucketer {
11
14
  width: u64,
@@ -25,37 +28,6 @@ impl Mechanism for Bucketer {
25
28
  }
26
29
  }
27
30
 
28
- /// Replaces a numeric value with the `"lo-hi"` range it falls in, e.g.
29
- /// width 10 turns `"23"` into `"20-29"`. A value that isn't a whole number
30
- /// has nothing to generalize and passes through unchanged.
31
- fn bucket_number(width: u64, n: i64) -> String {
32
- let width = width.max(1) as i64;
33
- let lo = n.div_euclid(width) * width;
34
- let hi = lo + width - 1;
35
- format!("{lo}-{hi}")
36
- }
37
-
38
- pub fn bucket_value(width: u64, value: &str) -> String {
39
- let Ok(n) = value.parse::<i64>() else {
40
- return value.to_string();
41
- };
42
- bucket_number(width, n)
43
- }
44
-
45
- /// Same bucketing as `bucket_value`, for a caller that already has a typed
46
- /// numeric value instead of a string to parse (e.g. `apps/triplex-web`'s
47
- /// risk-scoring wasm exports, which take a typed-array of `f64` straight
48
- /// from the browser instead of a JSON string of stringified cells).
49
- /// `NaN` represents a
50
- /// missing/non-numeric cell, passed through as an empty string, the same
51
- /// convention `bucket_value` uses for a value that fails to parse.
52
- pub fn bucket_numeric(width: u64, value: f64) -> String {
53
- if value.is_nan() {
54
- return String::new();
55
- }
56
- bucket_number(width, value as i64)
57
- }
58
-
59
31
  /// Generalizes a string value by keeping only its first `width` characters
60
32
  /// (Unicode scalar values, not bytes, so a multi-byte character is never
61
33
  /// split mid-codepoint) — the "automatic" string generalization ARX ships
@@ -82,36 +54,6 @@ pub fn generalize_string_prefix(width: usize, value: &str) -> String {
82
54
  mod tests {
83
55
  use super::*;
84
56
 
85
- #[test]
86
- fn buckets_a_number_into_its_width_sized_range() {
87
- assert_eq!(bucket_value(10, "23"), "20-29");
88
- assert_eq!(bucket_value(10, "20"), "20-29");
89
- assert_eq!(bucket_value(10, "29"), "20-29");
90
- assert_eq!(bucket_value(10, "30"), "30-39");
91
- }
92
-
93
- #[test]
94
- fn negative_numbers_bucket_toward_negative_infinity_not_toward_zero() {
95
- // div_euclid, not integer truncation: -1 must land in "-10--1", not "0-9".
96
- assert_eq!(bucket_value(10, "-1"), "-10--1");
97
- }
98
-
99
- #[test]
100
- fn a_non_numeric_value_passes_through_unchanged() {
101
- assert_eq!(bucket_value(10, "n/a"), "n/a");
102
- }
103
-
104
- #[test]
105
- fn bucket_numeric_matches_bucket_value_for_the_same_number() {
106
- assert_eq!(bucket_numeric(10, 23.0), bucket_value(10, "23"));
107
- assert_eq!(bucket_numeric(10, -1.0), bucket_value(10, "-1"));
108
- }
109
-
110
- #[test]
111
- fn bucket_numeric_treats_nan_as_the_missing_value_case() {
112
- assert_eq!(bucket_numeric(10, f64::NAN), "");
113
- }
114
-
115
57
  #[test]
116
58
  fn generalize_string_prefix_keeps_only_the_leading_characters() {
117
59
  assert_eq!(generalize_string_prefix(4, "3512AD"), "3512");
@@ -14,14 +14,16 @@ mod recipe;
14
14
  pub mod synthesize;
15
15
  mod tokenize;
16
16
 
17
- pub use bucket::{bucket_numeric, bucket_value, generalize_string_prefix};
17
+ pub use bucket::generalize_string_prefix;
18
18
  pub use fpe::fpe_mask;
19
19
  pub use mapping::{decrypt_mapping, encrypt_mapping, EncryptedMapping, MappingEntry};
20
20
  pub use partial_mask::partial_mask;
21
21
  pub use recipe::{
22
- load_recipe, verify_recipe_well_formed, AnonymizeColumn, AnonymizeMethod, AnonymizeRecipe,
22
+ load_recipe, recipe_from_yaml, verify_recipe_well_formed, AnonymizeColumn, AnonymizeMethod,
23
+ AnonymizeRecipe, RECIPE_VERSION,
23
24
  };
24
25
  pub use tokenize::hmac_token;
26
+ pub use triplex_datasetcard::{bucket_numeric, bucket_value};
25
27
  // Risk-model scoring moved to `triplex-datasetcard` — kept
26
28
  // re-exported here so nothing that already does
27
29
  // `use triplex_anonymizer::{RiskModel, ...}` breaks.
@@ -169,7 +171,12 @@ fn resolve_columns<'a>(
169
171
  drop_indices.insert(header_index);
170
172
  continue;
171
173
  }
172
- let salt = salt_for(declared)?;
174
+ // Only a keyed method needs a salt; the others give the same output for anyone.
175
+ let salt = if declared.method.is_keyed() {
176
+ salt_for(declared)?
177
+ } else {
178
+ Vec::new()
179
+ };
173
180
  resolved.push(ResolvedColumn {
174
181
  header_index,
175
182
  declared,
@@ -183,6 +190,12 @@ fn resolve_columns<'a>(
183
190
  /// itself is never a CLI argument, so it never lands in shell history or a
184
191
  /// process listing.
185
192
  fn salt_from_env(declared: &AnonymizeColumn) -> Result<Vec<u8>> {
193
+ if declared.salt_env.is_empty() {
194
+ return Err(Error::Validation(format!(
195
+ "column {:?} uses {:?}, which needs salt_env: the environment variable holding its salt",
196
+ declared.name, declared.method
197
+ )));
198
+ }
186
199
  std::env::var(&declared.salt_env)
187
200
  .map(String::into_bytes)
188
201
  .map_err(|_| Error::MissingEnvVar(declared.salt_env.clone()))