philoch-bib-sdk 0.3.9__cp313-cp313-win_amd64.whl

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 (44) hide show
  1. philoch_bib_sdk/__init__.py +0 -0
  2. philoch_bib_sdk/_rust.cp313-win_amd64.pyd +0 -0
  3. philoch_bib_sdk/adapters/io/__init__.py +115 -0
  4. philoch_bib_sdk/adapters/io/csv/__init__.py +308 -0
  5. philoch_bib_sdk/adapters/io/ods/__init__.py +145 -0
  6. philoch_bib_sdk/adapters/plaintext/bibitem_reader.py +0 -0
  7. philoch_bib_sdk/adapters/tabular_data/read_journal_volume_number_index.py +58 -0
  8. philoch_bib_sdk/converters/latex.py +6 -0
  9. philoch_bib_sdk/converters/plaintext/author/formatter.py +34 -0
  10. philoch_bib_sdk/converters/plaintext/author/parser.py +83 -0
  11. philoch_bib_sdk/converters/plaintext/bib_string_formatter.py +8 -0
  12. philoch_bib_sdk/converters/plaintext/bibitem/bibkey_formatter.py +21 -0
  13. philoch_bib_sdk/converters/plaintext/bibitem/bibkey_parser.py +158 -0
  14. philoch_bib_sdk/converters/plaintext/bibitem/date_formatter.py +37 -0
  15. philoch_bib_sdk/converters/plaintext/bibitem/date_parser.py +62 -0
  16. philoch_bib_sdk/converters/plaintext/bibitem/formatter.py +182 -0
  17. philoch_bib_sdk/converters/plaintext/bibitem/pages_formatter.py +13 -0
  18. philoch_bib_sdk/converters/plaintext/bibitem/pages_parser.py +63 -0
  19. philoch_bib_sdk/converters/plaintext/bibitem/parser.py +415 -0
  20. philoch_bib_sdk/converters/plaintext/journal/formatter.py +25 -0
  21. philoch_bib_sdk/converters/plaintext/journal/parser.py +36 -0
  22. philoch_bib_sdk/converters/plaintext/shared/renderable_formatter.py +25 -0
  23. philoch_bib_sdk/interfaces/cli/__init__.py +3 -0
  24. philoch_bib_sdk/interfaces/cli/fuzzy_matching.py +135 -0
  25. philoch_bib_sdk/logic/__init__.py +39 -0
  26. philoch_bib_sdk/logic/default_models.py +315 -0
  27. philoch_bib_sdk/logic/functions/__init__.py +31 -0
  28. philoch_bib_sdk/logic/functions/comparator.py +414 -0
  29. philoch_bib_sdk/logic/functions/fuzzy_matcher.py +796 -0
  30. philoch_bib_sdk/logic/functions/journal_article_matcher.py +44 -0
  31. philoch_bib_sdk/logic/literals.py +98 -0
  32. philoch_bib_sdk/logic/models.py +366 -0
  33. philoch_bib_sdk/logic/models_staging.py +173 -0
  34. philoch_bib_sdk/procedures/fuzzy_matching.py +112 -0
  35. philoch_bib_sdk/py.typed +0 -0
  36. philoch_bib_sdk/rust_scorer/Cargo.lock +232 -0
  37. philoch_bib_sdk/rust_scorer/Cargo.toml +26 -0
  38. philoch_bib_sdk/rust_scorer/pyproject.toml +15 -0
  39. philoch_bib_sdk/rust_scorer/rust_scorer.pyi +65 -0
  40. philoch_bib_sdk/rust_scorer/src/lib.rs +362 -0
  41. philoch_bib_sdk-0.3.9.dist-info/METADATA +15 -0
  42. philoch_bib_sdk-0.3.9.dist-info/RECORD +44 -0
  43. philoch_bib_sdk-0.3.9.dist-info/WHEEL +4 -0
  44. philoch_bib_sdk-0.3.9.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,362 @@
