Skip to content

Commit

Permalink
clean up for 24.6
Browse files Browse the repository at this point in the history
  • Loading branch information
thatstoasty committed Dec 13, 2024
1 parent 8b00952 commit 763b95b
Show file tree
Hide file tree
Showing 14 changed files with 4,638 additions and 2,012 deletions.
16 changes: 8 additions & 8 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
name: Build all packages

on:
push:
branches:
- nightly
paths:
- src/**

# on: ["push"]
# on:
# push:
# branches:
# - nightly
# paths:
# - src/**

on: ["push"]

jobs:
build:
Expand Down
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ repos:
language: system
files: '\.(mojo|🔥)$'
stages: [commit]
- id: check-docstrings
name: check-docstrings
entry: python3 ./scripts/check-docstrings.py
language: system
pass_filenames: false
stages: [commit]
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased] - yyyy-mm-dd

## [0.1.4] - 2024-10-05

- Refactor

## [0.1.3] - 2024-09-13

- First release with a changelog! Added rattler build and conda publish.
5,849 changes: 3,941 additions & 1,908 deletions magic.lock

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions mojoproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ channels = ["conda-forge", "https://conda.modular.com/max"]
description = "Datetime library."
name = "small_time"
platforms = ["osx-arm64", "linux-64"]
version = "1.24.6.0.dev2024092705"
version = "0.1.5.nightly1"
license = "MIT"
license-file = "LICENSE"
homepage = "https://github.com/thatstoasty/small-time"
Expand All @@ -21,13 +21,13 @@ publish = { cmd = "python scripts/util.py publish", env = { PREFIX_API_KEY = "$P
bp = { depends_on=["build", "publish"] }

[dependencies]
max = ">=24.5.0,<25"
max = ">=24.5.0"

[feature.nightly]
channels = ["conda-forge", "https://conda.modular.com/max-nightly"]

[feature.nightly.dependencies]
max = ">=24.6.0.dev2024092705"
max = "*"

[environments]
nightly = ["nightly"]
nightly = {features = ["nightly"]}
27 changes: 27 additions & 0 deletions scripts/check-docstrings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import subprocess
import sys

# TODO: Use the "mojo doc" directly when there is an option to
# fail if warnings are present (something like -Werror for gcc).


def main():
# This is actually faster than running "mojo doc" on each file since
# "mojo doc" only accept a single file/path as argument
command = [
"mojo",
"doc",
"--diagnose-missing-doc-strings",
"-o",
"/dev/null",
"./src/small-time",
]
result = subprocess.run(command, capture_output=True)
if result.stderr or result.returncode != 0:
print("Docstring issue found: ")
print(result.stderr.decode())
sys.exit(1)


if __name__ == "__main__":
main()
78 changes: 66 additions & 12 deletions scripts/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def build_dependency_list(dependencies: dict[str, str]) -> list[str]:
operator = version[:2]
start = 2

deps.append(f"- {name} {operator} {version[start:]}")
deps.append(f" - {name} {operator} {version[start:]}")

return deps

Expand Down Expand Up @@ -55,6 +55,9 @@ def generate_recipe(args: Any) -> None:
.replace("{{VERSION}}", config["project"]["version"])
)

if args.mode != "default":
recipe = recipe.replace("{{ENVIRONMENT_FLAG}}", f"-e {args.mode}")

# Dependencies are the only notable field that changes between environments.
dependencies: dict[str, str]
match args.mode:
Expand Down Expand Up @@ -82,7 +85,7 @@ def publish_to_prefix(args: Any) -> None:
for file in glob.glob(f'{conda_build_path}/**/*.conda'):
try:
subprocess.run(
["magic", "run", "rattler-build", "upload", "prefix", "-c", args.channel, file],
["rattler-build", "upload", "prefix", "-c", args.channel, file],
check=True,
)
except subprocess.CalledProcessError:
Expand Down Expand Up @@ -116,35 +119,62 @@ def execute_package_tests(args: Any) -> None:
prepare_temp_directory()
shutil.copytree(TEST_DIR, TEMP_DIR, dirs_exist_ok=True)

print("Running tests...")
subprocess.run(["mojo", "test", TEMP_DIR], check=True)
target = TEMP_DIR
if args.path:
target = f"{target}/{args.path}"
print(f"Running tests at {target}...")
subprocess.run(["mojo", "test", target], check=True)

