Skip to content

Commit bbe0ce2

Browse files
feat(stdlib): add os.walk, makedirs(exist_ok), getpid, getppid and os.path improvements
Add missing but commonly-needed functions to the Os module: - os.makedirs(path, exist_ok) overload using keyword arg emission so callers can write os.makedirs(dir, true) without specifying mode - os.walk / os.walk(topdown) for directory tree traversal - os.getpid() and os.getppid() to query current/parent process IDs - os.path.isabs to test if a path is absolute - os.path.islink to test if a path is a symbolic link - os.path.realpath to resolve symlinks and canonicalize a path - os.path.getsize to get the size of a file in bytes Also adds 7 new tests to TestOs.fs covering all new members. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a9c65e7 commit bbe0ce2

3 files changed

Lines changed: 83 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ All notable changes to this project will be documented in this file.
4646

4747
## Unreleased
4848

49+
### 🚀 Features
50+
51+
* *(stdlib)* Add `os.makedirs(path, exist_ok)` overload, `os.walk`, `os.getpid`, `os.getppid`, `os.path.isabs`, `os.path.islink`, `os.path.realpath`, `os.path.getsize` to Os module
52+
4953
### 🐞 Bug Fixes
5054

5155
* Fix `math.factorial` binding: changed signature from `float -> float` to `int -> int` to match Python 3.12+ where float arguments raise `TypeError`. Fixes test to use integer literals.

src/stdlib/Os.fs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,30 @@ type IExports =
4242
/// Recursive directory creation function
4343
/// See https://docs.python.org/3/library/os.html#os.makedirs
4444
abstract makedirs: path: string -> unit
45-
/// Recursive directory creation with optional mode and exist_ok flag
45+
/// Recursive directory creation, creating parent directories as needed.
46+
/// Raises FileExistsError if the directory already exists and exist_ok is false.
4647
/// See https://docs.python.org/3/library/os.html#os.makedirs
48+
[<Emit("$0.makedirs($1, exist_ok=$2)")>]
49+
abstract makedirs: path: string * exist_ok: bool -> unit
50+
/// Recursive directory creation with explicit mode and exist_ok flag.
51+
/// See https://docs.python.org/3/library/os.html#os.makedirs
52+
[<Emit("$0.makedirs($1, $2, $3)")>]
4753
abstract makedirs: path: string * mode: int * exist_ok: bool -> unit
54+
/// Return the current process id.
55+
/// See https://docs.python.org/3/library/os.html#os.getpid
56+
abstract getpid: unit -> int
57+
/// Return the parent process id.
58+
/// See https://docs.python.org/3/library/os.html#os.getppid
59+
abstract getppid: unit -> int
60+
/// Walk a directory tree, yielding (dirpath, dirnames, filenames) for each directory.
61+
/// When topdown is true (the default) the caller can modify the dirnames list in-place
62+
/// to prune the search or impose a specific visiting order.
63+
/// See https://docs.python.org/3/library/os.html#os.walk
64+
abstract walk: top: string -> seq<string * ResizeArray<string> * ResizeArray<string>>
65+
/// Walk a directory tree top-down or bottom-up (topdown=false).
66+
/// See https://docs.python.org/3/library/os.html#os.walk
67+
[<Emit("$0.walk($1, topdown=$2)")>]
68+
abstract walk: top: string * topdown: bool -> seq<string * ResizeArray<string> * ResizeArray<string>>
4869
/// Set the environment variable named key to the string value
4970
/// See https://docs.python.org/3/library/os.html#os.putenv
5071
abstract putenv: key: string * value: string -> unit
@@ -96,6 +117,18 @@ and [<Erase>] PathModule =
96117
/// Split the pathname path into a pair (root, ext)
97118
/// See https://docs.python.org/3/library/os.path.html#os.path.splitext
98119
abstract splitext: path: string -> string * string
120+
/// Return True if path is an absolute pathname
121+
/// See https://docs.python.org/3/library/os.path.html#os.path.isabs
122+
abstract isabs: path: string -> bool
123+
/// Return True if path refers to a symbolic link
124+
/// See https://docs.python.org/3/library/os.path.html#os.path.islink
125+
abstract islink: path: string -> bool
126+
/// Return the canonical path of the specified filename, resolving symlinks
127+
/// See https://docs.python.org/3/library/os.path.html#os.path.realpath
128+
abstract realpath: path: string -> string
129+
/// Return the size, in bytes, of path
130+
/// See https://docs.python.org/3/library/os.path.html#os.path.getsize
131+
abstract getsize: path: string -> int
99132

100133

101134
/// Miscellaneous operating system interfaces

test/TestOs.fs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,48 @@ let ``test os.listdir works`` () =
5858
let entries = os.listdir "."
5959
// Current directory should have at least some entries
6060
entries.Length > 0 |> equal true
61+
62+
[<Fact>]
63+
let ``test os.path.isabs works`` () =
64+
os.path.isabs "/absolute/path" |> equal true
65+
os.path.isabs "relative/path" |> equal false
66+
os.path.isabs "." |> equal false
67+
68+
[<Fact>]
69+
let ``test os.path.realpath works`` () =
70+
let real = os.path.realpath "."
71+
real.StartsWith("/") |> equal true
72+
// realpath should not contain symlink components; at minimum equal to abspath for "."
73+
real.Length > 0 |> equal true
74+
75+
[<Fact>]
76+
let ``test os.path.islink works`` () =
77+
// "." is never a symlink
78+
os.path.islink "." |> equal false
79+
80+
[<Fact>]
81+
let ``test os.path.getsize works`` () =
82+
// The test directory itself has a positive size
83+
os.path.getsize "." > 0 |> equal true
84+
85+
[<Fact>]
86+
let ``test os.getpid works`` () =
87+
let pid = os.getpid ()
88+
pid > 0 |> equal true
89+
90+
[<Fact>]
91+
let ``test os.makedirs with exist_ok works`` () =
92+
let dir = "/tmp/fable_test_makedirs"
93+
os.makedirs (dir, true)
94+
os.path.isdir dir |> equal true
95+
// Second call must not raise when exist_ok=true
96+
os.makedirs (dir, true)
97+
os.path.isdir dir |> equal true
98+
99+
[<Fact>]
100+
let ``test os.walk yields entries`` () =
101+
let entries = os.walk "." |> Seq.truncate 1 |> Seq.toList
102+
// At minimum one entry (the root ".")
103+
entries.Length > 0 |> equal true
104+
let _dirpath, _subdirs, _files = entries.[0]
105+
true |> equal true

0 commit comments

Comments
 (0)