1
+ use pyo3::prelude::*;
2
+ use rayon::prelude::*;
3
+ use std::cmp::Ordering;
4
+ use std::collections::BinaryHeap;
5
+ use strsim::jaro_winkler;
6
+
7
+ /// Normalize text: lowercase and collapse whitespace
8
+ fn normalize(s: &str) -> String {
9
+ s.to_lowercase()
10
+ .split_whitespace()
11
+ .collect::<Vec<_>>()
12
+ .join(" ")
13
+ }
14
+
15
+ /// Tokenize and sort tokens alphabetically
16
+ fn tokenize_and_sort(s: &str) -> Vec<&str> {
17
+ let mut tokens: Vec<&str> = s.split_whitespace().collect();
18
+ tokens.sort_unstable();
19
+ tokens
20
+ }
21
+
22
+ /// Internal token sort ratio returning f64 (0.0-100.0)
23
+ fn token_sort_ratio_f64(s1: &str, s2: &str) -> f64 {
24
+ if s1.is_empty() || s2.is_empty() {
25
+ return 0.0;
26
+ }
27
+
28
+ let norm1 = normalize(s1);
29
+ let norm2 = normalize(s2);
30
+
31
+ let sorted1 = tokenize_and_sort(&norm1).join(" ");
32
+ let sorted2 = tokenize_and_sort(&norm2).join(" ");
33
+
34
+ // Jaro-Winkler returns 0.0-1.0, scale to 0-100
35
+ jaro_winkler(&sorted1, &sorted2) * 100.0
36
+ }
37
+
38
+ /// Token sort ratio for Python: returns float 0.0-100.0
39
+ #[pyfunction]
40
+ fn token_sort_ratio(s1: &str, s2: &str) -> f64 {
41
+ token_sort_ratio_f64(s1, s2)
42
+ }
43
+
44
+ /// Input data for a single BibItem (simplified for Rust processing)
45
+ #[derive(Clone, Debug, FromPyObject)]
46
+ #[pyo3(from_item_all)]
47
+ struct BibItemData {
48
+ index: usize,
49
+ title: String,
50
+ author: String,
51
+ year: Option<i32>,
52
+ doi: Option<String>,
53
+ journal: Option<String>,
54
+ volume: Option<String>,
55
+ number: Option<String>,
56
+ pages: Option<String>,
57
+ publisher: Option<String>,
58
+ }
59
+
60
+ /// Result of scoring a candidate against a subject
61
+ #[derive(Clone, Debug, IntoPyObject)]
62
+ struct MatchResult {
63
+ candidate_index: usize,
64
+ total_score: f64,
65
+ title_score: f64,
66
+ author_score: f64,
67
+ date_score: f64,
68
+ bonus_score: f64,
69
+ }
70
+
71
+ impl PartialEq for MatchResult {
72
+ fn eq(&self, other: &Self) -> bool {
73
+ self.total_score == other.total_score
74
+ }
75
+ }
76
+
77
+ impl Eq for MatchResult {}
78
+
79
+ impl PartialOrd for MatchResult {
80
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
81
+ Some(self.cmp(other))
82
+ }
83
+ }
84
+
85
+ impl Ord for MatchResult {
86
+ fn cmp(&self, other: &Self) -> Ordering {
87
+ self.total_score
88
+ .partial_cmp(&other.total_score)
89
+ .unwrap_or(Ordering::Equal)
90
+ }
91
+ }
92
+
93
+ /// Score title similarity with bonuses
94
+ fn score_title(title1: &str, title2: &str, weight: f64) -> f64 {
95
+ if title1.is_empty() || title2.is_empty() {
96
+ return 0.0;
97
+ }
98
+
99
+ let norm1 = normalize(title1);
100
+ let norm2 = normalize(title2);
101
+
102
+ let raw_score = token_sort_ratio_f64(&norm1, &norm2);
103
+
104
+ // Check if one title contains the other (subtitle handling)
105
+ let one_contains_other = norm1.contains(&norm2) || norm2.contains(&norm1);
106
+
107
+ // Check for undesired keywords mismatch
108
+ let undesired = ["errata", "review"];
109
+ let has_undesired1: Vec<_> = undesired.iter().filter(|kw| norm1.contains(*kw)).collect();
110
+ let has_undesired2: Vec<_> = undesired.iter().filter(|kw| norm2.contains(*kw)).collect();
111
+ let kw_mismatch = has_undesired1.len() != has_undesired2.len()
112
+ || has_undesired1.iter().any(|kw| !has_undesired2.contains(kw));
113
+
114
+ let mut final_score = raw_score;
115
+
116
+ // High similarity bonus
117
+ if (raw_score > 85.0 || one_contains_other) && !kw_mismatch {
118
+ final_score += 100.0;
119
+ }
120
+
121
+ // Penalty for keyword mismatch
122
+ if kw_mismatch {
123
+ // penalty_count is at most 2 (size of undesired array), safe to multiply directly
124
+ let penalty_count = has_undesired1.len().abs_diff(has_undesired2.len());
125
+ final_score -= (penalty_count * 50) as f64;
126
+ }
127
+
128
+ final_score.max(0.0) * weight
129
+ }
130
+
131
+ /// Score author similarity with bonuses
132
+ fn score_author(author1: &str, author2: &str, weight: f64) -> f64 {
133
+ if author1.is_empty() || author2.is_empty() {
134
+ return 0.0;
135
+ }
136
+
137
+ let raw_score = token_sort_ratio_f64(author1, author2);
138
+ let mut final_score = raw_score;
139
+
140
+ if raw_score > 85.0 {
141
+ final_score += 100.0;
142
+ }
143
+
144
+ final_score * weight
145
+ }
146
+
147
+ /// Score date similarity
148
+ fn score_date(year1: Option<i32>, year2: Option<i32>, weight: f64) -> f64 {
149
+ match (year1, year2) {
150
+ (Some(y1), Some(y2)) => {
151
+ let diff = y1.abs_diff(y2);
152
+ let score = match diff {
153
+ 0 => 100.0,
154
+ 1..=3 => 100.0 - f64::from(diff) * 10.0,
155
+ _ if y1 / 10 == y2 / 10 => 30.0, // Same decade
156
+ _ => 0.0,
157
+ };
158
+ score * weight
159
+ }
160
+ _ => 0.0,
161
+ }
162
+ }
163
+
164
+ /// Score bonus fields (DOI, journal+vol+num, pages, publisher)
165
+ fn score_bonus(subject: &BibItemData, candidate: &BibItemData, weight: f64) -> f64 {
166
+ let mut bonus = 0.0;
167
+
168
+ // DOI exact match (highest confidence)
169
+ if let (Some(ref doi1), Some(ref doi2)) = (&subject.doi, &candidate.doi) {
170
+ if !doi1.is_empty() && doi1 == doi2 {
171
+ bonus += 100.0;
172
+ }
173
+ }
174
+
175
+ // Journal + Volume + Number match
176
+ if let (Some(ref j1), Some(ref j2)) = (&subject.journal, &candidate.journal) {
177
+ let norm_j1 = normalize(j1);
178
+ let norm_j2 = normalize(j2);
179
+ if !norm_j1.is_empty() && norm_j1 == norm_j2 {
180
+ let vol_match = match (&subject.volume, &candidate.volume) {
181
+ (Some(v1), Some(v2)) => !v1.is_empty() && v1 == v2,
182
+ _ => false,
183
+ };
184
+ let num_match = match (&subject.number, &candidate.number) {
185
+ (Some(n1), Some(n2)) => !n1.is_empty() && n1 == n2,
186
+ _ => false,
187
+ };
188
+ if vol_match && num_match {
189
+ bonus += 50.0;
190
+ }
191
+ }
192
+ }
193
+
194
+ // Pages match
195
+ if let (Some(ref p1), Some(ref p2)) = (&subject.pages, &candidate.pages) {
196
+ if !p1.is_empty() && p1 == p2 {
197
+ bonus += 20.0;
198
+ }
199
+ }
200
+
201
+ // Publisher match
202
+ if let (Some(ref pub1), Some(ref pub2)) = (&subject.publisher, &candidate.publisher) {
203
+ if !pub1.is_empty() && !pub2.is_empty() {
204
+ let pub_score = token_sort_ratio_f64(pub1, pub2);
205
+ if pub_score > 85.0 {
206
+ bonus += 10.0;
207
+ }
208
+ }
209
+ }
210
+
211
+ bonus * weight
212
+ }
213
+
214
+ /// Score a single candidate against a subject
215
+ fn score_candidate(subject: &BibItemData, candidate: &BibItemData) -> MatchResult {
216
+ // Weights: title=0.5, author=0.3, date=0.1, bonus=0.1
217
+ let title_score = score_title(&subject.title, &candidate.title, 0.5);
218
+ let author_score = score_author(&subject.author, &candidate.author, 0.3);
219
+ let date_score = score_date(subject.year, candidate.year, 0.1);
220
+ let bonus_score = score_bonus(subject, candidate, 0.1);
221
+
222
+ let total_score = title_score + author_score + date_score + bonus_score;
223
+
224
+ MatchResult {
225
+ candidate_index: candidate.index,
226
+ total_score,
227
+ title_score,
228
+ author_score,
229
+ date_score,
230
+ bonus_score,
231
+ }
232
+ }
233
+
234
+ /// Find top N matches for a single subject
235
+ fn find_top_matches(
236
+ subject: &BibItemData,
237
+ candidates: &[BibItemData],
238
+ top_n: usize,
239
+ min_score: f64,
240
+ ) -> Vec<MatchResult> {
241
+ // Quick DOI check first
242
+ if let Some(ref subject_doi) = subject.doi {
243
+ if !subject_doi.is_empty() {
244
+ for candidate in candidates {
245
+ if let Some(ref cand_doi) = candidate.doi {
246
+ if subject_doi == cand_doi {
247
+ return vec![score_candidate(subject, candidate)];
248
+ }
249
+ }
250
+ }
251
+ }
252
+ }
253
+
254
+ // Score all candidates and keep top N
255
+ let mut heap: BinaryHeap<MatchResult> = BinaryHeap::new();
256
+
257
+ for candidate in candidates {
258
+ let result = score_candidate(subject, candidate);
259
+ if result.total_score >= min_score {
260
+ heap.push(result);
261
+ }
262
+ }
263
+
264
+ // Extract top N
265
+ let mut results: Vec<MatchResult> = Vec::with_capacity(top_n.min(heap.len()));
266
+ for _ in 0..top_n {
267
+ if let Some(result) = heap.pop() {
268
+ results.push(result);
269
+ } else {
270
+ break;
271
+ }
272
+ }
273
+
274
+ results
275
+ }
276
+
277
+ /// Result for a single subject with its top matches
278
+ #[derive(Clone, Debug, IntoPyObject)]
279
+ struct SubjectMatchResult {
280
+ subject_index: usize,
281
+ matches: Vec<MatchResult>,
282
+ candidates_searched: usize,
283
+ }
284
+
285
+ /// Batch score multiple subjects against candidates in parallel.
286
+ #[pyfunction]
287
+ fn score_batch(
288
+ subjects: Vec<BibItemData>,
289
+ candidates: Vec<BibItemData>,
290
+ top_n: usize,
291
+ min_score: f64,
292
+ ) -> Vec<SubjectMatchResult> {
293
+ let candidates_len = candidates.len();
294
+
295
+ subjects
296
+ .par_iter()
297
+ .enumerate()
298
+ .map(|(idx, subject)| {
299
+ let matches = find_top_matches(subject, &candidates, top_n, min_score);
300
+ SubjectMatchResult {
301
+ subject_index: idx,
302
+ matches,
303
+ candidates_searched: candidates_len,
304
+ }
305
+ })
306
+ .collect()
307
+ }
308
+
309
+ /// A Python module implemented in Rust for fast fuzzy matching.
310
+ #[pymodule]
311
+ fn rust_scorer(m: &Bound<'_, PyModule>) -> PyResult<()> {
312
+ m.add_function(wrap_pyfunction!(token_sort_ratio, m)?)?;
313
+ m.add_function(wrap_pyfunction!(score_batch, m)?)?;
314
+ Ok(())
315
+ }
316
+
317
+ #[cfg(test)]
318
+ mod tests {
319
+ use super::*;
320
+
321
+ #[test]
322
+ fn test_token_sort_ratio_identical() {
323
+ let score = token_sort_ratio("hello world", "hello world");
324
+ assert!((score - 100.0).abs() < 0.001);
325
+ }
326
+
327
+ #[test]
328
+ fn test_token_sort_ratio_reordered() {
329
+ let score = token_sort_ratio("hello world", "world hello");
330
+ assert!((score - 100.0).abs() < 0.001);
331
+ }
332
+
333
+ #[test]
334
+ fn test_token_sort_ratio_different() {
335
+ let score = token_sort_ratio("hello world", "goodbye moon");
336
+ assert!(score < 50.0);
337
+ }
338
+
339
+ #[test]
340
+ fn test_token_sort_ratio_empty() {
341
+ assert!((token_sort_ratio("", "hello") - 0.0).abs() < 0.001);
342
+ assert!((token_sort_ratio("hello", "") - 0.0).abs() < 0.001);
343
+ }
344
+
345
+ #[test]
346
+ fn test_score_date_exact() {
347
+ let score = score_date(Some(2020), Some(2020), 1.0);
348
+ assert!((score - 100.0).abs() < 0.001);
349
+ }
350
+
351
+ #[test]
352
+ fn test_score_date_close() {
353
+ let score = score_date(Some(2020), Some(2021), 1.0);
354
+ assert!((score - 90.0).abs() < 0.001);
355
+ }
356
+
357
+ #[test]
358
+ fn test_score_date_same_decade() {
359
+ let score = score_date(Some(2020), Some(2025), 1.0);
360
+ assert!((score - 30.0).abs() < 0.001);
361
+ }
362
+ }
@@ -0,0 +1,15 @@
1
+ Metadata-Version: 2.4
2
+ Name: philoch-bib-sdk
3
+ Version: 0.3.9
4
+ License-File: LICENSE
5
+ Summary: Standard development kit for the Philosophie Bibliography project
6
+ Author-email: Luis Alejandro Bordo García <luis.bordo@philosophie.ch>
7
+ Maintainer-email: Luis Alejandro Bordo García <tech@philosophie.ch>
8
+ License: MIT
9
+ Requires-Python: >=3.13
10
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
11
+
12
+ # Philosophie.ch Bibliography SDK
13
+
14
+ This repository contains the standard development kit for the bibliography project of the [Philosophie.ch](https://philosophie.ch) association.
15
+
@@ -0,0 +1,44 @@
1
+ philoch_bib_sdk\__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ philoch_bib_sdk\_rust.cp313-win_amd64.pyd,sha256=CmkHcTY4RY9NBg-mNFN9NoaMvKTs51voH52AdjK26T8,286720
3
+ philoch_bib_sdk\adapters\io\__init__.py,sha256=Xxar4MA-37fBEd42PIlYmpA5G3WXmJ0JqKFAOoLnnhM,3466
4
+ philoch_bib_sdk\adapters\io\csv\__init__.py,sha256=YEU0h9VE4V91bmUJ45KTzJVplKp3IwGWaAAm_T6JKSo,10485
5
+ philoch_bib_sdk\adapters\io\ods\__init__.py,sha256=MTVnjP_hPI8hEibv7CYLD06gUMc_G1BPkvWqOvKLPD8,4874
6
+ philoch_bib_sdk\adapters\plaintext\bibitem_reader.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ philoch_bib_sdk\adapters\tabular_data\read_journal_volume_number_index.py,sha256=GLfBTilBm2dzzPBk0OEAi3q9rMO0O8umdzlfMNqX0_8,1805
8
+ philoch_bib_sdk\converters\latex.py,sha256=LuAKLrClECuBeaDQYJc7tIJECEV4h0kt0VE_ssv3s0o,236
9
+ philoch_bib_sdk\converters\plaintext\author\formatter.py,sha256=qoYKakj5BzJcTUI1XnANZcx70kqLq6KsY84C46RuAU4,1032
10
+ philoch_bib_sdk\converters\plaintext\author\parser.py,sha256=i2p7bsHR9yN9aW-zR0R5B5-9VIh3_9b_zEvUb_WfeAU,2866
11
+ philoch_bib_sdk\converters\plaintext\bib_string_formatter.py,sha256=5Z97u5GryHUgZcPhWE41thgWCB4wYu22pZ9et6nakmw,329
12
+ philoch_bib_sdk\converters\plaintext\bibitem\bibkey_formatter.py,sha256=YivsY0gblKJdC4yKYZ3tvWmKIvFXW4iNht9zhz8oFUs,565
13
+ philoch_bib_sdk\converters\plaintext\bibitem\bibkey_parser.py,sha256=TKHFQ9QeZ2Jgm3sFCjTqz_PDfous0amvz3DB0AJA51E,4991
14
+ philoch_bib_sdk\converters\plaintext\bibitem\date_formatter.py,sha256=G2mbaJidDg8avKBbro1rVcEznPC92XVTDQ4fSdmvhJo,1480
15
+ philoch_bib_sdk\converters\plaintext\bibitem\date_parser.py,sha256=3ZYGhhGqILzrvnwOvG4NPAjErLwVva0dfsN0B9eFomg,2242
16
+ philoch_bib_sdk\converters\plaintext\bibitem\formatter.py,sha256=EjSwHYAPn0YRjeLGK_rCi26Wtug6X5x5DFEKPjStn30,6298
17
+ philoch_bib_sdk\converters\plaintext\bibitem\pages_formatter.py,sha256=punzwm8ObrLJhsCOS1oKHSnTXMX_R_0Xs9M866J44pU,397
18
+ philoch_bib_sdk\converters\plaintext\bibitem\pages_parser.py,sha256=mMFviMZo5qHs0K_SXfbmjJ_nbmTGnSiKMrXyazzO2Qs,2018
19
+ philoch_bib_sdk\converters\plaintext\bibitem\parser.py,sha256=DakeRU4Dj8G1XaMf_ukJGUtgobLEoiUzg_eHVPcNORs,13536
20
+ philoch_bib_sdk\converters\plaintext\journal\formatter.py,sha256=o5ikU-aNFr6cxgzD0rBCjymHLpGrD6RGvNE8V2sX52s,599
21
+ philoch_bib_sdk\converters\plaintext\journal\parser.py,sha256=kT1YHwc9Am82WHRhaSWXaCeKitPn9QLWIbmIe8T1of4,1092
22
+ philoch_bib_sdk\converters\plaintext\shared\renderable_formatter.py,sha256=oS5u8RJpkRXaDTmauVqZi-uuXsyG-UQZMK2pgzSk-qo,686
23
+ philoch_bib_sdk\interfaces\cli\__init__.py,sha256=rKjz91BZYYu9suJyFMeS7GkBxaM1KEhL2G7EZj8JXdE,70
24
+ philoch_bib_sdk\interfaces\cli\fuzzy_matching.py,sha256=4OLbcHd9HZAiDzOxnjfmRwP3BTCz_UIGw6SlBO4Xwa4,3809
25
+ philoch_bib_sdk\logic\__init__.py,sha256=avTEfQfhr77hhsujj12GZ9MvTGZy2-DIQ1ncXTdGLFA,709
26
+ philoch_bib_sdk\logic\default_models.py,sha256=cHHKSFmNR29qBxQkPwelQ09sx66isHlAIr1PiIHAvH4,10467
27
+ philoch_bib_sdk\logic\functions\__init__.py,sha256=U2qNkMGxeFK-kBQYhD8kO6J2BpmjQPszOom3X_KvY7M,796
28
+ philoch_bib_sdk\logic\functions\comparator.py,sha256=enwy5-zkIDc5cXzp6eWvaz4LcVYDqxENlW-jRJ44IQI,13738
29
+ philoch_bib_sdk\logic\functions\fuzzy_matcher.py,sha256=JBdjj1soFhzomqir0y6bohkIcLS9DDSYnr5cuZ_LAhs,26483
30
+ philoch_bib_sdk\logic\functions\journal_article_matcher.py,sha256=Twv_UCRCMHEHyroG29BQjvkq_SHM60rjynfIywqCS5E,1330
31
+ philoch_bib_sdk\logic\literals.py,sha256=RLzpN3pJu0XZhkEUpMObr6ql-BdpMtpTcWeNw6aYBP4,1901
32
+ philoch_bib_sdk\logic\models.py,sha256=xHCQWFq_rEcX967icALD4oOQjM8AlLKLzXQ8SP-YNis,8681
33
+ philoch_bib_sdk\logic\models_staging.py,sha256=GdWT7IR4VGn9d3n2fcEWqGSjgHI5eLsbxC2zkIwj8ow,5880
34
+ philoch_bib_sdk\procedures\fuzzy_matching.py,sha256=J025vIaAHbwuQKzteGBgsM65VcRDeCNCzNrlqwFdKRE,4361
35
+ philoch_bib_sdk\py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
+ philoch_bib_sdk\rust_scorer\Cargo.lock,sha256=lXUfxNTAmUwdY8pORdeYPBvb9gKaTTutvBd57WKZG1o,6076
37
+ philoch_bib_sdk\rust_scorer\Cargo.toml,sha256=CsQ_LVSV34ZehikG7Z6nzQIzH9Kjcz1GBXB8YM34Cg0,443
38
+ philoch_bib_sdk\rust_scorer\pyproject.toml,sha256=91LsDiXEU49-Fy5JYKNf6JyWTMmtBcn_zRw3h2y1KAA,391
39
+ philoch_bib_sdk\rust_scorer\rust_scorer.pyi,sha256=CDT-4bpH9pOlEkxaqbVOzrZTiTIFzy5dsn8rqRT23Rs,1623
40
+ philoch_bib_sdk\rust_scorer\src\lib.rs,sha256=btLd9hhNdVVTfpVIrSpD9safSKp9AU7d8I5dgV6oGds,10377
41
+ philoch_bib_sdk-0.3.9.dist-info\METADATA,sha256=MKqlxSvctbz9Buvma3Ia0cDoYTzA5FUybhvn85BV73k,582
42
+ philoch_bib_sdk-0.3.9.dist-info\WHEEL,sha256=n_BmF69IyGtioVWE9c3M_zsEfe6-xMZy1v5HCL_6qE0,97
43
+ philoch_bib_sdk-0.3.9.dist-info\licenses\LICENSE,sha256=nplGobji9gkYmJxDBbBz2SKjZY27SUaqhqKkpUB-C30,1070
44
+ philoch_bib_sdk-0.3.9.dist-info\RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.11.5)
3
+ Root-Is-Purelib: false
4
+ Tag: cp313-cp313-win_amd64
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Philosophie.ch
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.