remove_temp_directory()


def execute_package_examples(args: Any) -> None:
"""Executes the examples for the package."""
EXAMPLE_DIR = "./examples"
EXAMPLE_DIR = "examples"
if not os.path.exists("examples"):
print(f"Path does not exist: {EXAMPLE_DIR}.")
return

print("Building package and copying examples.")
prepare_temp_directory()
shutil.copytree(EXAMPLE_DIR, TEMP_DIR)
shutil.copytree(EXAMPLE_DIR, TEMP_DIR, dirs_exist_ok=True)

example_files = f'{EXAMPLE_DIR}/*.mojo'
if args.path:
example_files = f"{EXAMPLE_DIR}/{args.path}"

print("Running examples...")
subprocess.run(["mojo", "test", TEMP_DIR], check=True)
print(f"Running examples in {example_files}...")
for file in glob.glob(example_files):
file_name = os.path.basename(file)
name, _ = os.path.splitext(file_name)
shutil.copyfile(file, f"{TEMP_DIR}/{file_name}")
subprocess.run(["mojo", "build", f"{TEMP_DIR}/{file_name}", "-o", f"{TEMP_DIR}/{name}"], check=True)
subprocess.run([f"{TEMP_DIR}/{name}"], check=True)

remove_temp_directory()


def execute_package_benchmarks(args: Any) -> None:
BENCHMARK_DIR = "./benchmarks"
if not os.path.exists("benchmarks"):
print(f"Path does not exist: {BENCHMARK_DIR}.")
return

print("Building package and copying benchmarks.")
prepare_temp_directory()
shutil.copytree(BENCHMARK_DIR, TEMP_DIR)
shutil.copytree(BENCHMARK_DIR, TEMP_DIR, dirs_exist_ok=True)

benchmark_files = f'{BENCHMARK_DIR}/*.mojo'
if args.path:
benchmark_files = f"{BENCHMARK_DIR}/{args.path}"

print("Running benchmarks...")
subprocess.run(["mojo", "test", TEMP_DIR], check=True)
print(f"Running benchmarks in {benchmark_files}...")
for file in glob.glob(benchmark_files):
file_name = os.path.basename(file)
name, _ = os.path.splitext(file_name)
shutil.copyfile(file, f"{TEMP_DIR}/{file_name}")
subprocess.run(["mojo", "build", f"{TEMP_DIR}/{file_name}", "-o", f"{TEMP_DIR}/{name}"], check=True)
subprocess.run([f"{TEMP_DIR}/{name}"], check=True)

remove_temp_directory()

Expand All @@ -154,19 +184,22 @@ def build_conda_package(args: Any) -> None:
# Build the conda package for the project.
config = load_project_config()
channels: list[str]
rattler_command: list[str]
match args.mode:
case "default":
channels = config["project"]["channels"]
rattler_command = ["magic", "run", "rattler-build", "build"]
case _:
channels = config["feature"][args.mode]["channels"]
rattler_command = ["magic", "run", "-e", args.mode, "rattler-build", "build"]

options: list[str] = []
for channel in channels:
options.extend(["-c", channel])

generate_recipe(args)
subprocess.run(
["magic", "run", "rattler-build", "build", "-r", RECIPE_DIR, "--skip-existing=all", *options],
[*rattler_command, "-r", RECIPE_DIR, "--skip-existing=all", *options],
check=True,
)
os.remove(f"{RECIPE_DIR}/recipe.yaml")
Expand Down Expand Up @@ -219,14 +252,35 @@ def main():

# create the parser for the "run tests" command
run_tests = run_subcommands.add_parser("tests", help="tests help")
run_tests.add_argument(
"-p",
"--path",
type=str,
default=None,
help="Optional path to test file or test directory to run tests for.",
)
run_tests.set_defaults(func=execute_package_tests)

# create the parser for the "run benchmarks" command
run_benchmarks = run_subcommands.add_parser("benchmarks", help="benchmarks help")
run_benchmarks.add_argument(
"-p",
"--path",
type=str,
default=None,
help="Optional path to benchmark file or test directory to run tests for.",
)
run_benchmarks.set_defaults(func=execute_package_benchmarks)

# create the parser for the "run examples" command
run_examples = run_subcommands.add_parser("examples", help="examples help")
run_examples.add_argument(
"-p",
"--path",
type=str,
default=None,
help="Optional path to example file or test directory to run tests for.",
)
run_examples.set_defaults(func=execute_package_examples)

