tmc_langs_python3/
policy.rs

1//! Contains the Python3 student file policy
2
3use std::{ffi::OsStr, path::Path};
4use tmc_langs_framework::{StudentFilePolicy, TmcProjectYml};
5
6pub struct Python3StudentFilePolicy {
7    project_config: TmcProjectYml,
8}
9
10impl StudentFilePolicy for Python3StudentFilePolicy {
11    fn new_with_project_config(project_config: TmcProjectYml) -> Self
12    where
13        Self: Sized,
14    {
15        Self { project_config }
16    }
17
18    fn get_project_config(&self) -> &TmcProjectYml {
19        &self.project_config
20    }
21
22    fn is_non_extra_student_file(&self, path: &Path) -> bool {
23        // include all .py and .ipynb files,
24        // since python project structure is more freeform than most languages
25        // so there may not be a src dir etc.
26        // but exclude venv, test and tmc dirs
27
28        let in_venv = path.starts_with("venv") || path.starts_with(".venv");
29        let in_test = path.starts_with("test");
30        let in_tmc = path.starts_with("tmc");
31        let excluded = in_venv || in_test || in_tmc;
32
33        let is_py = path.extension() == Some(OsStr::new("py"));
34        let is_ipynb = path.extension() == Some(OsStr::new("ipynb"));
35        !excluded && (is_py || is_ipynb)
36    }
37}
38
39#[cfg(test)]
40mod test {
41    use super::*;
42
43    #[test]
44    fn in_src_is_source_file() {
45        let policy = Python3StudentFilePolicy::new(Path::new(".")).unwrap();
46        assert!(policy.is_student_file(Path::new("src/some_file.py")));
47        assert!(policy.is_student_file(Path::new("src/some_dir/some_file.py")));
48    }
49
50    #[test]
51    fn in_root_is_source_file() {
52        let policy = Python3StudentFilePolicy::new(Path::new(".")).unwrap();
53        assert!(policy.is_student_file(Path::new("some_file.py")));
54    }
55
56    #[test]
57    fn pycache_is_not_source_file() {
58        let policy = Python3StudentFilePolicy::new(Path::new(".")).unwrap();
59        assert!(!policy.is_student_file(Path::new("__pycache__")));
60        assert!(!policy.is_student_file(Path::new("__pycache__/cachefile")));
61        assert!(!policy.is_student_file(Path::new("src/__pycache__")));
62    }
63
64    #[test]
65    fn pyc_is_not_source_file() {
66        let policy = Python3StudentFilePolicy::new(Path::new(".")).unwrap();
67        assert!(!policy.is_student_file(Path::new("some.pyc")));
68        assert!(!policy.is_student_file(Path::new("src/other.pyc")));
69    }
70
71    #[test]
72    fn subdirs_are_not_student_files() {
73        let policy = Python3StudentFilePolicy::new(Path::new(".")).unwrap();
74        assert!(!policy.is_student_file(Path::new("subdir/something")));
75        assert!(!policy.is_student_file(Path::new("another/mid/else")));
76    }
77
78    #[test]
79    fn tmc_and_test_are_not_student_files() {
80        let policy = Python3StudentFilePolicy::new(Path::new(".")).unwrap();
81        assert!(!policy.is_student_file(Path::new("test/something.py")));
82        assert!(!policy.is_student_file(Path::new("tmc/mid/else.py")));
83    }
84
85    #[test]
86    fn non_py_file_in_root_is_not_student_file() {
87        let policy = Python3StudentFilePolicy::new(Path::new(".")).unwrap();
88        assert!(!policy.is_student_file(Path::new("test")));
89        assert!(!policy.is_student_file(Path::new("root_file")));
90    }
91
92    #[test]
93    fn venv_dir_is_not_student_file() {
94        let policy = Python3StudentFilePolicy::new(Path::new(".")).unwrap();
95        assert!(!policy.is_student_file(Path::new("venv/asd.py")));
96        assert!(!policy.is_student_file(Path::new(".venv/asd.py")));
97    }
98}