Skip to content

Commit

Permalink
[External] [stdlib] Implement os.path.basename (#51331)
Browse files Browse the repository at this point in the history
[External] [stdlib] Implement `os.path.basename`

Implement `os.path.basename`.

Fixes [#2941](#2941).

Co-authored-by: bgreni <[email protected]>
Closes #2974
MODULAR_ORIG_COMMIT_REV_ID: e5ba09e0fc57c7bbcaca873c3dadcd1ec80db729
  • Loading branch information
bgreni authored and modularbot committed Nov 23, 2024
1 parent ced5633 commit 5ff00c7
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 0 deletions.
1 change: 1 addition & 0 deletions stdlib/src/os/path/__init__.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from .path import (
dirname,
basename,
exists,
expanduser,
expandvars,
Expand Down
25 changes: 25 additions & 0 deletions stdlib/src/os/path/path.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,31 @@ def split[PathLike: os.PathLike, //](path: PathLike) -> (String, String):
return head, tail


fn basename[PathLike: os.PathLike, //](path: PathLike) -> String:
"""Returns the tail section of a path.
```mojo
basename("a/path/foo.txt") # returns "foo.txt"
```
Parameters:
PathLike: The type conforming to the os.PathLike trait.
Args:
path: The path to retrieve the basename from.
Returns:
The basename from the path.
"""
var fspath = path.__fspath__()
alias sep = str(os.sep)
var i = fspath.rfind(sep) + 1
var head = fspath[i:]
if head and head != sep * len(head):
return head.rstrip(sep)
return head


# TODO uncomment this when unpacking is supported
# fn join[PathLike: os.PathLike](path: PathLike, *paths: PathLike) -> String:
# """Join two or more pathname components, inserting '/' as needed.
Expand Down
84 changes: 84 additions & 0 deletions stdlib/test/os/path/test_basename.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# ===----------------------------------------------------------------------=== #
# Copyright (c) 2024, Modular Inc. All rights reserved.
#
# Licensed under the Apache License v2.0 with LLVM Exceptions:
# https://llvm.org/LICENSE.txt
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ===----------------------------------------------------------------------=== #
# RUN: %mojo %s

from os.path import basename
from pathlib import Path
from builtin._location import __source_location
from testing import assert_equal


def main():
# Root directories
assert_equal("", basename("/"))

# Empty strings
assert_equal("", basename(""))

# Current directory (matching behavior of python, doesn't resolve `..` etc.)
assert_equal(".", basename("."))

# Parent directory
assert_equal("..", basename(".."))

# Absolute paths
assert_equal("file", basename("/file"))
assert_equal("file.txt", basename("/file.txt"))
assert_equal("file", basename("/dir/file"))
assert_equal("file", basename("/dir/subdir/file"))

# Relative paths
assert_equal("file", basename("dir/file"))
assert_equal("file", basename("dir/subdir/file"))
assert_equal("file", basename("file"))

# Trailing slashes
assert_equal("", basename("/path/to/"))
assert_equal("", basename("/path/to/dir/"))

# Multiple slashes
assert_equal("file", basename("/path/to//file"))
assert_equal("to", basename("/path//to"))

# Paths with spaces
assert_equal("file", basename("/path to/file"))
assert_equal("file", basename("/path to/dir/file"))

# Paths with special characters
assert_equal("file", basename("/path-to/file"))
assert_equal("file", basename("/path_to/dir/file"))

# Paths with dots
assert_equal("file", basename("/path/./to/file"))
assert_equal("file", basename("/path/../to/file"))

# Paths with double dots
assert_equal("file", basename("/path/../file"))
assert_equal("file", basename("/path/to/../file"))

# Root and relative mixed
assert_equal("file", basename("/dir/./file"))
assert_equal("file", basename("/dir/subdir/../file"))

# Edge cases
assert_equal("file", basename("/./file"))
assert_equal("file", basename("/../file"))

# Unix hidden files
assert_equal(".hiddenfile", basename("/path/to/.hiddenfile"))
assert_equal(".hiddenfile", basename("/path/to/dir/.hiddenfile"))

assert_equal("test_basename.mojo", basename(__source_location().file_name))
assert_equal(
"some_file.txt", basename(Path.home() / "dir" / "some_file.txt")
)

0 comments on commit 5ff00c7

Please sign in to comment.