args = parser.parse_args()
Expand Down
2 changes: 1 addition & 1 deletion src/small_time/__init__.mojo
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .small_time import SmallTime
from .small_time import SmallTime, now
from .time_zone import TimeZone
from .time_delta import TimeDelta
75 changes: 64 additions & 11 deletions src/small_time/c.mojo
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from sys import external_call
from memory import UnsafePointer
from memory import UnsafePointer, Pointer

alias void = UInt8
alias char = UInt8
Expand All @@ -17,18 +17,27 @@ alias double = Float64

@register_passable("trivial")
struct TimeVal:
"""Time value."""
var tv_sec: Int
"""Seconds."""
var tv_usec: Int
"""Microseconds."""

fn __init__(inout self, tv_sec: Int = 0, tv_usec: Int = 0):
fn __init__(out self, tv_sec: Int = 0, tv_usec: Int = 0):
"""Initializes a new time value.
Args:
tv_sec: Seconds.
tv_usec: Microseconds.
"""
self.tv_sec = tv_sec
self.tv_usec = tv_usec


@register_passable("trivial")
struct Tm:
"""C Tm struct."""

var tm_sec: Int32
"""Seconds."""
var tm_min: Int32
Expand All @@ -50,7 +59,8 @@ struct Tm:
var tm_gmtoff: Int64
"""Localtime zone offset seconds."""

fn __init__(inout self):
fn __init__(out self):
"""Initializes a new time struct."""
self.tm_sec = 0
self.tm_min = 0
self.tm_hour = 0
Expand All @@ -64,35 +74,78 @@ struct Tm:


fn gettimeofday() -> TimeVal:
"""Gets the current time. It's a wrapper around libc `gettimeofday`.
Returns:
Current time.
"""
var tv = TimeVal()
_ = external_call["gettimeofday", NoneType](Reference(tv), 0)
_ = external_call["gettimeofday", NoneType](Pointer.address_of(tv), 0)
return tv


fn time() -> Int:
"""Returns the current time in seconds since the Epoch.
Returns:
Current time in seconds.
"""
var time = 0
return external_call["time", Int](Reference(time))
return external_call["time", Int](Pointer.address_of(time))


fn localtime(owned tv_sec: Int) -> Tm:
"""Converts a time value to a broken-down local time.
Args:
tv_sec: Time value in seconds since the Epoch.
Returns:
Broken down local time.
"""
var buf = Tm()
_ = external_call["localtime_r", UnsafePointer[Tm]](Reference(tv_sec), Reference(buf))
_ = external_call["localtime_r", UnsafePointer[Tm]](Pointer.address_of(tv_sec), Pointer.address_of(buf))
return buf


fn strptime(time_str: String, time_format: String) -> Tm:
"""Parses a time string according to a format string.
Args:
time_str: Time string.
time_format: Time format string.
Returns:
Broken down time.
"""
var tm = Tm()
_ = external_call["strptime", NoneType](time_str.unsafe_ptr(), time_format.unsafe_ptr(), Reference(tm))
_ = external_call["strptime", NoneType](time_str.unsafe_ptr(), time_format.unsafe_ptr(), Pointer.address_of(tm))
return tm


fn strftime(format: String, owned time: Tm) -> String:
var buf = String(List[UInt8](capacity=26))
_ = external_call["strftime", UInt](buf.unsafe_ptr(), len(format), format.unsafe_ptr(), Reference(time))
"""Formats a time value according to a format string.
Args:
format: Format string.
time: Time value.
Returns:
Formatted time string.
"""
var buf = String(capacity=26)
_ = external_call["strftime", UInt](buf.unsafe_ptr(), len(format), Pointer.address_of(format), Pointer.address_of(time))
return buf


fn gmtime(owned tv_sec: Int) -> Tm:
"""Converts a time value to a broken-down UTC time."""
var tm = external_call["gmtime", UnsafePointer[Tm]](Reference(tv_sec)).take_pointee()
"""Converts a time value to a broken-down UTC time.
Args:
tv_sec: Time value in seconds since the Epoch.
Returns:
Broken down UTC time.
"""
var tm = external_call["gmtime", UnsafePointer[Tm]](Pointer.address_of(tv_sec)).take_pointee()
return tm
Loading

0 comments on commit 763b95b

Please sign in to comment.