Skip to content

Commit

Permalink
Add expandvars and respective tests. Added lit to pixi.toml, and `m…
Browse files Browse the repository at this point in the history
…agic run` to pre-commit configuration.

squash code a bit by using write

add tests

Cleanup with formatting and sign

add missing newline

Signed-off-by: Mikhail Tavarez <[email protected]>

updated changelog

updated changelog

Add unsetenv and use a context manager to unset test variables.

Add renamed test_env.mojo

Fix unsetenv result in EnvVar context manager.

Signed-off-by: Mikhail Tavarez <[email protected]>
  • Loading branch information
thatstoasty committed Nov 4, 2024
1 parent 388eaa4 commit 884cb52
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 32 deletions.
2 changes: 1 addition & 1 deletion stdlib/src/os/__init__.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"""Implements the os package."""

from .atomic import Atomic
from .env import getenv, setenv
from .env import getenv, setenv, unsetenv
from .fstat import lstat, stat, stat_result
from .os import (
SEEK_CUR,
Expand Down
20 changes: 20 additions & 0 deletions stdlib/src/os/env.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,26 @@ fn setenv(name: String, value: String, overwrite: Bool = True) -> Bool:
return status == 0


fn unsetenv(name: String) -> Bool:
"""Unsets an environment variable.
Constraints:
The function only works on macOS or Linux and returns False otherwise.
Args:
name: The name of the environment variable.
Returns:
True if unsetting the variable succeeded. Otherwise, False is returned.
"""
alias os_is_supported = os_is_linux() or os_is_macos()
if not os_is_supported:
return False

var status = external_call["unsetenv", Int32](name.unsafe_ptr())
return status == 0


fn getenv(name: String, default: String = "") -> String:
"""Returns the value of the given environment variable.
Expand Down
10 changes: 4 additions & 6 deletions stdlib/src/os/path/path.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -426,9 +426,7 @@ fn _is_shell_special_variable(byte: Byte) -> Bool:
ord("8"),
ord("9"),
)
if int(byte) in shell_variables:
return True
return False
return int(byte) in shell_variables


fn _is_alphanumeric(byte: Byte) -> Bool:
Expand Down Expand Up @@ -492,16 +490,16 @@ fn _parse_variable_name(bytes: Span[Byte]) -> Tuple[String, Int]:

fn expandvars[PathLike: os.PathLike, //](path: PathLike) -> String:
"""Replaces `${var}` or `$var` in the path with values from the current environment variables.
Undefined variables should be left alone.
Malformed variable names and references to non-existing variables are left unchanged.
Parameters:
PathLike: The type conforming to the os.PathLike trait.
Args:
path: The path to expand.
path: The path that is being expanded.
Returns:
The input path with environment variables expanded.
The expanded path.
"""
var path_str = path.__fspath__()
var bytes = path_str.as_bytes()
Expand Down
65 changes: 41 additions & 24 deletions stdlib/test/os/path/test_expandvars.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,53 @@ from os.path import expandvars
from testing import assert_equal


@value
struct EnvVar:
var name: String

fn __init__(inout self, name: String, value: String) -> None:
self.name = name
_ = os.setenv(name, value)

fn __enter__(self) -> Self:
return self

fn __exit__(self) -> None:
_ = os.unsetenv(self.name)


def test_expansion():
_ = os.setenv("TEST_VAR", "World")
assert_equal(expandvars("Hello $TEST_VAR!"), "Hello World!")
assert_equal(expandvars("漢字 $TEST_VAR🔥!"), "漢字 World🔥!")
assert_equal(expandvars("$TEST_VAR/path/to/file"), "World/path/to/file")

_ = os.setenv("UNICODE_TEST_VAR", "漢字🔥")
assert_equal(expandvars("Hello $UNICODE_TEST_VAR!"), "Hello 漢字🔥!")
assert_equal(expandvars("漢字 $UNICODE_TEST_VAR🔥!"), "漢字 漢字🔥🔥!")
assert_equal(
expandvars("$UNICODE_TEST_VAR/path/to/file"), "漢字🔥/path/to/file"
)
with EnvVar("TEST_VAR", "World"):
assert_equal(expandvars("Hello $TEST_VAR!"), "Hello World!")
assert_equal(expandvars("漢字 $TEST_VAR🔥!"), "漢字 World🔥!")
assert_equal(expandvars("$TEST_VAR/path/to/file"), "World/path/to/file")

with EnvVar("UNICODE_TEST_VAR", "漢字🔥"):
assert_equal(expandvars("Hello $UNICODE_TEST_VAR!"), "Hello 漢字🔥!")
assert_equal(expandvars("漢字 $UNICODE_TEST_VAR🔥!"), "漢字 漢字🔥🔥!")
assert_equal(
expandvars("$UNICODE_TEST_VAR/path/to/file"), "漢字🔥/path/to/file"
)


def test_braced_expansion():
_ = os.setenv("BRACE_VAR", "World")
assert_equal(expandvars("Hello ${BRACE_VAR}!"), "Hello World!")
assert_equal(expandvars("漢字 ${BRACE_VAR}🔥!"), "漢字 World🔥!")
assert_equal(expandvars("${BRACE_VAR}/path/to/file"), "World/path/to/file")

_ = os.setenv("UNICODE_BRACE_VAR", "漢字🔥")
assert_equal(expandvars("Hello ${UNICODE_BRACE_VAR}!"), "Hello 漢字🔥!")
assert_equal(expandvars("漢字 ${UNICODE_BRACE_VAR}🔥!"), "漢字 漢字🔥🔥!")
assert_equal(
expandvars("${UNICODE_BRACE_VAR}/path/to/file"), "漢字🔥/path/to/file"
)
with EnvVar("BRACE_VAR", "World"):
assert_equal(expandvars("Hello ${BRACE_VAR}!"), "Hello World!")
assert_equal(expandvars("漢字 ${BRACE_VAR}🔥!"), "漢字 World🔥!")
assert_equal(
expandvars("${BRACE_VAR}/path/to/file"), "World/path/to/file"
)

with EnvVar("UNICODE_BRACE_VAR", "漢字🔥"):
assert_equal(expandvars("Hello ${UNICODE_BRACE_VAR}!"), "Hello 漢字🔥!")
assert_equal(expandvars("漢字 ${UNICODE_BRACE_VAR}🔥!"), "漢字 漢字🔥🔥!")
assert_equal(
expandvars("${UNICODE_BRACE_VAR}/path/to/file"), "漢字🔥/path/to/file"
)


def test_unset_expansion():
# Unset variables should be expanded to an empty string.
# Unset variables should not be expanded.
assert_equal(
expandvars("Hello $NONEXISTENT_VAR!"), "Hello $NONEXISTENT_VAR!"
)
Expand All @@ -56,7 +73,7 @@ def test_unset_expansion():


def test_dollar_sign():
# A lone dollar sign should not be expanded.
# A lone `$` should not be expanded.
assert_equal(expandvars("A lone $ sign"), "A lone $ sign")

# Special shell variables should not be expanded.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# REQUIRES: system-linux || system-darwin
# RUN: TEST_MYVAR=MyValue %mojo %s

from os import getenv, setenv
from os import getenv, setenv, unsetenv

from testing import assert_equal

Expand All @@ -40,6 +40,14 @@ def test_setenv():
assert_equal(setenv("=", "INVALID", True), False)


def test_unsetenv():
assert_equal(setenv("NEW_VAR", "FOO", True), True)
assert_equal(getenv("NEW_VAR"), "FOO")
assert_equal(unsetenv("NEW_VAR"), True)
assert_equal(getenv("NEW_VAR"), "")


def main():
test_getenv()
test_setenv()
test_unsetenv()

0 comments on commit 884cb52

Please sign in to comment.