marianoguerra/pure-py/program does not have a README file

    SourceTree

    pub struct SourceTree {
    base_dir : String
    modules : Map[String,
    Module
    ]
    paths : Map[String, String]
    }

    Finding a program's modules on disk.

    A port of the reference's check_program.py discovery: what a module name means as a path, which files are part of the program, and what each one imports. The result is a value -- a SourceTree -- so that the checker and the evaluator both take one and neither touches the filesystem. A test can build one in memory.

    Three rules that are not obvious:

    • A directory with no __init__.py is a NAMESPACE PACKAGE, and its body is empty. pkg/sub.py alone makes pkg a module.
    • Every .py under the entry's directory is discovered, whether or not anything imports it, and so is every proper prefix of its name. An unused module is therefore parsed and sieved, though not checked.
    • A module that fails to parse, or that the sieve rejects, is a PROGRAM-level error carrying the file's path -- not a module-level one.

    SourceTree::from_entry

    fn SourceTree::from_entry(entry_path : String, predefined~ : Array[String], sweep? : Bool) -> SourceTree raise

    Discover a whole program from its entry file.

    sweep decides whether every .py under the entry's directory is part of the program, or only what the entry imports, transitively. Checking sweeps: the reference discovers an unused module and reports it if it will not parse. Running does not: the semantics only ever loads a module something imports, and a directory full of unrelated files -- which is exactly what the conformance suite's module-level tests are -- must not be dragged in.

    SourceTree::get

    SourceTree::module_names

    fn SourceTree::module_names(self : SourceTree) -> Array[String]

    SourceTree::modules_map

    SourceTree::of

    fn SourceTree::of(modules : Map[String,
    Module
    ], base_dir? : String) -> SourceTree

    Build a source tree in memory, for a test or a library caller.

    SourceTree::path_of

    fn SourceTree::path_of(self : SourceTree, q : String) -> String

    is_module

    fn is_module(name : String, base_dir : String) -> String?

    Where a module name lives, if it lives anywhere: a/b.py, then a/b/__init__.py, then the directory a/b as a namespace package.

    join

    fn join(base : String, child : String) -> String

    pathlib's /: a lone . on the left disappears.

    name_of

    fn name_of(p : String) -> String

    The file name, without its directories.

    parent

    fn parent(p : String) -> String

    Just enough of Python's pathlib to print the same paths the reference prints.

    The messages of check_program.py contain paths built with pathlib, and pathlib normalises in ways a naive join does not: the parent of main.py is ., and joining . with helper.py gives helper.py and not ./helper.py. Those two show up verbatim in module 'helper' not foundunder . and in helper.py: duplicate name 'f' in mutual region.

    proper_prefixes

    fn proper_prefixes(q : String) -> Array[String]

    a.b.c has proper prefixes a and a.b.

    stem

    fn stem(p : String) -> String

    The file name without its last extension.

    with_proper_prefixes

    fn with_proper_prefixes(names : Array[String]) -> Array[String]

    Every name and all of its proper prefixes, sorted and without repeats.

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io