1use crate::generator::GeneratedCode;
11use crate::Language;
12
13#[derive(Debug, Clone)]
15pub struct FileIOPatternGenerator {
16 max_depth: usize,
17}
18
19impl FileIOPatternGenerator {
20 #[must_use]
22 pub fn new(max_depth: usize) -> Self {
23 Self { max_depth }
24 }
25
26 #[must_use]
28 pub fn generate(&self) -> Vec<GeneratedCode> {
29 let mut programs = Vec::new();
30
31 programs.extend(self.generate_basic_write_patterns());
33
34 if self.max_depth >= 2 {
36 programs.extend(self.generate_handle_passing_patterns());
37 }
38
39 if self.max_depth >= 3 {
41 programs.extend(self.generate_context_manager_patterns());
42 }
43
44 if self.max_depth >= 4 {
46 programs.extend(self.generate_mixed_io_patterns());
47 }
48
49 programs
50 }
51
52 fn generate_basic_write_patterns(&self) -> Vec<GeneratedCode> {
54 vec![
55 GeneratedCode {
57 code: r#"import sys
58
59def main():
60 sys.stdout.write("hello\n")
61"#
62 .to_string(),
63 language: Language::Python,
64 ast_depth: 1,
65 features: vec!["sys_stdout_write".to_string()],
66 },
67 GeneratedCode {
69 code: r#"def main():
70 print("hello")
71"#
72 .to_string(),
73 language: Language::Python,
74 ast_depth: 1,
75 features: vec!["print".to_string()],
76 },
77 GeneratedCode {
79 code: r#"def main():
80 f = open("output.txt", "w")
81 f.write("hello\n")
82 f.close()
83"#
84 .to_string(),
85 language: Language::Python,
86 ast_depth: 1,
87 features: vec!["file_write".to_string()],
88 },
89 GeneratedCode {
91 code: r#"import sys
92
93def main():
94 sys.stderr.write("error\n")
95"#
96 .to_string(),
97 language: Language::Python,
98 ast_depth: 1,
99 features: vec!["sys_stderr_write".to_string()],
100 },
101 ]
102 }
103
104 fn generate_handle_passing_patterns(&self) -> Vec<GeneratedCode> {
106 vec![
107 GeneratedCode {
109 code: r#"def write_to(f, msg: str):
110 f.write(msg)
111
112def main():
113 f = open("out.txt", "w")
114 write_to(f, "hello\n")
115 f.close()
116"#
117 .to_string(),
118 language: Language::Python,
119 ast_depth: 2,
120 features: vec!["file_handle_param".to_string()],
121 },
122 GeneratedCode {
124 code: r#"import sys
125
126def write_to(f, msg: str):
127 f.write(msg)
128
129def main():
130 write_to(sys.stdout, "hello\n")
131"#
132 .to_string(),
133 language: Language::Python,
134 ast_depth: 2,
135 features: vec!["stdout_handle_param".to_string()],
136 },
137 GeneratedCode {
139 code: r#"def get_output():
140 return open("out.txt", "w")
141
142def main():
143 f = get_output()
144 f.write("hello\n")
145 f.close()
146"#
147 .to_string(),
148 language: Language::Python,
149 ast_depth: 2,
150 features: vec!["file_handle_return".to_string()],
151 },
152 GeneratedCode {
154 code: r#"import sys
155
156def main():
157 use_file = True
158 if use_file:
159 f = open("out.txt", "w")
160 else:
161 f = sys.stdout
162 f.write("hello\n")
163"#
164 .to_string(),
165 language: Language::Python,
166 ast_depth: 2,
167 features: vec!["conditional_io_type".to_string()],
168 },
169 ]
170 }
171
172 fn generate_context_manager_patterns(&self) -> Vec<GeneratedCode> {
174 vec![
175 GeneratedCode {
177 code: r#"def main():
178 with open("output.txt", "w") as f:
179 f.write("hello\n")
180"#
181 .to_string(),
182 language: Language::Python,
183 ast_depth: 3,
184 features: vec!["context_manager_write".to_string()],
185 },
186 GeneratedCode {
188 code: r#"def main():
189 with open("input.txt", "r") as f:
190 content = f.read()
191 print(content)
192"#
193 .to_string(),
194 language: Language::Python,
195 ast_depth: 3,
196 features: vec!["context_manager_read".to_string()],
197 },
198 GeneratedCode {
200 code: r#"def main():
201 with open("input.txt", "r") as fin:
202 with open("output.txt", "w") as fout:
203 fout.write(fin.read())
204"#
205 .to_string(),
206 language: Language::Python,
207 ast_depth: 3,
208 features: vec!["nested_context_manager".to_string()],
209 },
210 GeneratedCode {
212 code: r#"def main():
213 with open("in.txt", "r") as fin, open("out.txt", "w") as fout:
214 fout.write(fin.read())
215"#
216 .to_string(),
217 language: Language::Python,
218 ast_depth: 3,
219 features: vec!["multiple_context_manager".to_string()],
220 },
221 GeneratedCode {
223 code: r#"def main():
224 with open("input.txt", "r") as f:
225 for line in f.readlines():
226 print(line)
227"#
228 .to_string(),
229 language: Language::Python,
230 ast_depth: 3,
231 features: vec!["readlines_iteration".to_string()],
232 },
233 GeneratedCode {
235 code: r#"def main():
236 with open("input.txt", "r") as f:
237 for line in f:
238 print(line)
239"#
240 .to_string(),
241 language: Language::Python,
242 ast_depth: 3,
243 features: vec!["file_iteration".to_string()],
244 },
245 ]
246 }
247
248 fn generate_mixed_io_patterns(&self) -> Vec<GeneratedCode> {
250 vec![
251 GeneratedCode {
253 code: r#"import sys
254
255def log_message(output, msg: str):
256 output.write(f"[LOG] {msg}\n")
257
258def main():
259 log_message(sys.stdout, "to stdout")
260 with open("log.txt", "w") as f:
261 log_message(f, "to file")
262"#
263 .to_string(),
264 language: Language::Python,
265 ast_depth: 4,
266 features: vec!["polymorphic_writer".to_string()],
267 },
268 GeneratedCode {
270 code: r#"import sys
271
272def main():
273 outputs = [sys.stdout, open("out.txt", "w")]
274 for out in outputs:
275 out.write("hello\n")
276"#
277 .to_string(),
278 language: Language::Python,
279 ast_depth: 4,
280 features: vec!["writer_list".to_string()],
281 },
282 GeneratedCode {
284 code: r#"import sys
285
286def get_output(use_file: bool):
287 if use_file:
288 return open("out.txt", "w")
289 return sys.stdout
290
291def main():
292 out = get_output(True)
293 out.write("hello\n")
294"#
295 .to_string(),
296 language: Language::Python,
297 ast_depth: 4,
298 features: vec!["conditional_output_factory".to_string()],
299 },
300 GeneratedCode {
302 code: r#"import sys
303
304def filter_lines(input_stream, output_stream, predicate):
305 for line in input_stream:
306 if predicate(line):
307 output_stream.write(line)
308
309def main():
310 with open("data.txt", "r") as f:
311 filter_lines(f, sys.stdout, lambda x: len(x) > 5)
312"#
313 .to_string(),
314 language: Language::Python,
315 ast_depth: 4,
316 features: vec!["stream_filter".to_string()],
317 },
318 GeneratedCode {
320 code: r#"import sys
321
322def analyze_log(log_file: str):
323 counts = {}
324 with open(log_file, "r") as f:
325 for line in f:
326 level = line.split()[0] if line.strip() else "UNKNOWN"
327 counts[level] = counts.get(level, 0) + 1
328 return counts
329
330def main():
331 result = analyze_log("app.log")
332 for level, count in result.items():
333 sys.stdout.write(f"{level}: {count}\n")
334"#
335 .to_string(),
336 language: Language::Python,
337 ast_depth: 4,
338 features: vec!["log_analyzer".to_string()],
339 },
340 GeneratedCode {
342 code: r#"import sys
343from typing import TextIO
344
345def process(input: TextIO, output: TextIO):
346 for line in input:
347 output.write(line.upper())
348
349def main():
350 with open("in.txt", "r") as fin:
351 process(fin, sys.stdout)
352"#
353 .to_string(),
354 language: Language::Python,
355 ast_depth: 4,
356 features: vec!["typed_io_streams".to_string()],
357 },
358 ]
359 }
360}
361
362#[derive(Debug, Clone)]
364pub struct JsonDictPatternGenerator {
365 max_depth: usize,
366}
367
368impl JsonDictPatternGenerator {
369 #[must_use]
371 pub fn new(max_depth: usize) -> Self {
372 Self { max_depth }
373 }
374
375 #[must_use]
377 pub fn generate(&self) -> Vec<GeneratedCode> {
378 let mut programs = Vec::new();
379
380 programs.extend(self.generate_basic_dict_patterns());
382
383 if self.max_depth >= 2 {
385 programs.extend(self.generate_json_patterns());
386 }
387
388 if self.max_depth >= 3 {
390 programs.extend(self.generate_nested_patterns());
391 }
392
393 programs
394 }
395
396 fn generate_basic_dict_patterns(&self) -> Vec<GeneratedCode> {
398 vec![
399 GeneratedCode {
401 code: r#"def main():
402 d = {"key": "value", "count": 42}
403 print(d["key"])
404"#
405 .to_string(),
406 language: Language::Python,
407 ast_depth: 1,
408 features: vec!["dict_literal".to_string()],
409 },
410 GeneratedCode {
412 code: r#"def main():
413 d = {"a": 1}
414 val = d.get("b", 0)
415 print(val)
416"#
417 .to_string(),
418 language: Language::Python,
419 ast_depth: 1,
420 features: vec!["dict_get_default".to_string()],
421 },
422 GeneratedCode {
424 code: r#"def main():
425 d = {"a": 1, "b": 2}
426 for k, v in d.items():
427 print(f"{k}: {v}")
428"#
429 .to_string(),
430 language: Language::Python,
431 ast_depth: 1,
432 features: vec!["dict_items_iteration".to_string()],
433 },
434 GeneratedCode {
436 code: r"def main():
437 nums = [1, 2, 3]
438 d = {str(n): n * n for n in nums}
439 print(d)
440"
441 .to_string(),
442 language: Language::Python,
443 ast_depth: 1,
444 features: vec!["dict_comprehension".to_string()],
445 },
446 ]
447 }
448
449 fn generate_json_patterns(&self) -> Vec<GeneratedCode> {
451 vec![
452 GeneratedCode {
454 code: r#"import json
455
456def main():
457 data = json.loads('{"name": "test", "value": 42}')
458 print(data["name"])
459"#
460 .to_string(),
461 language: Language::Python,
462 ast_depth: 2,
463 features: vec!["json_loads".to_string()],
464 },
465 GeneratedCode {
467 code: r#"import json
468
469def main():
470 data = {"name": "test", "value": 42}
471 output = json.dumps(data)
472 print(output)
473"#
474 .to_string(),
475 language: Language::Python,
476 ast_depth: 2,
477 features: vec!["json_dumps".to_string()],
478 },
479 GeneratedCode {
481 code: r#"import json
482
483def main():
484 with open("data.json", "r") as f:
485 data = json.load(f)
486 print(data)
487"#
488 .to_string(),
489 language: Language::Python,
490 ast_depth: 2,
491 features: vec!["json_load_file".to_string()],
492 },
493 GeneratedCode {
495 code: r#"import json
496
497def main():
498 data = {"name": "test", "value": 42}
499 with open("output.json", "w") as f:
500 json.dump(data, f)
501"#
502 .to_string(),
503 language: Language::Python,
504 ast_depth: 2,
505 features: vec!["json_dump_file".to_string()],
506 },
507 ]
508 }
509
510 fn generate_nested_patterns(&self) -> Vec<GeneratedCode> {
512 vec![
513 GeneratedCode {
515 code: r#"def main():
516 data = {"user": {"name": "alice", "age": 30}}
517 print(data["user"]["name"])
518"#
519 .to_string(),
520 language: Language::Python,
521 ast_depth: 3,
522 features: vec!["nested_dict_access".to_string()],
523 },
524 GeneratedCode {
526 code: r#"def main():
527 data = {"items": [1, 2, 3], "tags": ["a", "b"]}
528 for item in data["items"]:
529 print(item)
530"#
531 .to_string(),
532 language: Language::Python,
533 ast_depth: 3,
534 features: vec!["dict_list_values".to_string()],
535 },
536 GeneratedCode {
538 code: r#"def get_value(d: dict, key: str):
539 return d.get(key)
540
541def main():
542 data = {"a": 1, "b": 2}
543 key = "a"
544 print(get_value(data, key))
545"#
546 .to_string(),
547 language: Language::Python,
548 ast_depth: 3,
549 features: vec!["dynamic_key_access".to_string()],
550 },
551 GeneratedCode {
553 code: r#"import json
554
555def main():
556 data = json.loads('{"str": "hello", "num": 42, "arr": [1, 2], "obj": {"nested": true}}')
557 print(type(data["str"]))
558 print(type(data["num"]))
559 print(type(data["arr"]))
560"#
561 .to_string(),
562 language: Language::Python,
563 ast_depth: 3,
564 features: vec!["json_mixed_types".to_string()],
565 },
566 ]
567 }
568}
569
570#[derive(Debug, Clone)]
572pub struct ContextManagerPatternGenerator {
573 max_depth: usize,
574}
575
576impl ContextManagerPatternGenerator {
577 #[must_use]
579 pub fn new(max_depth: usize) -> Self {
580 Self { max_depth }
581 }
582
583 #[must_use]
585 pub fn generate(&self) -> Vec<GeneratedCode> {
586 let mut programs = Vec::new();
587
588 programs.extend(self.generate_basic_with_patterns());
590
591 if self.max_depth >= 2 {
593 programs.extend(self.generate_custom_context_manager_patterns());
594 }
595
596 if self.max_depth >= 3 {
598 programs.extend(self.generate_exception_patterns());
599 }
600
601 programs
602 }
603
604 fn generate_basic_with_patterns(&self) -> Vec<GeneratedCode> {
606 vec![
607 GeneratedCode {
609 code: r#"def main():
610 with open("test.txt", "w") as f:
611 f.write("hello")
612"#
613 .to_string(),
614 language: Language::Python,
615 ast_depth: 1,
616 features: vec!["basic_file_context".to_string()],
617 },
618 GeneratedCode {
620 code: r#"from contextlib import suppress
621
622def main():
623 with suppress(FileNotFoundError):
624 with open("missing.txt", "r") as f:
625 print(f.read())
626"#
627 .to_string(),
628 language: Language::Python,
629 ast_depth: 1,
630 features: vec!["suppress_context".to_string()],
631 },
632 GeneratedCode {
634 code: r#"def main():
635 with open("a.txt", "r") as a, open("b.txt", "w") as b:
636 b.write(a.read())
637"#
638 .to_string(),
639 language: Language::Python,
640 ast_depth: 1,
641 features: vec!["multiple_with_items".to_string()],
642 },
643 ]
644 }
645
646 fn generate_custom_context_manager_patterns(&self) -> Vec<GeneratedCode> {
648 vec![
649 GeneratedCode {
651 code: r"class Timer:
652 def __enter__(self):
653 self.start = 0
654 return self
655
656 def __exit__(self, exc_type, exc_val, exc_tb):
657 self.elapsed = 100
658 return False
659
660def main():
661 with Timer() as t:
662 x = 1 + 1
663 print(t.elapsed)
664"
665 .to_string(),
666 language: Language::Python,
667 ast_depth: 2,
668 features: vec!["class_context_manager".to_string()],
669 },
670 GeneratedCode {
672 code: r#"from contextlib import contextmanager
673
674@contextmanager
675def managed_resource():
676 print("acquiring")
677 yield "resource"
678 print("releasing")
679
680def main():
681 with managed_resource() as r:
682 print(r)
683"#
684 .to_string(),
685 language: Language::Python,
686 ast_depth: 2,
687 features: vec!["contextmanager_decorator".to_string()],
688 },
689 ]
690 }
691
692 fn generate_exception_patterns(&self) -> Vec<GeneratedCode> {
694 vec![
695 GeneratedCode {
697 code: r#"def main():
698 try:
699 with open("test.txt", "w") as f:
700 f.write("hello")
701 raise ValueError("test error")
702 except ValueError as e:
703 print(f"caught: {e}")
704"#
705 .to_string(),
706 language: Language::Python,
707 ast_depth: 3,
708 features: vec!["exception_in_context".to_string()],
709 },
710 GeneratedCode {
712 code: r#"class Suppressor:
713 def __enter__(self):
714 return self
715
716 def __exit__(self, exc_type, exc_val, exc_tb):
717 return True # Suppress all exceptions
718
719def main():
720 with Suppressor():
721 raise ValueError("this is suppressed")
722 print("continued after exception")
723"#
724 .to_string(),
725 language: Language::Python,
726 ast_depth: 3,
727 features: vec!["exception_suppression".to_string()],
728 },
729 ]
730 }
731}
732
733#[derive(Debug, Clone)]
735pub struct DepylerPatternGenerator {
736 max_depth: usize,
737}
738
739impl DepylerPatternGenerator {
740 #[must_use]
742 pub fn new(max_depth: usize) -> Self {
743 Self { max_depth }
744 }
745
746 #[must_use]
748 pub fn generate(&self) -> Vec<GeneratedCode> {
749 let mut programs = Vec::new();
750
751 let file_gen = FileIOPatternGenerator::new(self.max_depth);
753 programs.extend(file_gen.generate());
754
755 let json_gen = JsonDictPatternGenerator::new(self.max_depth);
757 programs.extend(json_gen.generate());
758
759 let ctx_gen = ContextManagerPatternGenerator::new(self.max_depth);
761 programs.extend(ctx_gen.generate());
762
763 programs
764 }
765
766 #[must_use]
768 pub fn generate_with_stats(&self) -> (Vec<GeneratedCode>, DepylerPatternStats) {
769 let file_gen = FileIOPatternGenerator::new(self.max_depth);
770 let file_patterns = file_gen.generate();
771
772 let json_gen = JsonDictPatternGenerator::new(self.max_depth);
773 let json_patterns = json_gen.generate();
774
775 let ctx_gen = ContextManagerPatternGenerator::new(self.max_depth);
776 let ctx_patterns = ctx_gen.generate();
777
778 let stats = DepylerPatternStats {
779 file_io_count: file_patterns.len(),
780 json_dict_count: json_patterns.len(),
781 context_manager_count: ctx_patterns.len(),
782 total_count: file_patterns.len() + json_patterns.len() + ctx_patterns.len(),
783 };
784
785 let mut programs = file_patterns;
786 programs.extend(json_patterns);
787 programs.extend(ctx_patterns);
788
789 (programs, stats)
790 }
791}
792
793#[derive(Debug, Clone)]
795pub struct DepylerPatternStats {
796 pub file_io_count: usize,
798 pub json_dict_count: usize,
800 pub context_manager_count: usize,
802 pub total_count: usize,
804}
805
806#[derive(Debug, Clone)]
812pub struct AdvancedDepylerPatternGenerator {
813 max_depth: usize,
814}
815
816impl AdvancedDepylerPatternGenerator {
817 #[must_use]
819 pub fn new(max_depth: usize) -> Self {
820 Self { max_depth }
821 }
822
823 #[must_use]
825 pub fn generate(&self) -> Vec<GeneratedCode> {
826 let mut programs = Vec::new();
827
828 programs.extend(self.generate_option_path_patterns());
830
831 if self.max_depth >= 2 {
833 programs.extend(self.generate_trait_object_patterns());
834 }
835
836 if self.max_depth >= 3 {
838 programs.extend(self.generate_dynamic_value_patterns());
839 }
840
841 if self.max_depth >= 4 {
843 programs.extend(self.generate_enter_exit_patterns());
844 }
845
846 programs
847 }
848
849 fn generate_option_path_patterns(&self) -> Vec<GeneratedCode> {
851 vec![
852 GeneratedCode {
854 code: r#"def process_file(filename: str = None):
855 if filename is None:
856 filename = "default.txt"
857 with open(filename, "r") as f:
858 return f.read()
859
860def main():
861 result = process_file()
862 print(result)
863"#
864 .to_string(),
865 language: Language::Python,
866 ast_depth: 1,
867 features: vec!["option_path_default".to_string()],
868 },
869 GeneratedCode {
871 code: r#"def get_config_path(override: str = None) -> str:
872 if override:
873 return override
874 return "config.json"
875
876def main():
877 path = get_config_path()
878 with open(path, "r") as f:
879 print(f.read())
880"#
881 .to_string(),
882 language: Language::Python,
883 ast_depth: 1,
884 features: vec!["option_path_override".to_string()],
885 },
886 GeneratedCode {
888 code: r#"def main():
889 config = {"output": "result.txt"}
890 path = config.get("output", "default.txt")
891 with open(path, "w") as f:
892 f.write("data")
893"#
894 .to_string(),
895 language: Language::Python,
896 ast_depth: 1,
897 features: vec!["option_path_dict_get".to_string()],
898 },
899 GeneratedCode {
901 code: r#"import os
902
903def main():
904 path = os.environ.get("OUTPUT_FILE") or "output.txt"
905 with open(path, "w") as f:
906 f.write("result")
907"#
908 .to_string(),
909 language: Language::Python,
910 ast_depth: 1,
911 features: vec!["option_path_or_fallback".to_string()],
912 },
913 ]
914 }
915
916 fn generate_trait_object_patterns(&self) -> Vec<GeneratedCode> {
918 vec![
919 GeneratedCode {
921 code: r#"import sys
922
923def get_writer(use_stdout: bool):
924 if use_stdout:
925 return sys.stdout
926 return open("output.txt", "w")
927
928def main():
929 writer = get_writer(True)
930 writer.write("hello\n")
931"#
932 .to_string(),
933 language: Language::Python,
934 ast_depth: 2,
935 features: vec!["trait_object_conditional_return".to_string()],
936 },
937 GeneratedCode {
939 code: r#"import sys
940
941def main():
942 verbose = True
943 out = sys.stdout if verbose else open("log.txt", "w")
944 out.write("message\n")
945"#
946 .to_string(),
947 language: Language::Python,
948 ast_depth: 2,
949 features: vec!["trait_object_ternary".to_string()],
950 },
951 GeneratedCode {
953 code: r#"import sys
954
955def write_report(output, data: str):
956 output.write(f"Report: {data}\n")
957 output.write("=" * 40 + "\n")
958
959def main():
960 write_report(sys.stdout, "summary")
961 with open("report.txt", "w") as f:
962 write_report(f, "detailed")
963"#
964 .to_string(),
965 language: Language::Python,
966 ast_depth: 2,
967 features: vec!["trait_object_param_both_types".to_string()],
968 },
969 GeneratedCode {
971 code: r#"import sys
972
973def broadcast(writers: list, msg: str):
974 for w in writers:
975 w.write(msg)
976
977def main():
978 with open("log.txt", "w") as f:
979 broadcast([sys.stdout, f], "broadcast message\n")
980"#
981 .to_string(),
982 language: Language::Python,
983 ast_depth: 2,
984 features: vec!["trait_object_list_mixed".to_string()],
985 },
986 GeneratedCode {
988 code: r#"import sys
989
990class Logger:
991 def __init__(self, filename: str = None):
992 if filename:
993 self.output = open(filename, "w")
994 else:
995 self.output = sys.stdout
996
997 def log(self, msg: str):
998 self.output.write(f"[LOG] {msg}\n")
999
1000def main():
1001 logger = Logger()
1002 logger.log("test message")
1003"#
1004 .to_string(),
1005 language: Language::Python,
1006 ast_depth: 2,
1007 features: vec!["trait_object_class_field".to_string()],
1008 },
1009 ]
1010 }
1011
1012 fn generate_dynamic_value_patterns(&self) -> Vec<GeneratedCode> {
1014 vec![
1015 GeneratedCode {
1017 code: r#"import json
1018
1019def parse_config(json_str: str) -> str:
1020 config = json.loads(json_str)
1021 name = config["name"]
1022 return name
1023
1024def main():
1025 result = parse_config('{"name": "test"}')
1026 print(result)
1027"#
1028 .to_string(),
1029 language: Language::Python,
1030 ast_depth: 3,
1031 features: vec!["value_json_to_dict_field".to_string()],
1032 },
1033 GeneratedCode {
1035 code: r#"import json
1036
1037def get_items(json_str: str) -> list:
1038 data = json.loads(json_str)
1039 items = data["items"]
1040 return [item["name"] for item in items]
1041
1042def main():
1043 result = get_items('{"items": [{"name": "a"}, {"name": "b"}]}')
1044 print(result)
1045"#
1046 .to_string(),
1047 language: Language::Python,
1048 ast_depth: 3,
1049 features: vec!["value_json_nested_iteration".to_string()],
1050 },
1051 GeneratedCode {
1053 code: r#"import json
1054
1055def process_response(json_str: str):
1056 response = json.loads(json_str)
1057 if response["status"] == "ok":
1058 data = response["data"]
1059 count = data["count"]
1060 return count
1061 return 0
1062
1063def main():
1064 result = process_response('{"status": "ok", "data": {"count": 42}}')
1065 print(result)
1066"#
1067 .to_string(),
1068 language: Language::Python,
1069 ast_depth: 3,
1070 features: vec!["value_json_conditional_access".to_string()],
1071 },
1072 GeneratedCode {
1074 code: r#"import json
1075
1076def merge_configs(base: dict, override_json: str) -> dict:
1077 override = json.loads(override_json)
1078 result = base.copy()
1079 result.update(override)
1080 return result
1081
1082def main():
1083 base = {"debug": False, "port": 8080}
1084 merged = merge_configs(base, '{"debug": true}')
1085 print(merged["debug"])
1086"#
1087 .to_string(),
1088 language: Language::Python,
1089 ast_depth: 3,
1090 features: vec!["value_dict_json_merge".to_string()],
1091 },
1092 ]
1093 }
1094
1095 fn generate_enter_exit_patterns(&self) -> Vec<GeneratedCode> {
1097 vec![
1098 GeneratedCode {
1100 code: r#"class Connection:
1101 def __init__(self, host: str):
1102 self.host = host
1103 self.connected = False
1104
1105 def __enter__(self):
1106 self.connected = True
1107 return self
1108
1109 def __exit__(self, exc_type, exc_val, exc_tb):
1110 self.connected = False
1111 return False
1112
1113 def query(self, sql: str) -> str:
1114 return f"Result from {self.host}"
1115
1116def main():
1117 with Connection("localhost") as conn:
1118 result = conn.query("SELECT 1")
1119 print(result)
1120"#
1121 .to_string(),
1122 language: Language::Python,
1123 ast_depth: 4,
1124 features: vec!["enter_returns_self".to_string()],
1125 },
1126 GeneratedCode {
1128 code: r#"class FileManager:
1129 def __init__(self, filename: str):
1130 self.filename = filename
1131 self.file = None
1132
1133 def __enter__(self):
1134 self.file = open(self.filename, "w")
1135 return self.file
1136
1137 def __exit__(self, exc_type, exc_val, exc_tb):
1138 if self.file:
1139 self.file.close()
1140 return False
1141
1142def main():
1143 with FileManager("output.txt") as f:
1144 f.write("managed write")
1145"#
1146 .to_string(),
1147 language: Language::Python,
1148 ast_depth: 4,
1149 features: vec!["enter_returns_different".to_string()],
1150 },
1151 GeneratedCode {
1153 code: r#"class Timer:
1154 def __enter__(self):
1155 self.start = 0
1156 return self
1157
1158 def __exit__(self, *args):
1159 self.elapsed = 100
1160 return False
1161
1162def main():
1163 with Timer() as t:
1164 with open("data.txt", "w") as f:
1165 f.write("timed write")
1166 print(f"Elapsed: {t.elapsed}")
1167"#
1168 .to_string(),
1169 language: Language::Python,
1170 ast_depth: 4,
1171 features: vec!["enter_nested_different_types".to_string()],
1172 },
1173 GeneratedCode {
1175 code: r#"class TransactionManager:
1176 def __init__(self):
1177 self.committed = False
1178
1179 def __enter__(self):
1180 print("Starting transaction")
1181 return self
1182
1183 def __exit__(self, exc_type, exc_val, exc_tb):
1184 if exc_type is None:
1185 self.committed = True
1186 print("Committed")
1187 else:
1188 print("Rolled back")
1189 return False
1190
1191 def execute(self, query: str):
1192 print(f"Executing: {query}")
1193
1194def main():
1195 with TransactionManager() as tx:
1196 tx.execute("INSERT INTO users VALUES (1)")
1197"#
1198 .to_string(),
1199 language: Language::Python,
1200 ast_depth: 4,
1201 features: vec!["exit_exception_handling".to_string()],
1202 },
1203 ]
1204 }
1205}
1206
1207#[cfg(test)]
1208mod tests {
1209 use super::*;
1210
1211 #[test]
1212 fn test_file_io_generator_basic() {
1213 let gen = FileIOPatternGenerator::new(1);
1214 let programs = gen.generate();
1215 assert_eq!(programs.len(), 4);
1216 assert!(programs.iter().all(|p| p.language == Language::Python));
1217 }
1218
1219 #[test]
1220 fn test_file_io_generator_full_depth() {
1221 let gen = FileIOPatternGenerator::new(4);
1222 let programs = gen.generate();
1223 assert_eq!(programs.len(), 20);
1224
1225 let features: Vec<_> = programs.iter().flat_map(|p| &p.features).collect();
1227 assert!(features.iter().any(|f| f.contains("stdout")));
1228 assert!(features.iter().any(|f| f.contains("context_manager")));
1229 assert!(features.iter().any(|f| f.contains("polymorphic")));
1230 }
1231
1232 #[test]
1233 fn test_json_dict_generator_basic() {
1234 let gen = JsonDictPatternGenerator::new(1);
1235 let programs = gen.generate();
1236 assert_eq!(programs.len(), 4);
1237 }
1238
1239 #[test]
1240 fn test_json_dict_generator_full_depth() {
1241 let gen = JsonDictPatternGenerator::new(3);
1242 let programs = gen.generate();
1243 assert_eq!(programs.len(), 12);
1244
1245 let features: Vec<_> = programs.iter().flat_map(|p| &p.features).collect();
1246 assert!(features.iter().any(|f| f.contains("json_loads")));
1247 assert!(features.iter().any(|f| f.contains("nested")));
1248 }
1249
1250 #[test]
1251 fn test_context_manager_generator_basic() {
1252 let gen = ContextManagerPatternGenerator::new(1);
1253 let programs = gen.generate();
1254 assert_eq!(programs.len(), 3);
1255 }
1256
1257 #[test]
1258 fn test_context_manager_generator_full_depth() {
1259 let gen = ContextManagerPatternGenerator::new(3);
1260 let programs = gen.generate();
1261 assert_eq!(programs.len(), 7);
1262 }
1263
1264 #[test]
1265 fn test_combined_generator() {
1266 let gen = DepylerPatternGenerator::new(4);
1267 let programs = gen.generate();
1268 assert_eq!(programs.len(), 39); }
1270
1271 #[test]
1272 fn test_combined_generator_with_stats() {
1273 let gen = DepylerPatternGenerator::new(4);
1274 let (programs, stats) = gen.generate_with_stats();
1275
1276 assert_eq!(stats.file_io_count, 20);
1277 assert_eq!(stats.json_dict_count, 12);
1278 assert_eq!(stats.context_manager_count, 7);
1279 assert_eq!(stats.total_count, 39);
1280 assert_eq!(programs.len(), stats.total_count);
1281 }
1282
1283 #[test]
1284 fn test_patterns_have_valid_python_syntax() {
1285 let gen = DepylerPatternGenerator::new(4);
1286 let programs = gen.generate();
1287
1288 for prog in &programs {
1290 assert!(
1291 prog.code.contains("def main()") || prog.code.contains("class "),
1292 "Pattern missing main function: {}",
1293 prog.code
1294 );
1295 }
1296 }
1297
1298 #[test]
1299 fn test_file_io_features_are_tagged() {
1300 let gen = FileIOPatternGenerator::new(4);
1301 let programs = gen.generate();
1302
1303 for prog in &programs {
1305 assert!(
1306 !prog.features.is_empty(),
1307 "Pattern missing features: {}",
1308 prog.code
1309 );
1310 }
1311 }
1312
1313 #[test]
1314 fn test_depth_constraint_respected() {
1315 let gen1 = FileIOPatternGenerator::new(1);
1317 let programs1 = gen1.generate();
1318 assert!(programs1.iter().all(|p| p.ast_depth <= 1));
1319
1320 let gen4 = FileIOPatternGenerator::new(4);
1322 let programs4 = gen4.generate();
1323 assert!(programs4.iter().any(|p| p.ast_depth == 4));
1324 }
1325
1326 #[test]
1329 fn test_advanced_generator_option_path() {
1330 let gen = AdvancedDepylerPatternGenerator::new(1);
1331 let programs = gen.generate();
1332 assert_eq!(programs.len(), 4); let features: Vec<_> = programs.iter().flat_map(|p| &p.features).collect();
1335 assert!(features.iter().any(|f| f.contains("option_path")));
1336 }
1337
1338 #[test]
1339 fn test_advanced_generator_trait_objects() {
1340 let gen = AdvancedDepylerPatternGenerator::new(2);
1341 let programs = gen.generate();
1342 assert_eq!(programs.len(), 9); let features: Vec<_> = programs.iter().flat_map(|p| &p.features).collect();
1345 assert!(features.iter().any(|f| f.contains("trait_object")));
1346 }
1347
1348 #[test]
1349 fn test_advanced_generator_json_value() {
1350 let gen = AdvancedDepylerPatternGenerator::new(3);
1351 let programs = gen.generate();
1352 assert_eq!(programs.len(), 13); let features: Vec<_> = programs.iter().flat_map(|p| &p.features).collect();
1355 assert!(features.iter().any(|f| f.contains("value_json")));
1356 }
1357
1358 #[test]
1359 fn test_advanced_generator_full_depth() {
1360 let gen = AdvancedDepylerPatternGenerator::new(4);
1361 let programs = gen.generate();
1362 assert_eq!(programs.len(), 17); let features: Vec<_> = programs.iter().flat_map(|p| &p.features).collect();
1365 assert!(features.iter().any(|f| f.contains("enter_")));
1366 }
1367
1368 #[test]
1369 fn test_advanced_patterns_target_depyler_issues() {
1370 let gen = AdvancedDepylerPatternGenerator::new(4);
1371 let programs = gen.generate();
1372
1373 let features: Vec<_> = programs.iter().flat_map(|p| &p.features).cloned().collect();
1375
1376 assert!(features.iter().any(|f| f.contains("option_path")));
1378 assert!(features.iter().any(|f| f.contains("trait_object")));
1380 assert!(features.iter().any(|f| f.contains("value_json")));
1382 assert!(features.iter().any(|f| f.contains("enter_")));
1384 }
1385
1386 #[test]
1387 fn test_advanced_patterns_have_main() {
1388 let gen = AdvancedDepylerPatternGenerator::new(4);
1389 let programs = gen.generate();
1390
1391 for prog in &programs {
1392 assert!(
1393 prog.code.contains("def main()") || prog.code.contains("class "),
1394 "Pattern missing main function or class: {}",
1395 prog.features.first().unwrap_or(&"unknown".to_string())
1396 );
1397 }
1398 }
1399}