diff --git a/CHANGELOG.md b/CHANGELOG.md index 74d5e81..d9d3cd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Changed -- Bumped MAX / Mojo toolchain dependency to `max ">=26.1.0,<27"` and updated recipes to pin `mojo_version = "=0.26.1"`. -- Updated lexer, parser, writer, and tests to use `codepoint_slices()` and explicit `List[String]` buffers instead of direct `String` indexing or iteration, matching Mojo 0.26.1 string and `__getitem__` semantics. -- Adopted a "no warnings" policy for the core library and tests so future migrations surface only new issues. -- Bumped project and packaging version metadata to `0.9.1` to mark progression towards the Mojo 1.0 beta migration milestone. +- Aligned project dependency pinning to Mojo `1.0.0` in `pixi.toml`. +- Updated packaging recipe compiler pins to `mojo-compiler =1.0.0` and aligned recipe metadata/license consistency. +- Updated migration planning/docs framing from “1.0 beta migration” to a stable Mojo 1.0 migration wave. +- Reworked `TomlValue` recursive storage for Mojo 1.0 compatibility by replacing direct `List[TomlValue]`/`Dict[String, TomlValue]` fields with boxed recursive values and explicit deep-copy/deinit handling. +- Updated parser APIs for Mojo 1.0 stdlib changes (`std.math` import path and `String.byte_length()` for numeric prefix checks). ### Planned for v0.6.0 - Remaining TOML 1.1 - Multiline inline tables with trailing commas diff --git a/README.md b/README.md index c723df3..e39c401 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ `mojo-toml` enables native TOML parsing in Mojo without Python dependencies. Parse configuration files, project settings, and structured data with a clean, type-safe API. **Key features:** + - ✅ **TOML 1.0 compliant** - full specification support - ✅ **Array of tables** - `[[section]]` syntax for repeated table arrays - ✅ **Alternative number bases** - hex (`0xDEAD`), octal (`0o755`), binary (`0b1101`) @@ -200,10 +201,12 @@ pixi add mojo-toml ### 🔮 TOML 1.1 (Partial Support) TOML 1.1 features implemented: + - ✅ `\\xHH` escape sequences for codepoints 0-255 (e.g., `\\x00`, `\\x61`) - ✅ `\\e` escape for escape character (U+001B) TOML 1.1 features not yet implemented: + - Multiline inline tables with trailing commas - Optional seconds in datetime/time values @@ -264,6 +267,7 @@ pixi run benchmark-python ``` Both benchmarks generate markdown reports in `benchmarks/reports/` with: + - System specifications (OS, CPU, GPU, RAM, Mojo/Python versions) - Performance tables with throughput and latency - Timestamp and machine configuration @@ -292,15 +296,18 @@ See [ROADMAP.md](docs/planning/ROADMAP.md) for areas where contributions would b ## Related Projects **Other Mojo Config Libraries:** + - **[mojo-ini](https://github.com/databooth/mojo-ini)** - INI file parser with Python configparser compatibility - **[mojo-dotenv](https://github.com/databooth/mojo-dotenv)** - Load environment variables from .env files **Other TOML Parsers in Mojo:** + - **[decimojo/tomlmojo](https://github.com/forfudan/decimojo/tree/main/src/tomlmojo)** - Lightweight TOML parser (~900 LOC, parser-only) embedded in the decimojo library. Good choice if you only need basic config reading for tests and don't need a standalone package or TOML 1.0 features. ## Acknowledgements Special thanks to: + - **[DataBooth](https://www.databooth.com.au/posts/mojo)** - Project sponsor, building high-performance data and AI services with Mojo - **[Python tomli](https://github.com/hukkin/tomli)** - Reference implementation for validation - **[TOML Specification](https://toml.io/en/v1.0.0)** - Tom Preston-Werner's excellent config format diff --git a/RECIPE_SETUP.md b/RECIPE_SETUP.md index 29587fa..e7d494f 100644 --- a/RECIPE_SETUP.md +++ b/RECIPE_SETUP.md @@ -59,7 +59,7 @@ The GitHub Actions workflow runs automatically when `packaging/recipe.yaml` chan ## 📋 Integration Options -### Option 1: Pre-commit Hook (Recommended) +### Option 1: Prek Hook (Recommended) Add to `.pre-commit-config.yaml`: @@ -74,7 +74,7 @@ Add to `.pre-commit-config.yaml`: pass_filenames: false ``` -Then: `pre-commit install` +Then: `prek install -f` ### Option 2: Just Recipe @@ -125,6 +125,6 @@ See `docs/RECIPE_VALIDATION.md` for: ## 🔗 Next Steps 1. Test validation: `./scripts/validate-recipe.sh packaging/recipe.yaml` -2. Add to pre-commit: Edit `.pre-commit-config.yaml` +2. Add to prek: Edit `.pre-commit-config.yaml` 3. Replicate to other packages: Copy files as shown above 4. Read full guide: `docs/RECIPE_VALIDATION.md` diff --git a/docs/JUST_SETUP.md b/docs/JUST_SETUP.md new file mode 100644 index 0000000..a30a163 --- /dev/null +++ b/docs/JUST_SETUP.md @@ -0,0 +1,31 @@ +# Just setup +This repository uses `just` to expose self-documented workflows. + +## What is Just? +Just is a command runner similar to `make`, with a simpler syntax. + +Official site: +- https://just.systems + +Installation instructions: +- https://just.systems/man/en/chapter_4.html + +Install options: +- macOS (Homebrew): `brew install just` +- Linux (Cargo): `cargo install just` +- Windows (Chocolatey): `choco install just` +- Windows (Scoop): `scoop install just` + +## Quick start +From the repository root: + +```shell +just --list +``` + +## Key recipes +- `just pixi-tasks` +- `just test` +- `just build` +- `just examples` +- `just run ` diff --git a/docs/MOJO_1_0_MIGRATION_BLOG.md b/docs/MOJO_1_0_MIGRATION_BLOG.md deleted file mode 100644 index 2f01f7c..0000000 --- a/docs/MOJO_1_0_MIGRATION_BLOG.md +++ /dev/null @@ -1,161 +0,0 @@ -+++ -title = "Mojo 1.0 beta migration wave: what changed, what worked, and what’s next" -date = "2026-05-30" -draft = false -[taxonomies] -tags = [ - "Mojo 🔥", - "Mojo 1.0 Beta", - "Library Migration", - "Release Engineering", - "Open Source", - "Packaging", - "Testing", - "Refactoring" -] -[extra] -comment = true -+++ -# Mojo 1.0 beta migration wave: what changed, what worked, and what’s next -## Exec summary -Over this migration wave, I moved my `mojo-*` libraries onto one consistent Mojo 1.0 beta baseline. - -The goal was practical: reduce release friction, keep each package usable, and stop the “works in repo A, breaks in repo B” cycle. - -The result is a cleaner operational path, better cross-repo consistency, and a clear public release set on the `0.9.1` beta line. - -This post keeps the main story concise. Full technical notes are in the appendices. - -## Why this migration now -The ecosystem has been moving quickly, and the repos had drifted in small but painful ways: packaging paths, validation assumptions, and compatibility handling. - -None of those issues was huge on its own. Together, they created avoidable drag in day-to-day delivery. - -So the migration focused on three things: -- one release approach across repos, -- one repeatable validation posture, -- and one version line for this beta phase. - -## What was delivered -### 1) Operational consistency -For package-oriented repos, recipe handling and validation flow were aligned so local scripts, CI, and docs all reference the same source of truth. - -### 2) Compatibility uplift -The key Mojo 1.0 beta breakpoints were addressed, including stricter API surfaces and checked-raises related test stabilisation. - -### 3) Release alignment -All migrated repos now sit on a shared `0.9.1` beta line with corresponding tags, so consumers can target a coherent set of builds. - -## Alignment with agentic engineering practice -This migration broadly followed the pattern in Modular’s write-up on building Mojo projects with AI agents: -- human-led architecture and product judgement, -- agent-led execution for repetitive, cross-repo, and boilerplate-heavy work. - -Where I deliberately diverged: distribution policy. Because packaging is still evolving, the practical choice for now is controlled `0.9.1` beta releases with explicit consumer pinning. - -Reference: -- https://www.modular.com/blog/how-i-built-a-pure-mojo-app-and-10-libraries-with-ai-agents - -## Distribution stance for this beta phase -For these migrated DataBooth libraries, the recommendation is to consume the `0.9.1` beta line and avoid fallback to older 26.x-era community artefacts. - -In practice: -- prefer DataBooth-hosted packages for these libraries, -- pin versions explicitly (`==0.9.1` is the safest default), -- use modular-community for other dependencies only where needed. - -## Public release scope for this wave -This public release now focuses on five libraries: -- `mojo-toml` -- `mojo-ini` -- `mojo-yaml` -- `mojo-dotenv` -- `mojo-asciichart` - -## Current status -This closes the current migration execution wave across: -- `mojo-toml` -- `mojo-ini` -- `mojo-yaml` -- `mojo-dotenv` -- `mojo-asciichart` - -## What happens next -Near term, the plan stays simple and low-risk: -- publish and support the five-library `0.9.1` release cleanly, -- keep release mechanics repeatable, -- revisit packaging strategy once the ecosystem settles further. - -## Appendix A: Repo-level technical notes -### `mojo-ini`, `mojo-yaml`, `mojo-dotenv`, `mojo-asciichart` -- Consolidated recipe-path handling and pre-submit flow. -- Synced migration-sensitive docs with the operational command path. -- Retained passing validation with only non-blocking tool warnings. - -### `mojo-benchsuite` -- Updated compatibility in benchmark plumbing. -- Removed brittle subprocess-based version probing. -- Confirmed benchmark task execution after migration. - -### `mojo-data-star` -- Reworked the most brittle 1.0 beta interop surface. -- Simplified data-shape handling to reduce API churn exposure. -- Brought Mojo/Python test paths back into a stable green state. - -### `mojo-fireplace` -- Stabilised Mojo test flow and environment assumptions. -- Updated test patterns for checked raises and current stdlib usage. -- Fixed practical runtime and test-path issues that blocked reliable local validation. - -## Appendix B: Practical migration sequence used -1. Create or switch to `feature/mojo-1.0b1-migration`. -2. Resolve packaging and tooling path consistency first. -3. Run repo-native tests and validation. -4. Fix compiler and runtime issues in clusters. -5. Update docs in the same change set. -6. Re-run full validation before push. - -## Appendix C: Consumer install policy examples -### Option 1: Packaged installs via a DataBooth channel (recommended) -For packaged releases, use one package channel URL plus explicit pins: - -```toml -[project] -channels = [ - "conda-forge", - "https://conda.modular.com/max", - "" -] - -[dependencies] -mojo-toml = "==0.9.1" -mojo-ini = "==0.9.1" -mojo-yaml = "==0.9.1" -mojo-dotenv = "==0.9.1" -mojo-asciichart = "==0.9.1" -``` - -Important: `` is the package index/channel endpoint, not individual GitHub repository URLs. - -If modular-community is present for other packages, explicit pins prevent accidental resolution to older incompatible builds for these libraries. - -### Option 2: Source consumption from GitHub repos (follow-up or experimental) -If you want to consume directly from source, add each library repo and include its `src` path when running Mojo: - -```bash -git submodule add https://github.com/databooth/mojo-toml vendor/mojo-toml -git submodule add https://github.com/databooth/mojo-ini vendor/mojo-ini -git submodule add https://github.com/databooth/mojo-yaml vendor/mojo-yaml -git submodule add https://github.com/databooth/mojo-dotenv vendor/mojo-dotenv -git submodule add https://github.com/databooth/mojo-asciichart vendor/mojo-asciichart -``` - -```bash -mojo \ - -I vendor/mojo-toml/src \ - -I vendor/mojo-ini/src \ - -I vendor/mojo-yaml/src \ - -I vendor/mojo-dotenv/src \ - -I vendor/mojo-asciichart/src \ - your_app.mojo -``` diff --git a/docs/RECIPE_VALIDATION.md b/docs/RECIPE_VALIDATION.md index 67680e6..1ccf8a4 100644 --- a/docs/RECIPE_VALIDATION.md +++ b/docs/RECIPE_VALIDATION.md @@ -114,7 +114,7 @@ tests: ## Integration with Your Workflow -### Pre-commit Hook +### Prek Hook Add to `.pre-commit-config.yaml`: @@ -130,7 +130,7 @@ repos: pass_filenames: false ``` -Then install: `pre-commit install` +Then install: `prek install -f` ### Just Recipe diff --git a/docs/SUBMITTING_TO_MODULAR_COMMUNITY.md b/docs/SUBMITTING_TO_MODULAR_COMMUNITY.md index 775fe88..852e524 100644 --- a/docs/SUBMITTING_TO_MODULAR_COMMUNITY.md +++ b/docs/SUBMITTING_TO_MODULAR_COMMUNITY.md @@ -496,7 +496,7 @@ about: 1. Add validation script: [`scripts/validate-recipe.sh`](../scripts/validate-recipe.sh) 2. Add GitHub Actions: [`.github/workflows/validate-recipe.yml`](../.github/workflows/validate-recipe.yml) -3. Add to pre-commit: +3. Add to prek: ```yaml - repo: local hooks: @@ -545,26 +545,26 @@ requirements: **When to update:** When new stable Mojo releases (check [Mojo changelog](https://docs.modular.com/mojo/changelog/)) -### ✅ Pre-commit Hygiene +### ✅ Prek hygiene **Issue:** Trailing whitespace, incorrect line endings cause CI failures. -**Solution:** Install and run pre-commit in your package repos. +**Solution:** Install and run prek in your package repos. **Setup:** ```bash cd your-package-repo -pixi run bash -c "pre-commit install" -pixi run bash -c "pre-commit run --all-files" +pixi run bash -c "prek install -f" +pixi run bash -c "prek run --all-files" ``` -**Common fixes pre-commit catches:** +**Common fixes prek catches:** - Trailing whitespace - Missing final newlines - YAML/TOML syntax errors - Mixed line endings -**Automate:** Pre-commit runs on every `git commit` once installed. +**Automate:** Prek runs on every `git commit` once installed. ### ✅ Git Tag Management @@ -660,7 +660,7 @@ Use this checklist before creating your PR: **Your Package Repo:** - [ ] Git tag exists and pushed (e.g., `v0.9.1`) - [ ] CodeQL enabled with badge in README -- [ ] Pre-commit hooks installed and passing +- [ ] Prek hooks installed and passing - [ ] Tests pass locally - [ ] LICENSE file exists - [ ] Package image created (512×512 PNG) diff --git a/docs/pixi-pre-submit.md b/docs/pixi-pre-submit.md index c7af433..a342090 100644 --- a/docs/pixi-pre-submit.md +++ b/docs/pixi-pre-submit.md @@ -32,8 +32,8 @@ Individual `test-*` tasks may exist for focused development, but `test-all` is t ### Code quality -- `pre-commit` – runs all pre-commit hooks for this repository. -- `pre-commit-install` – installs the git hooks for local development. +- `prek` – runs all prek hooks for this repository. +- `prek-install` – installs git hook shims for local development. ### Pre-submit for modular-community @@ -59,7 +59,7 @@ The shared core dependencies across the `mojo-*` libraries are: - `mojo` – the Modular toolchain (`==1.0.0b1`). - `python` – used for the test runner, benchmarks, and pre-submit tooling (`">=3.11,<4"`). -- `pre-commit` – for local code quality checks (`">=4.5.1,<5"`). +- `prek` – for local code quality checks (`">=0.4.5,<1"`). - `rattler-build` – for building conda packages (`">=0.55.1,<0.56"`). Each repository may add extra dependencies (for example benchmark counterparts such as `asciichartpy`, `python-dotenv`, `pyyaml`, or `tomli-w`) but the core tooling above is consistent. diff --git a/docs/planning/MOJO_1_0_LIBRARY_MIGRATION_WAVE_PLAN.md b/docs/planning/MOJO_1_0_LIBRARY_MIGRATION_WAVE_PLAN.md new file mode 100644 index 0000000..ab3a743 --- /dev/null +++ b/docs/planning/MOJO_1_0_LIBRARY_MIGRATION_WAVE_PLAN.md @@ -0,0 +1,73 @@ +# Mojo 1.0 Library Migration Wave Plan +## Problem statement +Mojo has reached the 1.0 release phase, and the DataBooth `mojo-*` libraries need a coordinated migration from mixed pre-1.0 and beta-era assumptions to a stable, repeatable Mojo 1.0 baseline. The migration should also produce a progressive public narrative capturing gotchas, lessons, and release-engineering decisions. +## Current state +`mojo-toml` is the furthest along and already uses a workspace manifest plus a 1.0 beta pin (`pixi.toml:1`, `pixi.toml:68`) with an existing migration write-up (`docs/MOJO_1_0_MIGRATION_BLOG.md:2`, `docs/MOJO_1_0_MIGRATION_BLOG.md:4`). +Other target repos still show pre-1.0 posture in one or more places: +* `../mojo-asciichart/pixi.toml:1` and `../mojo-asciichart/pixi.toml:47` +* `../mojo-dotenv/pixi.toml:1` and `../mojo-dotenv/pixi.toml:58` +* `../mojo-ini/pixi.toml:1` and `../mojo-ini/pixi.toml:49` +* `../mojo-yaml/pixi.toml:1` and `../mojo-yaml/pixi.toml:46` +Packaging compiler pins remain at `=0.26.1` in several repos: +* `../mojo-asciichart/packaging/recipe.yaml:3` +* `../mojo-dotenv/packaging/recipe.yaml:3` +* `../mojo-ini/packaging/recipe.yaml:3` +* `../mojo-yaml/packaging/recipe.yaml:3` +`mojo-benchsuite` currently uses a nightly channel and has a placeholder test task (`../mojo-benchsuite/pixi.toml:3`, `../mojo-benchsuite/pixi.toml:40`), so its migration needs both compatibility and release-hardening work. +## Proposed changes +### 1) Establish canonical Mojo 1.0 policy in `mojo-toml` first +Use `mojo-toml` as the pilot repo to define canonical policy for: +* dependency pinning strategy for Mojo 1.0 (runtime + packaging/compiler constraints) +* channels and manifest schema conventions +* recipe pin and compatibility policy +* CI matrix and release validation expectations +Any unresolved ambiguity (pin granularity, channel order, lockfile policy) is decided once in `mojo-toml`, then reused in all sibling repos. +### 2) Create a shared migration playbook before editing sibling repos +After pilot validation in `mojo-toml`, codify one playbook for every repo: +* manifest normalization (`[project]`/`[workspace]`, channels, dependency policy) +* recipe/compiler pin migration and package smoke-test rules +* source/test syntax and stdlib compatibility updates required by 1.0 +* CI/workflow parity requirements (tests, recipe validation, package build) +* post-migration verification commands and acceptance checks +This avoids six one-off migrations and keeps release behavior consistent. +### 2a) Pilot outcomes from `mojo-toml` (playbook v1) +The pilot uncovered one hard compatibility blocker and several mechanical updates that should now be applied proactively in sibling repos. +Core reusable pattern: +* **Recursive value model fix**: Mojo 1.0 rejects direct recursive container fields such as `List[Self]`/`Dict[String, Self]` with Deinitable errors. Use boxed recursive storage (`Pointer[..., MutUntrackedOrigin]`) plus explicit deep-copy and `__deinit__` cleanup for owned boxed values. +Mechanical language/std changes to apply early: +* replace legacy `fn` declarations with `def` +* move test imports from `testing` to `std.testing` +* prefer `std.` import paths (for example `std.math`) +* replace `len(String)` usage with explicit length APIs (`byte_length()`, `len(codepoints())`, or `len(graphemes())` as appropriate) +Validation gate proven in pilot: +* `pixi lock` +* `pixi run mojo-version` +* `pixi run test-all` +* `pixi run build-package` +If these pass in each repo, the migration is functionally complete for that repo’s baseline. +### 3) Roll out to remaining repos in controlled waves +Apply the playbook in two rollout waves: +* Wave A: `../mojo-asciichart`, `../mojo-dotenv`, `../mojo-ini`, `../mojo-yaml` +* Wave B: `../mojo-benchsuite` (includes extra hardening because of current nightly/testing posture) +Each repo migration ends with local validation + CI alignment before moving on. +### 4) Keep release engineering in scope +Migration is complete per repo only when source compatibility and release mechanics both pass: +* tests/examples/benchmarks (repo-appropriate) +* recipe validation +* package build and smoke install checks +* docs alignment for install and release workflows +## Progressive blog capture strategy +Run a parallel documentation stream from day one: +* Keep `docs/MOJO_1_0_MIGRATION_BLOG.md` in `mojo-toml` as the canonical living narrative draft. +* Add structured per-repo migration notes (“what changed / what broke / fix pattern / validation evidence”). +* After each repo wave, fold validated lessons into the central draft with concrete gotchas and reusable patterns. +* Publish once all six repos are migrated and validated, with an appendix of practical interop/tooling pitfalls and mitigations. +## Risk management +Primary risks are hidden API/stdlib incompatibilities, packaging drift, and release workflow regressions. +Mitigation approach: +* pilot-first policy in `mojo-toml` +* strict reuse of one migration playbook +* verification gates at repo boundaries +* progressive documentation so repeated failures become explicit reusable fixes +## Success criteria +Success means all six repos are on a coherent Mojo 1.0 baseline with aligned manifests, recipes, and CI/release workflows, and a publication-ready migration article exists documenting practical gotchas and lessons from the full wave. diff --git a/examples/parse_pixi.mojo b/examples/parse_pixi.mojo index b841e0a..a11a443 100644 --- a/examples/parse_pixi.mojo +++ b/examples/parse_pixi.mojo @@ -7,7 +7,7 @@ the project's own pixi.toml file and generating a detailed report of its content from toml import parse -fn main() raises: +def main() raises: """Parse pixi.toml and generate comprehensive report.""" print("🔥 mojo-toml - Pixi Configuration Report") diff --git a/examples/quickstart.mojo b/examples/quickstart.mojo index 6390413..fb9778a 100644 --- a/examples/quickstart.mojo +++ b/examples/quickstart.mojo @@ -7,7 +7,7 @@ demonstrating both reading and writing TOML files. from toml import parse, to_toml, TomlValue -fn main() raises: +def main() raises: print("🔥 mojo-toml - Quickstart Example") print("=" * 50) print() diff --git a/examples/roundtrip.mojo b/examples/roundtrip.mojo index 05ab42c..41481dc 100644 --- a/examples/roundtrip.mojo +++ b/examples/roundtrip.mojo @@ -10,7 +10,7 @@ from toml import parse, to_toml, TomlValue from std.collections import Dict -fn main() raises: +def main() raises: print("🔥 mojo-toml - Round-trip Example") print("=" * 50) print() diff --git a/examples/simple.mojo b/examples/simple.mojo index 11d4e02..acaf5aa 100644 --- a/examples/simple.mojo +++ b/examples/simple.mojo @@ -6,7 +6,7 @@ This example demonstrates how to parse TOML files and access values. from toml import parse -fn main() raises: +def main() raises: """Demonstrate basic TOML parsing with a simple configuration.""" print("🔥 mojo-toml - Simple Example") diff --git a/examples/test_quickstart.mojo b/examples/test_quickstart.mojo index 5fd27f6..eb82f05 100644 --- a/examples/test_quickstart.mojo +++ b/examples/test_quickstart.mojo @@ -4,11 +4,11 @@ This validates that the quickstart example works correctly and demonstrates testing TOML parsing. """ -from testing import assert_equal, assert_true, TestSuite +from std.testing import assert_equal, assert_true, TestSuite from toml import parse -fn test_quickstart_app() raises: +def test_quickstart_app() raises: """Test parsing app section from quickstart.toml.""" var content: String with open("examples/quickstart.toml", "r") as f: @@ -22,7 +22,7 @@ fn test_quickstart_app() raises: assert_equal(app["debug"].as_bool(), False) -fn test_quickstart_database() raises: +def test_quickstart_database() raises: """Test parsing database section from quickstart.toml.""" var content: String with open("examples/quickstart.toml", "r") as f: @@ -36,7 +36,7 @@ fn test_quickstart_database() raises: assert_equal(db["timeout"].as_float(), 30.5) -fn test_quickstart_features() raises: +def test_quickstart_features() raises: """Test parsing features array from quickstart.toml.""" var content: String with open("examples/quickstart.toml", "r") as f: @@ -51,7 +51,7 @@ fn test_quickstart_features() raises: assert_equal(features[2].as_string(), "metrics") -fn test_quickstart_complete() raises: +def test_quickstart_complete() raises: """Test complete parsing of quickstart.toml.""" var content: String with open("examples/quickstart.toml", "r") as f: diff --git a/justfile b/justfile new file mode 100644 index 0000000..c9613e0 --- /dev/null +++ b/justfile @@ -0,0 +1,17 @@ +default: + @just --list + +pixi-tasks: + @pixi task list + +run task: + pixi run {{task}} + +test: + pixi run test-all + +build: + pixi run build-package + +examples: + pixi run examples-all diff --git a/llms-full.txt b/llms-full.txt new file mode 100644 index 0000000..98ddfc0 --- /dev/null +++ b/llms-full.txt @@ -0,0 +1,21 @@ +# mojo-toml +> Native TOML 1.0 parser and writer for Mojo with zero Python runtime dependencies. +## Project Summary +mojo-toml provides parsing and writing support for TOML configuration files in Mojo. +The library targets TOML 1.0 compliance and includes partial TOML 1.1 support. +## Core Features +- TOML 1.0 parser support, including nested tables, dotted keys, arrays, and inline tables. +- TOML writer support with semantic round-trip fidelity. +- Validation for duplicates and malformed structures with line and column error context. +- Support for additional numeric bases (`0x`, `0o`, `0b`) and selected TOML 1.1 escapes. +## Primary Docs +- Home: https://databooth.github.io/mojo-toml/ +- Changelog: https://databooth.github.io/mojo-toml/changelog.html +- Performance: https://databooth.github.io/mojo-toml/user-guide/PERFORMANCE.html +- Platform builds: https://databooth.github.io/mojo-toml/user-guide/PLATFORM_BUILDS.html +- Roadmap: https://databooth.github.io/mojo-toml/roadmap.html +## Install Guidance +- Recommended packaging and release consumption is documented in the home page and user guide pages. +- For source-based consumption, use the repository and include `src` in Mojo include paths. +## Repository +- GitHub: https://github.com/DataBooth/mojo-toml diff --git a/llms.txt b/llms.txt new file mode 100644 index 0000000..cb9de95 --- /dev/null +++ b/llms.txt @@ -0,0 +1,11 @@ +# mojo-toml +> Native TOML 1.0 parser and writer for Mojo with zero Python runtime dependencies. +## Documentation +- [Home](https://databooth.github.io/mojo-toml/): Project overview, quickstart, installation, and usage. +- [Changelog](https://databooth.github.io/mojo-toml/changelog.html): Release history and version notes. +- [Performance](https://databooth.github.io/mojo-toml/user-guide/PERFORMANCE.html): Benchmark methodology and results. +- [Platform Builds](https://databooth.github.io/mojo-toml/user-guide/PLATFORM_BUILDS.html): Packaging and platform build considerations. +- [Roadmap](https://databooth.github.io/mojo-toml/roadmap.html): Planned improvements and future work. +- [Blog Findings](https://databooth.github.io/mojo-toml/blog/2026-06-20-great-docs-mojo-findings.html): Great Docs rollout findings for this repository. +## Source +- [Repository](https://github.com/DataBooth/mojo-toml) diff --git a/packaging/recipe.yaml b/packaging/recipe.yaml index 71393d4..d691564 100644 --- a/packaging/recipe.yaml +++ b/packaging/recipe.yaml @@ -14,9 +14,9 @@ build: requirements: build: - - mojo-compiler =1.0.0b1 + - mojo-compiler =1.0.0 host: - - mojo-compiler =1.0.0b1 + - mojo-compiler =1.0.0 run: - ${{ pin_compatible('mojo-compiler') }} @@ -29,7 +29,7 @@ tests: about: homepage: https://github.com/DataBooth/mojo-toml - license: MIT + license: Apache-2.0 license_file: LICENSE summary: Native TOML 1.0 parser and writer for Mojo - Complete + Partial 1.1 🔥 description: | diff --git a/pixi.lock b/pixi.lock index 417db71..3200318 100644 --- a/pixi.lock +++ b/pixi.lock @@ -13,7 +13,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_8.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py314h4a8dc5f_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.2-h33c6efd_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda @@ -35,55 +34,42 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/prek-0.4.5-hb17b654_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.2-h32b2ec7_101_cp314.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyzmq-27.1.0-py312hda471dd_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/rattler-build-0.55.1-he64ecbb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.6-py314h5bd0f2a_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.1.0-py314h9891dd4_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h09e67af_11.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.1.4-hbd8a1cb_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.4.1-pyhc90fa1f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.2-py314hd8ed1ab_101.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.20.3-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.16-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.6.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_core-5.9.1-pyhc90fa1f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.2-h4df99d1_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pyyaml-6.0.3-pyh7db6752_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.10.2-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-w-1.2.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.15.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.36.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda - - conda: https://conda.modular.com/max/linux-64/mojo-1.0.0b1-release.conda - - conda: https://conda.modular.com/max/linux-64/mojo-compiler-1.0.0b1-release.conda - - conda: https://conda.modular.com/max/noarch/mblack-26.3.0-release.conda - - conda: https://conda.modular.com/max/noarch/mojo-python-1.0.0b1-release.conda + - conda: https://conda.modular.com/max/linux-64/mojo-1.0.0-release.conda + - conda: https://conda.modular.com/max/linux-64/mojo-compiler-1.0.0-release.conda + - conda: https://conda.modular.com/max/noarch/mblack-26.5.0-release.conda + - conda: https://conda.modular.com/max/noarch/mojo-python-1.0.0-release.conda linux-aarch64: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-2_gnu.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_8.conda - - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cffi-2.0.0-py314h0bd77cf_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.2-hb1525cb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/keyutils-1.6.3-h86ecc28_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/krb5-1.22.2-hfd895c2_0.conda @@ -105,85 +91,61 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.1-h546c87b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/patchelf-0.17.2-h884eca8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/prek-0.4.5-h069e38c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.2-hb06a95a_101_cp314.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyzmq-27.1.0-py312hdf0a211_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rattler-build-0.55.1-hb434046_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tornado-6.5.6-py314hafb4487_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ukkonen-1.1.0-py314hd7d8586_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zeromq-4.3.5-hec9560f_11.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.1.4-hbd8a1cb_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.4.1-pyhc90fa1f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.2-py314hd8ed1ab_101.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.20.3-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.16-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.6.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_core-5.9.1-pyhc90fa1f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.2-h4df99d1_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pyyaml-6.0.3-pyh7db6752_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.10.2-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-w-1.2.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.15.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.36.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda - - conda: https://conda.modular.com/max/linux-aarch64/mojo-1.0.0b1-release.conda - - conda: https://conda.modular.com/max/linux-aarch64/mojo-compiler-1.0.0b1-release.conda - - conda: https://conda.modular.com/max/noarch/mblack-26.3.0-release.conda - - conda: https://conda.modular.com/max/noarch/mojo-python-1.0.0b1-release.conda + - conda: https://conda.modular.com/max/linux-aarch64/mojo-1.0.0-release.conda + - conda: https://conda.modular.com/max/linux-aarch64/mojo-compiler-1.0.0-release.conda + - conda: https://conda.modular.com/max/noarch/mblack-26.5.0-release.conda + - conda: https://conda.modular.com/max/noarch/mojo-python-1.0.0-release.conda osx-arm64: - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.1.4-hbd8a1cb_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.4.1-pyhc90fa1f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.2-py314hd8ed1ab_101.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.20.3-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.16-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.6.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_core-5.9.1-pyhc90fa1f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.2-h4df99d1_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pyyaml-6.0.3-pyh7db6752_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.10.2-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-w-1.2.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.15.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.36.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_8.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-2.0.0-py314h44086f9_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.2-h38cb7af_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-21.1.8-hf598326_1.conda @@ -197,20 +159,19 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.1-hd24854e_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/prek-0.4.5-h6fdd925_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.14.2-h40d2674_101_cp314.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyzmq-27.1.0-py312h022ad19_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/rattler-build-0.55.1-h6fdd925_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.5.6-py314h6c2aa35_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ukkonen-1.1.0-py314h6cfcd04_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zeromq-4.3.5-h10816f8_11.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda - - conda: https://conda.modular.com/max/noarch/mblack-26.3.0-release.conda - - conda: https://conda.modular.com/max/noarch/mojo-python-1.0.0b1-release.conda - - conda: https://conda.modular.com/max/osx-arm64/mojo-1.0.0b1-release.conda - - conda: https://conda.modular.com/max/osx-arm64/mojo-compiler-1.0.0b1-release.conda + - conda: https://conda.modular.com/max/noarch/mblack-26.5.0-release.conda + - conda: https://conda.modular.com/max/noarch/mojo-python-1.0.0-release.conda + - conda: https://conda.modular.com/max/osx-arm64/mojo-1.0.0-release.conda + - conda: https://conda.modular.com/max/osx-arm64/mojo-compiler-1.0.0-release.conda packages: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 sha256: fe51de6107f9edc7aa4f786a70f4a883943bc9d39b3bb7307c04c41410990726 @@ -241,20 +202,6 @@ packages: license_family: BSD size: 260341 timestamp: 1757437258798 -- conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py314h4a8dc5f_1.conda - sha256: c6339858a0aaf5d939e00d345c98b99e4558f285942b27232ac098ad17ac7f8e - md5: cf45f4278afd6f4e6d03eda0f435d527 - depends: - - __glibc >=2.17,<3.0.a0 - - libffi >=3.5.2,<3.6.0a0 - - libgcc >=14 - - pycparser - - python >=3.14,<3.15.0a0 - - python_abi 3.14.* *_cp314 - license: MIT - license_family: MIT - size: 300271 - timestamp: 1761203085220 - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.2-h33c6efd_0.conda sha256: 142a722072fa96cf16ff98eaaf641f54ab84744af81754c292cb81e0881c0329 md5: 186a18e3ba246eccfc7cff00cd19a870 @@ -481,6 +428,19 @@ packages: license_family: GPL size: 94048 timestamp: 1673473024463 +- conda: https://conda.anaconda.org/conda-forge/linux-64/prek-0.4.5-hb17b654_0.conda + sha256: 2928b1ae6f2fb6e980ad40a918323c1b20cfe7d1ae0b92d4d122066429df0156 + md5: 9275f4d52fbe8d5a89e2ad82fd0d738f + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - __glibc >=2.17 + license: MIT + license_family: MIT + run_exports: {} + size: 6049503 + timestamp: 1781546640651 - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.2-h32b2ec7_101_cp314.conda build_number: 101 sha256: 24719868a471dd94041aa9873c6f87adf3b86c07878ad4e242ac97228f9e6460 @@ -574,30 +534,6 @@ packages: license_family: Apache size: 914451 timestamp: 1779915938568 -- conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.1.0-py314h9891dd4_0.conda - sha256: c84034056dc938c853e4f61e72e5bd37e2ec91927a661fb9762f678cbea52d43 - md5: 5d3c008e54c7f49592fca9c32896a76f - depends: - - __glibc >=2.17,<3.0.a0 - - cffi - - libgcc >=14 - - libstdcxx >=14 - - python >=3.14,<3.15.0a0 - - python_abi 3.14.* *_cp314 - license: MIT - license_family: MIT - size: 15004 - timestamp: 1769438727085 -- conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda - sha256: 6d9ea2f731e284e9316d95fa61869fe7bbba33df7929f82693c121022810f4ad - md5: a77f85f77be52ff59391544bfe73390a - depends: - - libgcc >=14 - - __glibc >=2.17,<3.0.a0 - license: MIT - license_family: MIT - size: 85189 - timestamp: 1753484064210 - conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h09e67af_11.conda sha256: dc9f28dedcb5f35a127fad2d847674d2833369dd616d294e423b8997df31d8a8 md5: 96b08867e21d4694fa5c2c226e6581b0 @@ -642,19 +578,6 @@ packages: license_family: BSD size: 192536 timestamp: 1757437302703 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cffi-2.0.0-py314h0bd77cf_1.conda - sha256: 728e55b32bf538e792010308fbe55d26d02903ddc295fbe101167903a123dd6f - md5: f333c475896dbc8b15efd8f7c61154c7 - depends: - - libffi >=3.5.2,<3.6.0a0 - - libgcc >=14 - - pycparser - - python >=3.14,<3.15.0a0 - - python_abi 3.14.* *_cp314 - license: MIT - license_family: MIT - size: 318357 - timestamp: 1761203973223 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.2-hb1525cb_0.conda sha256: 09f7f9213eb68e7e4291cd476e72b37f3ded99ed957528567f32f5ba6b611043 md5: 15b35dc33e185e7d2aac1cfcd6778627 @@ -862,6 +785,18 @@ packages: license_family: GPL size: 101306 timestamp: 1673473812166 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/prek-0.4.5-h069e38c_0.conda + sha256: 60bb50776787c703130d92f3e0319a93b1f4a0574560a91f271b734fe0afc30f + md5: c609cf3ab657f7f4dfc49eb632282e74 + depends: + - libgcc >=14 + constrains: + - __glibc >=2.17 + license: MIT + license_family: MIT + run_exports: {} + size: 5876143 + timestamp: 1781546655454 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.2-hb06a95a_101_cp314.conda build_number: 101 sha256: daca72ef5fa5fc63077c65f5bda424d97d319889c94ae8240567d84fb185f417 @@ -949,29 +884,6 @@ packages: license_family: Apache size: 916159 timestamp: 1779917140941 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ukkonen-1.1.0-py314hd7d8586_0.conda - sha256: 0a7efe469d7e2a34a1d017bc51cf6fb9a51436730256983694c5ad74a33bd4e0 - md5: f3a967efabf9cf450b7741487318ea6e - depends: - - cffi - - libgcc >=14 - - libstdcxx >=14 - - python >=3.14,<3.15.0a0 - - python >=3.14,<3.15.0a0 *_cp314 - - python_abi 3.14.* *_cp314 - license: MIT - license_family: MIT - size: 15756 - timestamp: 1769438772414 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda - sha256: 66265e943f32ce02396ad214e27cb35f5b0490b3bd4f064446390f9d67fa5d88 - md5: 032d8030e4a24fe1f72c74423a46fb88 - depends: - - libgcc >=14 - license: MIT - license_family: MIT - size: 88088 - timestamp: 1753484092643 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zeromq-4.3.5-hec9560f_11.conda sha256: 134bceda31df1ad0dbadb61dd30e7254f5eab398288fcdd8b070946130533b5a md5: 1ae4f546793d83754d79a43a38154746 @@ -1011,15 +923,6 @@ packages: license: ISC size: 146519 timestamp: 1767500828366 -- conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda - sha256: aa589352e61bb221351a79e5946d56916e3c595783994884accdb3b97fe9d449 - md5: 381bd45fb7aa032691f3063aff47e3a1 - depends: - - python >=3.10 - license: MIT - license_family: MIT - size: 13589 - timestamp: 1763607964133 - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.4.1-pyhc90fa1f_0.conda sha256: c253a41cdf898b651a0786cbb76c6d5fc101d0dbbe719f93a124bc4fde5cdd6a md5: 554304a07e581a85891b15e39ea9f268 @@ -1041,33 +944,6 @@ packages: license: Python-2.0 size: 49613 timestamp: 1769457358023 -- conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda - sha256: 6d977f0b2fc24fee21a9554389ab83070db341af6d6f09285360b2e09ef8b26e - md5: 003b8ba0a94e2f1e117d0bd46aebc901 - depends: - - python >=3.9 - license: Apache-2.0 - license_family: APACHE - size: 275642 - timestamp: 1752823081585 -- conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.20.3-pyhd8ed1ab_0.conda - sha256: 8b90dc21f00167a7e58abb5141a140bdb31a7c5734fe1361b5f98f4a4183fd32 - md5: 2cfaaccf085c133a477f0a7a8657afe9 - depends: - - python >=3.10 - license: Unlicense - size: 18661 - timestamp: 1768022315929 -- conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.16-pyhd8ed1ab_0.conda - sha256: 6a88cdde151469131df1948839ac2315ada99cf8d38aaacc9a7a5984e9cd8c19 - md5: 8bc5851c415865334882157127e75799 - depends: - - python >=3.10 - - ukkonen - license: MIT - license_family: MIT - size: 79302 - timestamp: 1768295306539 - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda sha256: 43e2a5497cad1598ff88a3e69f69bc88b7b8f141fa63c60eab5db296317318b8 md5: ffc17e785d64e12fc311af9184221839 @@ -1119,16 +995,6 @@ packages: license_family: MIT size: 11766 timestamp: 1745776666688 -- conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda - sha256: 4fa40e3e13fc6ea0a93f67dfc76c96190afd7ea4ffc1bac2612d954b42cdc3ee - md5: eb52d14a901e23c39e9e7b4a1a5c015f - depends: - - python >=3.10 - - setuptools - license: BSD-3-Clause - license_family: BSD - size: 40866 - timestamp: 1766261270149 - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda sha256: 3906abfb6511a3bb309e39b9b1b7bc38f50a723971de2395489fd1f379255890 md5: 4c06a92e74452cfa53623a81592e8934 @@ -1158,30 +1024,6 @@ packages: license_family: MIT size: 23922 timestamp: 1764950726246 -- conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda - sha256: 5b81b7516d4baf43d0c185896b245fa7384b25dc5615e7baa504b7fa4e07b706 - md5: 7f3ac694319c7eaf81a0325d6405e974 - depends: - - cfgv >=2.0.0 - - identify >=1.0.0 - - nodeenv >=0.11.1 - - python >=3.10 - - pyyaml >=5.1 - - virtualenv >=20.10.0 - license: MIT - license_family: MIT - size: 200827 - timestamp: 1765937577534 -- conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - sha256: 79db7928d13fab2d892592223d7570f5061c192f27b9febd1a418427b719acc6 - md5: 12c566707c80111f9799308d9e265aef - depends: - - python >=3.9 - - python - license: BSD-3-Clause - license_family: BSD - size: 110100 - timestamp: 1733195786147 - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda sha256: d6a17ece93bbd5139e02d2bd7dbfa80bee1a4261dced63f65f679121686bf664 md5: 5b8d21249ff20967101ffa321cab24e8 @@ -1212,27 +1054,6 @@ packages: license_family: BSD size: 6989 timestamp: 1752805904792 -- conda: https://conda.anaconda.org/conda-forge/noarch/pyyaml-6.0.3-pyh7db6752_0.conda - sha256: 828af2fd7bb66afc9ab1c564c2046be391aaf66c0215f05afaf6d7a9a270fe2a - md5: b12f41c0d7fb5ab81709fcc86579688f - depends: - - python >=3.10.* - - yaml - track_features: - - pyyaml_no_compile - license: MIT - license_family: MIT - size: 45223 - timestamp: 1758891992558 -- conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.10.2-pyh332efcf_0.conda - sha256: f5fcb7854d2b7639a5b1aca41dd0f2d5a69a60bbc313e7f192e2dc385ca52f86 - md5: 7b446fcbb6779ee479debb4fd7453e6c - depends: - - python >=3.10 - license: MIT - license_family: MIT - size: 678888 - timestamp: 1769601206751 - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda sha256: 458227f759d5e3fcec5d9b7acce54e10c9e1f4f4b7ec978f3bfd54ce4ee9853d md5: 3339e3b65d58accf4ca4fb8748ab16b3 @@ -1272,35 +1093,12 @@ packages: license_family: BSD size: 115165 timestamp: 1778074251714 -- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - sha256: 032271135bca55aeb156cee361c81350c6f3fb203f57d024d7e5a1fc9ef18731 - md5: 0caa1af407ecff61170c9437a808404d - depends: - - python >=3.10 - - python - license: PSF-2.0 - license_family: PSF - size: 51692 - timestamp: 1756220668932 - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c md5: ad659d0a2b3e47e38d829aa8cad2d610 license: LicenseRef-Public-Domain size: 119135 timestamp: 1767016325805 -- conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.36.1-pyhd8ed1ab_0.conda - sha256: fa0a21fdcd0a8e6cf64cc8cd349ed6ceb373f09854fd3c4365f0bc4586dccf9a - md5: 6b0259cea8ffa6b66b35bae0ca01c447 - depends: - - distlib >=0.3.7,<1 - - filelock >=3.20.1,<4 - - platformdirs >=3.9.1,<5 - - python >=3.10 - - typing_extensions >=4.13.2 - license: MIT - license_family: MIT - size: 4404318 - timestamp: 1768069793682 - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda sha256: 210bd31c22bb88f5e2a167df24c95bb5f152b2ada7502f9b8c49d1f5366db423 md5: ba3dcdc8584155c97c648ae9c044b7a3 @@ -1320,20 +1118,6 @@ packages: license_family: BSD size: 125061 timestamp: 1757437486465 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-2.0.0-py314h44086f9_1.conda - sha256: 5b5ee5de01eb4e4fd2576add5ec9edfc654fbaf9293e7b7ad2f893a67780aa98 - md5: 10dd19e4c797b8f8bdb1ec1fbb6821d7 - depends: - - __osx >=11.0 - - libffi >=3.5.2,<3.6.0a0 - - pycparser - - python >=3.14,<3.15.0a0 - - python >=3.14,<3.15.0a0 *_cp314 - - python_abi 3.14.* *_cp314 - license: MIT - license_family: MIT - size: 292983 - timestamp: 1761203354051 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.2-h38cb7af_0.conda sha256: d4cefbca587429d1192509edc52c88de52bc96c2447771ddc1f8bee928aed5ef md5: 1e93aca311da0210e660d2247812fa02 @@ -1462,6 +1246,18 @@ packages: license_family: Apache size: 3104268 timestamp: 1769556384749 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/prek-0.4.5-h6fdd925_0.conda + sha256: a91f822644bcb308fd8e3dbd079f03fb047784adaff0326768c4746e328d72e3 + md5: 4ce75f6117de1747a3dbe9c9009956d7 + depends: + - __osx >=11.0 + constrains: + - __osx >=11.0 + license: MIT + license_family: MIT + run_exports: {} + size: 5645361 + timestamp: 1781546839263 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.14.2-h40d2674_101_cp314.conda build_number: 101 sha256: 0b3ae49a61b8baf1af8133e8dac0d404a66b634000de0760c8fb692a5ce86e84 @@ -1544,29 +1340,6 @@ packages: license_family: Apache size: 916141 timestamp: 1779916422402 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ukkonen-1.1.0-py314h6cfcd04_0.conda - sha256: 033dbf9859fe58fb85350cf6395be6b1346792e1766d2d5acab538a6eb3659fb - md5: e229f444fbdb28d8c4f40e247154d993 - depends: - - __osx >=11.0 - - cffi - - libcxx >=19 - - python >=3.14,<3.15.0a0 - - python >=3.14,<3.15.0a0 *_cp314 - - python_abi 3.14.* *_cp314 - license: MIT - license_family: MIT - size: 14884 - timestamp: 1769439056290 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda - sha256: b03433b13d89f5567e828ea9f1a7d5c5d697bf374c28a4168d71e9464f5dafac - md5: 78a0fe9e9c50d2c381e8ee47e3ea437d - depends: - - __osx >=11.0 - license: MIT - license_family: MIT - size: 83386 - timestamp: 1753484079473 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zeromq-4.3.5-h10816f8_11.conda sha256: 01fd50d2801b23b59fafea6bf704a6c5faf0f5969104400eae0e6572cb2e5304 md5: d31c0e54c4f9c51100ec8c812ee925d1 @@ -1589,48 +1362,52 @@ packages: license_family: BSD size: 433413 timestamp: 1764777166076 -- conda: https://conda.modular.com/max/linux-64/mojo-1.0.0b1-release.conda - sha256: a8f36a83ece187307d7d78c152828eac58edb002d515de2bcbe9f5a19388b70c - md5: 11bdf0256d179b89dc00ca4150c6963c +- conda: https://conda.modular.com/max/linux-64/mojo-1.0.0-release.conda + sha256: 5778f999b69cf77bd6f07ccaf32d0bafc258fe75206afc8e88919269cebb6e75 + md5: afeb126acb57602a5f9b8153e75e1c3c depends: - python >=3.10 - - mojo-compiler ==1.0.0b1 - - mblack ==26.3.0 + - mojo-compiler ==1.0.0 + - mblack ==26.5.0 - jupyter_client >=8.6.2,<8.7 license: LicenseRef-Modular-Proprietary - size: 94106548 - timestamp: 1777595784229 -- conda: https://conda.modular.com/max/linux-64/mojo-compiler-1.0.0b1-release.conda - sha256: 706c7f8e2be740dda8039bf96182b578bfbbd9220ca1a7f762e1f82acc4eb784 - md5: 2fc6038c3837e50bb855bcf7f930c1c9 - depends: - - mojo-python ==1.0.0b1 + run_exports: {} + size: 115641078 + timestamp: 1786292404342 +- conda: https://conda.modular.com/max/linux-64/mojo-compiler-1.0.0-release.conda + sha256: 4394c6146d47ec7794a9a3ed5775ae158f59f83f8e1aed59408b17c4909821b3 + md5: 75d2e2ca9d87fdc76513d7939202e7dc + depends: + - mojo-python ==1.0.0 license: LicenseRef-Modular-Proprietary - size: 89421276 - timestamp: 1777595833113 -- conda: https://conda.modular.com/max/linux-aarch64/mojo-1.0.0b1-release.conda - sha256: bcc1b91f2d39ab25e430d2de0c552b6f5afe03c13d8d726c4b2aca4ce5e0901e - md5: c6970314e455e0c04eee0be160adbebb + run_exports: {} + size: 68511359 + timestamp: 1786292410712 +- conda: https://conda.modular.com/max/linux-aarch64/mojo-1.0.0-release.conda + sha256: 0f273174733386a584e41489e556c9014a5e975a57bd556d847f252fc9091d76 + md5: 169bbe721ee90fb2fb81744b9212d269 depends: - python >=3.10 - - mojo-compiler ==1.0.0b1 - - mblack ==26.3.0 + - mojo-compiler ==1.0.0 + - mblack ==26.5.0 - jupyter_client >=8.6.2,<8.7 license: LicenseRef-Modular-Proprietary - size: 92647635 - timestamp: 1777595798392 -- conda: https://conda.modular.com/max/linux-aarch64/mojo-compiler-1.0.0b1-release.conda - sha256: 6d6973cc34960597e786ad0f0ed0eba2c005d08eeefd37df53d2cd489ee2acd6 - md5: 6b81a95a59f729be52dc9685210165e5 - depends: - - mojo-python ==1.0.0b1 + run_exports: {} + size: 112856443 + timestamp: 1786292324875 +- conda: https://conda.modular.com/max/linux-aarch64/mojo-compiler-1.0.0-release.conda + sha256: da1772742c54f1f8f7b883e6338b1fe5de4592f2c882220dcceae623cc661e57 + md5: 5a07709330153bf6a5720a01d9294a39 + depends: + - mojo-python ==1.0.0 license: LicenseRef-Modular-Proprietary - size: 86382462 - timestamp: 1777595795606 -- conda: https://conda.modular.com/max/noarch/mblack-26.3.0-release.conda + run_exports: {} + size: 66479788 + timestamp: 1786292303628 +- conda: https://conda.modular.com/max/noarch/mblack-26.5.0-release.conda noarch: python - sha256: c7c36d5b223862acffaaacdfc6f672ca198a046a66f4a956ca57933123fb93b2 - md5: 63c657fb1780079c3f6cbb7a758a16d2 + sha256: 49102b55366eab56b04620533302b8693b4fa4a6c5972b3cc978b3f3bad83ebe + md5: 0cbfc119215c063cd279f0a6beb04285 depends: - python >=3.10 - click >=8.0.0 @@ -1640,33 +1417,37 @@ packages: - platformdirs >=2 - tomli >=1.1.0 license: LicenseRef-Modular-Proprietary - size: 135000 - timestamp: 1777574970629 -- conda: https://conda.modular.com/max/noarch/mojo-python-1.0.0b1-release.conda + run_exports: {} + size: 137187 + timestamp: 1786151006088 +- conda: https://conda.modular.com/max/noarch/mojo-python-1.0.0-release.conda noarch: python - sha256: b0554c7705685c86e8a8063bcd11ed58897a498c8e1e19ef045f5ebba2c8874f - md5: d0ad2f8ba3758f03bfda84d92bb34b67 + sha256: fc449a47c7707ed96a794768e29d5d2b0bf7afab373e2a9751f281ed7c4f822c + md5: 4a27e1596a5c2d27330a2377090b12c5 depends: - python >=3.10 license: LicenseRef-Modular-Proprietary - size: 23114 - timestamp: 1777594699418 -- conda: https://conda.modular.com/max/osx-arm64/mojo-1.0.0b1-release.conda - sha256: 2980b825e3eedb153f68f74edeaae6a7b819912c3eb6e49f1eed7d25f883e050 - md5: b5f2c6b04a9e2bbe199fef1ea5677014 + run_exports: {} + size: 24040 + timestamp: 1785891558838 +- conda: https://conda.modular.com/max/osx-arm64/mojo-1.0.0-release.conda + sha256: 200bd9ace6e06ad2a9b4f4cce9afa3e5f3c00b3d87a6d57206249df2a5568e38 + md5: 954433eb905b424cc3d4325c9c2242de depends: - python >=3.10 - - mojo-compiler ==1.0.0b1 - - mblack ==26.3.0 + - mojo-compiler ==1.0.0 + - mblack ==26.5.0 - jupyter_client >=8.6.2,<8.7 license: LicenseRef-Modular-Proprietary - size: 83375027 - timestamp: 1777596028766 -- conda: https://conda.modular.com/max/osx-arm64/mojo-compiler-1.0.0b1-release.conda - sha256: 3e0d6e6e814cb39d14d24234eb8f2ac6524379ea0a9c398a54e77598844e96d6 - md5: fe08c02512b02563a0b878eeb32a684b - depends: - - mojo-python ==1.0.0b1 + run_exports: {} + size: 101155040 + timestamp: 1786294689438 +- conda: https://conda.modular.com/max/osx-arm64/mojo-compiler-1.0.0-release.conda + sha256: c52054bc444d851e5c38cc33e790fb011a1080470244aaa59351ac5056d08c59 + md5: b5103c9d9978173a1e97c5e5eed1aeba + depends: + - mojo-python ==1.0.0 license: LicenseRef-Modular-Proprietary - size: 67503416 - timestamp: 1777596016502 + run_exports: {} + size: 61221085 + timestamp: 1786294690001 diff --git a/pixi.toml b/pixi.toml index d96c6a3..46d354b 100644 --- a/pixi.toml +++ b/pixi.toml @@ -61,12 +61,12 @@ benchmark-mojo = "python benchmarks/run_mojo_benchmark.py" benchmark-python = "python benchmarks/compare_python.py" # Code quality tasks -pre-commit = "pre-commit run --all-files" -pre-commit-install = "pre-commit install" +prek = "prek run --all-files" +prek-install = "prek install -f" [dependencies] -mojo = "==1.0.0b1" +mojo = "==1.0.0" python = ">=3.11,<4" # Required for test runner and benchmarks tomli-w = ">=1.0.0,<2" # For write benchmarks (tomllib is read-only) -pre-commit = ">=4.5.1,<5" +prek = ">=0.4.5,<1" rattler-build = ">=0.55.1,<0.56" diff --git a/recipe.yaml b/recipe.yaml index d79fc82..b1c36ff 100644 --- a/recipe.yaml +++ b/recipe.yaml @@ -1,6 +1,6 @@ context: version: 0.9.1 - mojo_version: "=1.0.0b1" + mojo_version: "=1.0.0" package: name: mojo-toml diff --git a/src/toml/lexer.mojo b/src/toml/lexer.mojo index 24952bc..2d53060 100644 --- a/src/toml/lexer.mojo +++ b/src/toml/lexer.mojo @@ -45,7 +45,7 @@ struct Position(Copyable, Movable): var line: Int var column: Int - fn __init__(out self, line: Int, column: Int): + def __init__(out self, line: Int, column: Int): self.line = line self.column = column @@ -58,102 +58,102 @@ struct TokenKind(Copyable, Movable): """ var _value: Int - fn __init__(out self, value: Int): + def __init__(out self, value: Int): self._value = value # Special tokens @staticmethod - fn EOF() -> TokenKind: + def EOF() -> TokenKind: """End of file marker.""" return TokenKind(0) @staticmethod - fn NEWLINE() -> TokenKind: + def NEWLINE() -> TokenKind: """Line break (significant in TOML for separating key-value pairs).""" return TokenKind(1) @staticmethod - fn WHITESPACE() -> TokenKind: + def WHITESPACE() -> TokenKind: """Spaces and tabs (usually skipped).""" return TokenKind(2) @staticmethod - fn COMMENT() -> TokenKind: + def COMMENT() -> TokenKind: """Comment text after # symbol.""" return TokenKind(3) # Literal values @staticmethod - fn STRING() -> TokenKind: + def STRING() -> TokenKind: """String literal: "basic" or 'literal'.""" return TokenKind(10) @staticmethod - fn INTEGER() -> TokenKind: + def INTEGER() -> TokenKind: """Integer: 42, +17, -5, 1_000.""" return TokenKind(11) @staticmethod - fn FLOAT() -> TokenKind: + def FLOAT() -> TokenKind: """Float: 3.14, 1e10, inf, nan.""" return TokenKind(12) @staticmethod - fn BOOLEAN() -> TokenKind: + def BOOLEAN() -> TokenKind: """Boolean: true or false.""" return TokenKind(13) @staticmethod - fn DATETIME() -> TokenKind: + def DATETIME() -> TokenKind: """ISO 8601 datetime (parsed as string in v0.1.0).""" return TokenKind(14) # Identifiers @staticmethod - fn KEY() -> TokenKind: + def KEY() -> TokenKind: """Unquoted key name.""" return TokenKind(20) # Punctuation (structural elements) @staticmethod - fn EQUALS() -> TokenKind: + def EQUALS() -> TokenKind: """Assignment operator: =.""" return TokenKind(30) @staticmethod - fn DOT() -> TokenKind: + def DOT() -> TokenKind: """Dotted key separator: a.b.c.""" return TokenKind(31) @staticmethod - fn COMMA() -> TokenKind: + def COMMA() -> TokenKind: """Array/inline table separator: ,.""" return TokenKind(32) @staticmethod - fn LEFT_BRACKET() -> TokenKind: + def LEFT_BRACKET() -> TokenKind: """Array start or table header: [.""" return TokenKind(33) @staticmethod - fn RIGHT_BRACKET() -> TokenKind: + def RIGHT_BRACKET() -> TokenKind: """Array end or table header close: ].""" return TokenKind(34) @staticmethod - fn LEFT_BRACE() -> TokenKind: + def LEFT_BRACE() -> TokenKind: """Inline table start: {.""" return TokenKind(35) @staticmethod - fn RIGHT_BRACE() -> TokenKind: + def RIGHT_BRACE() -> TokenKind: """Inline table end: }.""" return TokenKind(36) - fn __eq__(self, other: TokenKind) -> Bool: + def __eq__(self, other: TokenKind) -> Bool: return self._value == other._value - fn __ne__(self, other: TokenKind) -> Bool: + def __ne__(self, other: TokenKind) -> Bool: return self._value != other._value @@ -167,7 +167,7 @@ struct Token(Copyable, Movable): var value: String # The actual text content var pos: Position # Where it appears in the file - fn __init__(out self, kind: TokenKind, value: String, pos: Position): + def __init__(out self, kind: TokenKind, value: String, pos: Position): self.kind = kind.copy() self.value = value self.pos = pos.copy() @@ -195,7 +195,7 @@ struct Lexer: var line: Int # Current line number (1-indexed) var column: Int # Current column number (1-indexed) - fn __init__(out self, input: String): + def __init__(out self, input: String): """Initialise lexer with TOML input. Args: @@ -211,7 +211,7 @@ struct Lexer: self.line = 1 self.column = 1 - fn current(self) -> String: + def current(self) -> String: """Get current character without advancing. Returns: @@ -221,7 +221,7 @@ struct Lexer: return "" return self.chars[self.pos] - fn peek(self, offset: Int = 1) -> String: + def peek(self, offset: Int = 1) -> String: """Look ahead at character without consuming it. Used for lookahead decisions, e.g. detecting triple quotes. @@ -237,7 +237,7 @@ struct Lexer: return "" return self.chars[peek_pos] - fn advance(mut self) -> String: + def advance(mut self) -> String: """Consume and return current character. Advances position and updates line/column tracking for error messages. @@ -259,7 +259,7 @@ struct Lexer: return c - fn skip_whitespace(mut self): + def skip_whitespace(mut self): """Skip whitespace characters (space, tab) but not newlines. Newlines are significant in TOML for separating key-value pairs, @@ -272,7 +272,7 @@ struct Lexer: else: break - fn read_comment(mut self) raises -> Token: + def read_comment(mut self) raises -> Token: """Read a comment starting with #. Comments run from # to end of line. They can appear after values: @@ -293,7 +293,7 @@ struct Lexer: return Token(TokenKind.COMMENT(), comment, start_pos) - fn read_string(mut self) raises -> Token: + def read_string(mut self) raises -> Token: """Read a quoted string (basic or literal). TOML supports two string types: @@ -385,7 +385,7 @@ struct Lexer: return Token(TokenKind.STRING(), value, start_pos) - fn read_number(mut self) raises -> Token: + def read_number(mut self) raises -> Token: """Read a number (integer or float). TOML supports rich number formats: @@ -497,7 +497,7 @@ struct Lexer: else: return Token(TokenKind.INTEGER(), value, start_pos) - fn read_key(mut self) raises -> Token: + def read_key(mut self) raises -> Token: """Read an unquoted key or boolean/datetime value. Unquoted keys can contain: a-z, A-Z, 0-9, _, - @@ -528,7 +528,7 @@ struct Lexer: return Token(TokenKind.KEY(), value, start_pos) - fn next_token(mut self) raises -> Token: + def next_token(mut self) raises -> Token: """Get the next token from the input. This is the main lexer logic that dispatches to specific readers @@ -605,7 +605,7 @@ struct Lexer: # Unquoted key or boolean return self.read_key() - fn is_hex_digit(self, c: String) -> Bool: + def is_hex_digit(self, c: String) -> Bool: """Check if character is a hexadecimal digit (0-9, a-f, A-F). Args: @@ -616,7 +616,7 @@ struct Lexer: """ return (c >= "0" and c <= "9") or (c >= "a" and c <= "f") or (c >= "A" and c <= "F") - fn hex_to_int(self, hex_str: String) -> Int: + def hex_to_int(self, hex_str: String) -> Int: """Convert a 2-character hex string to integer. Args: @@ -645,7 +645,7 @@ struct Lexer: result = result * 16 + digit_value return result - fn tokenize(mut self) raises -> List[Token]: + def tokenize(mut self) raises -> List[Token]: """Tokenise entire input into list of tokens. This is the main public API for the lexer. It produces a complete diff --git a/src/toml/parser.mojo b/src/toml/parser.mojo index 4d456bf..c9a8fe7 100644 --- a/src/toml/parser.mojo +++ b/src/toml/parser.mojo @@ -26,8 +26,9 @@ This keeps parsing logic separate from tokenisation, making both simpler. """ from std.collections import Dict, List -from math import inf, nan -from .lexer import Token, TokenKind, Lexer +from std.memory import alloc +from std.math import inf, nan +from .lexer import Token, TokenKind, Lexer, Position struct KeyValuePair(Movable, Copyable): @@ -35,11 +36,11 @@ struct KeyValuePair(Movable, Copyable): var key: String var value: TomlValue - fn __init__(out self, key: String, var value: TomlValue): + def __init__(out self, key: String, var value: TomlValue): self.key = key self.value = value^ - fn copy(self) -> Self: + def copy(self) -> Self: return KeyValuePair(self.key, self.value.copy()) @@ -62,158 +63,189 @@ struct TomlValue(Copyable, Movable): arrays, and tables (nested dicts). """ + comptime ValuePointer = Pointer[TomlValue, MutUntrackedOrigin] + var value_type: Int var string_value: String var int_value: Int var float_value: Float64 var bool_value: Bool - var array_value: List[TomlValue] - var table_value: Dict[String, TomlValue] - - fn __init__(out self, value: String): + var array_value: List[Self.ValuePointer] + var table_value: Dict[String, Self.ValuePointer] + + @staticmethod + def box_value(var value: TomlValue) -> Self.ValuePointer: + """Allocate a boxed TomlValue for recursive storage.""" + var ptr = alloc[TomlValue](1) + ptr.unsafe_write(value^) + return ptr + + @staticmethod + def clone_boxed_value(value_ptr: Self.ValuePointer) -> Self.ValuePointer: + """Deep-copy a boxed TomlValue into a new allocation.""" + var copied = value_ptr[].copy() + return Self.box_value(copied^) + + def __init__(out self, value: String): """Create string value.""" self.value_type = TomlValueType.STRING self.string_value = value self.int_value = 0 self.float_value = 0.0 self.bool_value = False - self.array_value = List[TomlValue]() - self.table_value = Dict[String, TomlValue]() + self.array_value = List[Self.ValuePointer]() + self.table_value = Dict[String, Self.ValuePointer]() - fn __init__(out self, value: Int): + def __init__(out self, value: Int): """Create integer value.""" self.value_type = TomlValueType.INTEGER self.string_value = "" self.int_value = value self.float_value = 0.0 self.bool_value = False - self.array_value = List[TomlValue]() - self.table_value = Dict[String, TomlValue]() + self.array_value = List[Self.ValuePointer]() + self.table_value = Dict[String, Self.ValuePointer]() - fn __init__(out self, value: Float64): + def __init__(out self, value: Float64): """Create float value.""" self.value_type = TomlValueType.FLOAT self.string_value = "" self.int_value = 0 self.float_value = value self.bool_value = False - self.array_value = List[TomlValue]() - self.table_value = Dict[String, TomlValue]() + self.array_value = List[Self.ValuePointer]() + self.table_value = Dict[String, Self.ValuePointer]() - fn __init__(out self, value: Bool): + def __init__(out self, value: Bool): """Create boolean value.""" self.value_type = TomlValueType.BOOLEAN self.string_value = "" self.int_value = 0 self.float_value = 0.0 self.bool_value = value - self.array_value = List[TomlValue]() - self.table_value = Dict[String, TomlValue]() + self.array_value = List[Self.ValuePointer]() + self.table_value = Dict[String, Self.ValuePointer]() - fn __init__(out self, var value: List[TomlValue]): + def __init__(out self, var value: List[TomlValue]): """Create array value.""" self.value_type = TomlValueType.ARRAY self.string_value = "" self.int_value = 0 self.float_value = 0.0 self.bool_value = False - self.array_value = value^ - self.table_value = Dict[String, TomlValue]() + self.array_value = List[Self.ValuePointer]() + self.table_value = Dict[String, Self.ValuePointer]() - fn __init__(out self, var value: Dict[String, TomlValue]): + for i in range(len(value)): + var element_copy = value[i].copy() + self.array_value.append(Self.box_value(element_copy^)) + + def __init__(out self, var value: Dict[String, TomlValue]): """Create table (inline table) value.""" self.value_type = TomlValueType.TABLE self.string_value = "" self.int_value = 0 self.float_value = 0.0 self.bool_value = False - self.array_value = List[TomlValue]() - self.table_value = value^ + self.array_value = List[Self.ValuePointer]() + self.table_value = Dict[String, Self.ValuePointer]() + + for entry in value.items(): + var entry_copy = entry.value.copy() + self.table_value[entry.key] = Self.box_value(entry_copy^) + + def __init__(out self, *, copy: Self): + """Create a deep copy of this value.""" + self.value_type = copy.value_type + self.string_value = copy.string_value + self.int_value = copy.int_value + self.float_value = copy.float_value + self.bool_value = copy.bool_value + self.array_value = List[Self.ValuePointer]() + self.table_value = Dict[String, Self.ValuePointer]() + + for i in range(len(copy.array_value)): + self.array_value.append(Self.clone_boxed_value(copy.array_value[i])) + + for entry in copy.table_value.items(): + self.table_value[entry.key] = Self.clone_boxed_value(entry.value) + + def __deinit__(deinit self): + """Free boxed recursive values owned by this instance.""" + for i in range(len(self.array_value)): + var ptr = self.array_value[i] + ptr.unsafe_deinit_pointee() + ptr.unsafe_free() - fn is_string(self) -> Bool: + for entry in self.table_value.items(): + var ptr = entry.value + ptr.unsafe_deinit_pointee() + ptr.unsafe_free() + + def is_string(self) -> Bool: return self.value_type == TomlValueType.STRING - fn is_int(self) -> Bool: + def is_int(self) -> Bool: return self.value_type == TomlValueType.INTEGER - fn is_float(self) -> Bool: + def is_float(self) -> Bool: return self.value_type == TomlValueType.FLOAT - fn is_bool(self) -> Bool: + def is_bool(self) -> Bool: return self.value_type == TomlValueType.BOOLEAN - fn is_array(self) -> Bool: + def is_array(self) -> Bool: return self.value_type == TomlValueType.ARRAY - fn is_table(self) -> Bool: + def is_table(self) -> Bool: return self.value_type == TomlValueType.TABLE - fn copy(self) -> Self: - """Create a copy of this value.""" - if self.value_type == TomlValueType.STRING: - return TomlValue(self.string_value) - elif self.value_type == TomlValueType.INTEGER: - return TomlValue(self.int_value) - elif self.value_type == TomlValueType.FLOAT: - return TomlValue(self.float_value) - elif self.value_type == TomlValueType.BOOLEAN: - return TomlValue(self.bool_value) - elif self.value_type == TomlValueType.ARRAY: - var arr_copy = List[TomlValue]() - for i in range(len(self.array_value)): - arr_copy.append(self.array_value[i].copy()) - return TomlValue(arr_copy^) - elif self.value_type == TomlValueType.TABLE: - var table_copy = Dict[String, TomlValue]() - for entry in self.table_value.items(): - table_copy[entry.key] = entry.value.copy() - return TomlValue(table_copy^) - else: - # Should not reach here - return TomlValue("") + def copy(self) -> Self: + """Create a deep copy of this value.""" + return Self(copy=self) - fn as_string(self) raises -> String: + def as_string(self) raises -> String: """Get string value (raises if not a string).""" if not self.is_string(): raise Error("Value is not a string") return self.string_value - fn as_int(self) raises -> Int: + def as_int(self) raises -> Int: """Get integer value (raises if not an integer).""" if not self.is_int(): raise Error("Value is not an integer") return self.int_value - fn as_float(self) raises -> Float64: + def as_float(self) raises -> Float64: """Get float value (raises if not a float).""" if not self.is_float(): raise Error("Value is not a float") return self.float_value - fn as_bool(self) raises -> Bool: + def as_bool(self) raises -> Bool: """Get boolean value (raises if not a boolean).""" if not self.is_bool(): raise Error("Value is not a boolean") return self.bool_value - fn as_array(self) raises -> List[TomlValue]: + def as_array(self) raises -> List[TomlValue]: """Get array value (raises if not an array).""" if not self.is_array(): raise Error("Value is not an array") # Return a copy since we can't return a reference var result = List[TomlValue]() for i in range(len(self.array_value)): - result.append(self.array_value[i].copy()) + result.append(self.array_value[i][].copy()) return result^ - fn as_table(self) raises -> Dict[String, TomlValue]: + def as_table(self) raises -> Dict[String, TomlValue]: """Get table value (raises if not a table).""" if not self.is_table(): raise Error("Value is not a table") # Return a copy of the table var result = Dict[String, TomlValue]() for entry in self.table_value.items(): - result[entry.key] = entry.value.copy() + result[entry.key] = entry.value[].copy() return result^ @@ -234,7 +266,7 @@ struct Parser: var current_table_path: List[String] # Track current table path for flat key storage var is_array_of_tables: Bool # True if current path is an array of tables [[...]] - fn __init__(out self, var tokens: List[Token]): + def __init__(out self, var tokens: List[Token]): """Initialise parser with token stream. Args: @@ -245,7 +277,7 @@ struct Parser: self.current_table_path = List[String]() self.is_array_of_tables = False - fn reset(mut self, var tokens: List[Token]): + def reset(mut self, var tokens: List[Token]): """Reset parser state for reuse with new token stream. Allows reusing the same Parser instance for multiple documents, @@ -268,7 +300,7 @@ struct Parser: self.current_table_path = List[String]() self.is_array_of_tables = False - fn current(self) raises -> Token: + def current(self) raises -> Token: """Get current token without advancing. Returns: @@ -279,7 +311,7 @@ struct Parser: # Must copy since we're returning from borrowed self return Token(self.tokens[self.pos].kind, self.tokens[self.pos].value, self.tokens[self.pos].pos) - fn peek(self, offset: Int = 1) raises -> Token: + def peek(self, offset: Int = 1) raises -> Token: """Look ahead at token. Args: @@ -293,7 +325,7 @@ struct Parser: # Must copy token explicitly return Token(self.tokens[peek_pos].kind, self.tokens[peek_pos].value, self.tokens[peek_pos].pos) - fn advance(mut self) raises -> Token: + def advance(mut self) raises -> Token: """Consume and return current token. Returns: @@ -303,7 +335,7 @@ struct Parser: self.pos += 1 return tok^ - fn expect(mut self, kind: TokenKind) raises: + def expect(mut self, kind: TokenKind) raises: """Expect a specific token type and consume it. Args: @@ -313,7 +345,7 @@ struct Parser: if token.kind != kind: raise Error(self.format_error("Expected specific token type but got different type", token.pos)) - fn skip_newlines(mut self): + def skip_newlines(mut self): """Skip any newline tokens.""" while self.pos < len(self.tokens): try: @@ -325,7 +357,7 @@ struct Parser: except: break - fn skip_whitespace_and_newlines(mut self): + def skip_whitespace_and_newlines(mut self): """Skip whitespace and newline tokens (used inside arrays/tables).""" while self.pos < len(self.tokens): try: @@ -337,7 +369,7 @@ struct Parser: except: break - fn parse_inline_table(mut self) raises -> TomlValue: + def parse_inline_table(mut self) raises -> TomlValue: """Parse a TOML inline table {name = "value", port = 8080}. Returns: @@ -388,7 +420,7 @@ struct Parser: return TomlValue(table^) - fn parse_array(mut self) raises -> TomlValue: + def parse_array(mut self) raises -> TomlValue: """Parse a TOML array [1, 2, 3]. Returns: @@ -437,7 +469,7 @@ struct Parser: return TomlValue(elements^) - fn parse_value(mut self) raises -> TomlValue: + def parse_value(mut self) raises -> TomlValue: """Parse a TOML value (string, number, bool, array, or inline table). Returns: @@ -488,7 +520,7 @@ struct Parser: else: raise Error(self.format_error("Unexpected token in value position", token.pos)) - fn parse_integer(self, value_str: String) raises -> Int: + def parse_integer(self, value_str: String) raises -> Int: """Parse integer string, handling alternative bases. Supports: @@ -504,7 +536,7 @@ struct Parser: var clean_value = value_str # Short values cannot have base prefixes; treat as decimal - if len(clean_value) <= 2: + if clean_value.byte_length() <= 2: return atol(clean_value) # Convert to a list of single-character strings to avoid direct String indexing. @@ -528,7 +560,7 @@ struct Parser: else: return atol(clean_value) - fn parse_hex(self, hex_str: String) raises -> Int: + def parse_hex(self, hex_str: String) raises -> Int: """Parse hexadecimal string to integer. Args: @@ -563,7 +595,7 @@ struct Parser: return result - fn parse_octal(self, octal_str: String) raises -> Int: + def parse_octal(self, octal_str: String) raises -> Int: """Parse octal string to integer. Args: @@ -591,7 +623,7 @@ struct Parser: return result - fn parse_binary(self, binary_str: String) raises -> Int: + def parse_binary(self, binary_str: String) raises -> Int: """Parse binary string to integer. Args: @@ -619,7 +651,7 @@ struct Parser: return result - fn copy_path(self, path: List[String]) -> List[String]: + def copy_path(self, path: List[String]) -> List[String]: """Create a copy of a path list. Mojo List does not support implicit copying, so we must manually copy. @@ -634,7 +666,7 @@ struct Parser: result.append(path[i]) return result^ - fn format_error(self, message: String, pos: Position) -> String: + def format_error(self, message: String, pos: Position) -> String: """Format an error message with line and column information. Args: @@ -645,7 +677,7 @@ struct Parser: """ return message + " at line " + String(pos.line) + ", column " + String(pos.column) - fn parse_table_header(mut self) raises -> List[String]: + def parse_table_header(mut self) raises -> List[String]: """Parse a table header [section.name] and return the path. Returns: @@ -683,7 +715,7 @@ struct Parser: return path^ - fn parse_array_of_tables_header(mut self) raises -> List[String]: + def parse_array_of_tables_header(mut self) raises -> List[String]: """Parse an array of tables header [[section.name]] and return the path. Returns: @@ -728,7 +760,7 @@ struct Parser: return path^ - fn ensure_table_path(mut self, result: Dict[String, TomlValue], path: List[String]) raises -> Dict[String, TomlValue]: + def ensure_table_path(mut self, result: Dict[String, TomlValue], path: List[String]) raises -> Dict[String, TomlValue]: """Ensure a nested table path exists, creating tables as needed. Args: @@ -769,7 +801,7 @@ struct Parser: return new_result^ - fn ensure_array_of_tables_path(mut self, result: Dict[String, TomlValue], path: List[String]) raises -> Dict[String, TomlValue]: + def ensure_array_of_tables_path(mut self, result: Dict[String, TomlValue], path: List[String]) raises -> Dict[String, TomlValue]: """Ensure an array of tables path exists, creating or appending as needed. For [[products]], this creates or appends to the 'products' array. @@ -893,7 +925,7 @@ struct Parser: new_result[first_key] = TomlValue(nested_table^) return new_result^ - fn set_table_at_path(mut self, result: Dict[String, TomlValue], path: List[String], var table: Dict[String, TomlValue]) raises -> Dict[String, TomlValue]: + def set_table_at_path(mut self, result: Dict[String, TomlValue], path: List[String], var table: Dict[String, TomlValue]) raises -> Dict[String, TomlValue]: """Set a table at a specific path (helper for array of tables). Args: @@ -923,7 +955,7 @@ struct Parser: new_result[first_key] = TomlValue(nested_table^) return new_result^ - fn merge_tables(self, existing: Dict[String, TomlValue], var new_table: TomlValue, key: String) raises -> Dict[String, TomlValue]: + def merge_tables(self, existing: Dict[String, TomlValue], var new_table: TomlValue, key: String) raises -> Dict[String, TomlValue]: """Merge a new table value into existing table, checking for conflicts. Args: @@ -958,7 +990,7 @@ struct Parser: return result^ - fn set_in_table_path(mut self, result: Dict[String, TomlValue], path: List[String], key: String, var value: TomlValue) raises -> Dict[String, TomlValue]: + def set_in_table_path(mut self, result: Dict[String, TomlValue], path: List[String], key: String, var value: TomlValue) raises -> Dict[String, TomlValue]: """Set a key-value pair at a specific table path with duplicate key detection. Args: @@ -1008,7 +1040,7 @@ struct Parser: new_result[path[0]] = TomlValue(table^) return new_result^ - fn set_in_array_of_tables_path(mut self, result: Dict[String, TomlValue], path: List[String], key: String, var value: TomlValue) raises -> Dict[String, TomlValue]: + def set_in_array_of_tables_path(mut self, result: Dict[String, TomlValue], path: List[String], key: String, var value: TomlValue) raises -> Dict[String, TomlValue]: """Set a key-value pair in the last element of an array of tables. Args: @@ -1146,7 +1178,7 @@ struct Parser: new_result[first_key] = TomlValue(nested_table^) return new_result^ - fn create_nested_value_from_dotted_key(self, key_parts: List[String], var value: TomlValue) raises -> TomlValue: + def create_nested_value_from_dotted_key(self, key_parts: List[String], var value: TomlValue) raises -> TomlValue: """Convert dotted key into nested table structure. For example: a.b.c = value becomes {a: {b: {c: value}}} @@ -1168,7 +1200,7 @@ struct Parser: return result^ - fn parse_key_value_pair(mut self) raises -> KeyValuePair: + def parse_key_value_pair(mut self) raises -> KeyValuePair: """Parse a key = value pair and return the key and value. Returns: @@ -1217,7 +1249,7 @@ struct Parser: var nested_value = self.create_nested_value_from_dotted_key(key_parts, value^) return KeyValuePair(key_parts[0], nested_value^) - fn parse(mut self) raises -> Dict[String, TomlValue]: + def parse(mut self) raises -> Dict[String, TomlValue]: """Parse the entire TOML document. Returns: @@ -1304,7 +1336,7 @@ struct Parser: raise Error(self.format_error("Unexpected token at top level", token.pos)) return result^ -fn parse(content: String) raises -> Dict[String, TomlValue]: +def parse(content: String) raises -> Dict[String, TomlValue]: """Parse TOML content from a string. This is the main public API for parsing TOML. diff --git a/src/toml/writer.mojo b/src/toml/writer.mojo index 1e66242..8fcb0c1 100644 --- a/src/toml/writer.mojo +++ b/src/toml/writer.mojo @@ -39,11 +39,11 @@ struct Writer: var buffer: String - fn __init__(out self): + def __init__(out self): """Initialise writer with empty buffer.""" self.buffer = "" - fn escape_string(self, s: String) -> String: + def escape_string(self, s: String) -> String: """Escape special characters in strings for TOML output. Handles: @@ -91,7 +91,7 @@ struct Writer: return result - fn format_string(self, s: String) -> String: + def format_string(self, s: String) -> String: """Format a string value for TOML output. Args: @@ -101,7 +101,7 @@ struct Writer: """ return "\"" + self.escape_string(s) + "\"" - fn format_integer(self, n: Int) -> String: + def format_integer(self, n: Int) -> String: """Format an integer value for TOML output. Args: @@ -111,7 +111,7 @@ struct Writer: """ return String(n) - fn format_float(self, f: Float64) -> String: + def format_float(self, f: Float64) -> String: """Format a float value for TOML output. Handles special values: inf, -inf, nan @@ -135,7 +135,7 @@ struct Writer: else: return String(f) - fn format_boolean(self, b: Bool) -> String: + def format_boolean(self, b: Bool) -> String: """Format a boolean value for TOML output. Args: @@ -145,7 +145,7 @@ struct Writer: """ return "true" if b else "false" - fn format_array(self, arr: List[TomlValue]) raises -> String: + def format_array(self, arr: List[TomlValue]) raises -> String: """Format an array for TOML output. Args: @@ -165,7 +165,7 @@ struct Writer: result += "]" return result - fn format_inline_table(self, table: Dict[String, TomlValue]) raises -> String: + def format_inline_table(self, table: Dict[String, TomlValue]) raises -> String: """Format an inline table for TOML output. Args: @@ -191,7 +191,7 @@ struct Writer: result += " }" return result - fn format_value(self, value: TomlValue) raises -> String: + def format_value(self, value: TomlValue) raises -> String: """Format any TomlValue for TOML output. Args: @@ -214,7 +214,7 @@ struct Writer: else: raise Error("Unknown value type") - fn should_use_inline(self, table: Dict[String, TomlValue]) -> Bool: + def should_use_inline(self, table: Dict[String, TomlValue]) -> Bool: """Determine if a table should be written as inline table. Heuristic: @@ -243,7 +243,7 @@ struct Writer: # Very small table (0-1 keys) with only simple values: use inline return True - fn write_key_value(mut self, key: String, value: TomlValue) raises: + def write_key_value(mut self, key: String, value: TomlValue) raises: """Write a key-value pair to the buffer. Args: @@ -254,7 +254,7 @@ struct Writer: self.buffer += self.format_value(value) self.buffer += "\n" - fn write_table_header(mut self, path: List[String]): + def write_table_header(mut self, path: List[String]): """Write a table header to the buffer. Args: @@ -272,7 +272,7 @@ struct Writer: self.buffer += "]\n" - fn write_table(mut self, path: List[String], table: Dict[String, TomlValue]) raises: + def write_table(mut self, path: List[String], table: Dict[String, TomlValue]) raises: """Write a table with proper [section] header. Recursively handles nested tables. @@ -329,14 +329,14 @@ struct Writer: # Recursively write nested table self.write_table(new_path, table[key].as_table()) - fn to_string(self) -> String: + def to_string(self) -> String: """Get the final TOML string. Returns: Complete TOML document. """ return self.buffer -fn to_toml(config: Dict[String, TomlValue]) raises -> String: +def to_toml(config: Dict[String, TomlValue]) raises -> String: """Convert a Dict[String, TomlValue] structure to TOML format string. This is the main public API for TOML serialisation. It takes a nested diff --git a/test_package.mojo b/test_package.mojo index 84c2d88..1c5611c 100644 --- a/test_package.mojo +++ b/test_package.mojo @@ -1,6 +1,6 @@ from toml import parse, to_toml -fn main() raises: +def main() raises: # Parse a simple TOML document let config = parse(""" [package] diff --git a/tests/dev/test_both.mojo b/tests/dev/test_both.mojo index e20bb8a..12c3ec3 100644 --- a/tests/dev/test_both.mojo +++ b/tests/dev/test_both.mojo @@ -1,6 +1,6 @@ from toml import parse -fn main() raises: +def main() raises: var d1 = parse("a = inf\nb = nan") print("Test 1 passed") diff --git a/tests/dev/test_dict_iteration.mojo b/tests/dev/test_dict_iteration.mojo index 8065e3b..46bfb86 100644 --- a/tests/dev/test_dict_iteration.mojo +++ b/tests/dev/test_dict_iteration.mojo @@ -2,7 +2,7 @@ from std.collections import Dict -fn main() raises: +def main() raises: var data = Dict[String, String]() data["name"] = "Alice" data["age"] = "30" diff --git a/tests/dev/test_exact.mojo b/tests/dev/test_exact.mojo index c78dc32..243e0a7 100644 --- a/tests/dev/test_exact.mojo +++ b/tests/dev/test_exact.mojo @@ -1,6 +1,6 @@ from toml import parse -fn main() raises: +def main() raises: # Test exactly what the test has var data = parse("infinity = inf\nnot_a_number = nan") print("Has infinity:", data.__contains__("infinity")) diff --git a/tests/dev/test_multi.mojo b/tests/dev/test_multi.mojo index 16e0220..350dd95 100644 --- a/tests/dev/test_multi.mojo +++ b/tests/dev/test_multi.mojo @@ -1,6 +1,6 @@ from toml import parse -fn main() raises: +def main() raises: var d = parse("infinity = inf\nnot_a_number = nan") print("Has infinity:", d.__contains__("infinity")) print("Has not_a_number:", d.__contains__("not_a_number")) diff --git a/tests/dev/test_nested_dict.mojo b/tests/dev/test_nested_dict.mojo index 37b2ba8..45c99ca 100644 --- a/tests/dev/test_nested_dict.mojo +++ b/tests/dev/test_nested_dict.mojo @@ -7,17 +7,17 @@ struct TomlValue(Movable, Copyable): var is_table: Bool var table: Dict[String, TomlValue] - fn __init__(out self, value: String): + def __init__(out self, value: String): self.data = value self.is_table = False self.table = Dict[String, TomlValue]() - fn __init__(out self, owned table: Dict[String, TomlValue]): + def __init__(out self, owned table: Dict[String, TomlValue]): self.data = "" self.is_table = True self.table = table^ - fn __copyinit__(out self, existing: Self): + def __copyinit__(out self, existing: Self): self.data = existing.data self.is_table = existing.is_table self.table = Dict[String, TomlValue]() @@ -25,22 +25,22 @@ struct TomlValue(Movable, Copyable): for entry in existing.table.items(): self.table[entry.key] = entry.value.copy() - fn __moveinit__(out self, owned existing: Self): + def __moveinit__(out self, owned existing: Self): self.data = existing.data^ self.is_table = existing.is_table self.table = existing.table^ - fn as_string(self) -> String: + def as_string(self) -> String: return self.data - fn as_table(self) -> Dict[String, TomlValue]: + def as_table(self) -> Dict[String, TomlValue]: var result = Dict[String, TomlValue]() for entry in self.table.items(): result[entry.key] = entry.value.copy() return result^ -fn main() raises: +def main() raises: print("Testing nested Dict structure building:") print() diff --git a/tests/dev/test_parser_nested.mojo b/tests/dev/test_parser_nested.mojo index c7647b4..f87dcb3 100644 --- a/tests/dev/test_parser_nested.mojo +++ b/tests/dev/test_parser_nested.mojo @@ -2,7 +2,7 @@ from toml import parse -fn main() raises: +def main() raises: print("Testing nested table parsing:") print() diff --git a/tests/test_array_of_tables.mojo b/tests/test_array_of_tables.mojo index b9f210a..f92a2fe 100644 --- a/tests/test_array_of_tables.mojo +++ b/tests/test_array_of_tables.mojo @@ -4,11 +4,11 @@ Tests the [[section]] array-of-tables feature which allows defining arrays of tables in TOML configuration files. """ -from testing import assert_equal, assert_true, TestSuite +from std.testing import assert_equal, assert_true, TestSuite from toml import parse -fn test_simple_array_of_tables() raises: +def test_simple_array_of_tables() raises: """Test basic array of tables syntax.""" var toml = """ [[products]] @@ -29,7 +29,7 @@ sku = 284758393 assert_equal(products[1].as_table()["sku"].as_int(), 284758393) -fn test_empty_array_of_tables() raises: +def test_empty_array_of_tables() raises: """Test array of tables with no keys.""" var toml = """ [[empty]] @@ -45,7 +45,7 @@ fn test_empty_array_of_tables() raises: assert_equal(len(empty[1].as_table()), 0) -fn test_single_array_element() raises: +def test_single_array_element() raises: """Test array of tables with single element.""" var toml = """ [[items]] @@ -58,7 +58,7 @@ value = 42 assert_equal(items[0].as_table()["value"].as_int(), 42) -fn test_nested_array_of_tables() raises: +def test_nested_array_of_tables() raises: """Test nested array of tables: [[fruit.variety]].""" var toml = """ [[fruit]] @@ -95,7 +95,7 @@ name = "banana" assert_equal(banana_varieties[0].as_table()["name"].as_string(), "plantain") -fn test_mixed_tables_and_arrays() raises: +def test_mixed_tables_and_arrays() raises: """Test document with both regular tables and array-of-tables.""" var toml = """ [database] @@ -129,7 +129,7 @@ ttl = 300 assert_equal(cache["ttl"].as_int(), 300) -fn test_dotted_keys_in_array_of_tables() raises: +def test_dotted_keys_in_array_of_tables() raises: """Test dotted keys within array-of-tables entries.""" var toml = """ [[configs]] @@ -145,7 +145,7 @@ server.port = 8080 assert_equal(server["port"].as_int(), 8080) -fn test_array_values_in_array_of_tables() raises: +def test_array_values_in_array_of_tables() raises: """Test arrays as values within array-of-tables.""" var toml = """ [[packages]] @@ -169,7 +169,7 @@ tags = ["cli"] assert_equal(bar_tags[0].as_string(), "cli") -fn test_inline_table_in_array_of_tables() raises: +def test_inline_table_in_array_of_tables() raises: """Test inline tables within array-of-tables.""" var toml = """ [[entries]] @@ -188,7 +188,7 @@ metadata = { author = "Bob", tags = ["bar"] } assert_equal(metadata1["author"].as_string(), "Alice") -fn test_multiple_array_of_tables_sections() raises: +def test_multiple_array_of_tables_sections() raises: """Test multiple independent array-of-tables in same document.""" var toml = """ [[users]] @@ -217,7 +217,7 @@ name = "users" # Error cases - these should raise errors -fn test_error_redefine_array_as_table() raises: +def test_error_redefine_array_as_table() raises: """Test error: cannot redefine array-of-tables as regular table.""" var toml = """ [[products]] @@ -234,7 +234,7 @@ type = "tools" pass -fn test_error_redefine_table_as_array() raises: +def test_error_redefine_table_as_array() raises: """Test error: cannot redefine regular table as array-of-tables.""" var toml = """ [database] @@ -251,7 +251,7 @@ port = 5432 pass -fn test_error_duplicate_keys_in_array_element() raises: +def test_error_duplicate_keys_in_array_element() raises: """Test error: duplicate keys within same array element.""" var toml = """ [[items]] diff --git a/tests/test_arrays.mojo b/tests/test_arrays.mojo index a30b2cc..34cf264 100644 --- a/tests/test_arrays.mojo +++ b/tests/test_arrays.mojo @@ -4,11 +4,11 @@ Tests TOML array parsing including homogeneous and heterogeneous arrays, nested arrays, multiline arrays, and arrays with trailing commas. """ -from testing import assert_equal, assert_true, assert_false, TestSuite +from std.testing import assert_equal, assert_true, assert_false, TestSuite from toml import parse -fn test_empty_array() raises: +def test_empty_array() raises: """Test parsing empty array.""" var data = parse("items = []") @@ -19,7 +19,7 @@ fn test_empty_array() raises: assert_equal(len(arr), 0) -fn test_integer_array() raises: +def test_integer_array() raises: """Test parsing array of integers.""" var data = parse("numbers = [1, 2, 3, 4, 5]") @@ -34,7 +34,7 @@ fn test_integer_array() raises: assert_equal(arr[4].as_int(), 5) -fn test_string_array() raises: +def test_string_array() raises: """Test parsing array of strings.""" var data = parse('colors = ["red", "green", "blue"]') @@ -47,7 +47,7 @@ fn test_string_array() raises: assert_equal(arr[2].as_string(), "blue") -fn test_float_array() raises: +def test_float_array() raises: """Test parsing array of floats.""" var data = parse("values = [1.0, 2.5, 3.14]") @@ -60,7 +60,7 @@ fn test_float_array() raises: assert_equal(arr[2].as_float(), 3.14) -fn test_boolean_array() raises: +def test_boolean_array() raises: """Test parsing array of booleans.""" var data = parse("flags = [true, false, true]") @@ -73,7 +73,7 @@ fn test_boolean_array() raises: assert_true(arr[2].as_bool()) -fn test_mixed_type_array() raises: +def test_mixed_type_array() raises: """Test parsing array with mixed types (valid in TOML).""" var data = parse('mixed = [1, "two", 3.0, true]') @@ -92,7 +92,7 @@ fn test_mixed_type_array() raises: assert_true(arr[3].as_bool()) -fn test_nested_array() raises: +def test_nested_array() raises: """Test parsing nested arrays.""" var data = parse("matrix = [[1, 2], [3, 4], [5, 6]]") @@ -119,7 +119,7 @@ fn test_nested_array() raises: assert_equal(row3[1].as_int(), 6) -fn test_array_with_trailing_comma() raises: +def test_array_with_trailing_comma() raises: """Test parsing array with trailing comma.""" var data = parse("items = [1, 2, 3,]") @@ -132,7 +132,7 @@ fn test_array_with_trailing_comma() raises: assert_equal(arr[2].as_int(), 3) -fn test_multiline_array() raises: +def test_multiline_array() raises: """Test parsing multiline array.""" var data = parse("""items = [ 1, @@ -149,7 +149,7 @@ fn test_multiline_array() raises: assert_equal(arr[2].as_int(), 3) -fn test_array_with_comments() raises: +def test_array_with_comments() raises: """Test parsing array with comments.""" var data = parse("""items = [ 1, # first item @@ -166,7 +166,7 @@ fn test_array_with_comments() raises: assert_equal(arr[2].as_int(), 3) -fn test_array_single_element() raises: +def test_array_single_element() raises: """Test parsing single-element array.""" var data = parse("singleton = [42]") @@ -177,7 +177,7 @@ fn test_array_single_element() raises: assert_equal(arr[0].as_int(), 42) -fn test_array_with_whitespace() raises: +def test_array_with_whitespace() raises: """Test parsing array with extra whitespace.""" var data = parse("spaced = [ 1 , 2 , 3 ]") @@ -190,7 +190,7 @@ fn test_array_with_whitespace() raises: assert_equal(arr[2].as_int(), 3) -fn test_deeply_nested_array() raises: +def test_deeply_nested_array() raises: """Test parsing deeply nested arrays.""" var data = parse("deep = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]") @@ -211,7 +211,7 @@ fn test_deeply_nested_array() raises: assert_equal(level3_2[1].as_int(), 4) -fn test_multiple_arrays() raises: +def test_multiple_arrays() raises: """Test parsing multiple arrays in one document.""" var data = parse(""" first = [1, 2, 3] diff --git a/tests/test_dotted_keys.mojo b/tests/test_dotted_keys.mojo index b43ff4a..9f269bc 100644 --- a/tests/test_dotted_keys.mojo +++ b/tests/test_dotted_keys.mojo @@ -3,11 +3,11 @@ Tests the dotted key syntax (a.b.c = value) which creates nested table structures. """ -from testing import assert_equal, assert_true, TestSuite, assert_raises +from std.testing import assert_equal, assert_true, TestSuite, assert_raises from toml import parse -fn test_simple_dotted_key() raises: +def test_simple_dotted_key() raises: """Test simple dotted key creates nested table.""" var data = parse(""" a.b = "value" @@ -18,7 +18,7 @@ a.b = "value" assert_equal(a_table["b"].as_string(), "value") -fn test_multiple_dotted_keys() raises: +def test_multiple_dotted_keys() raises: """Test multiple dotted keys in same namespace.""" var data = parse(""" a.b = "value1" @@ -30,7 +30,7 @@ a.c = "value2" assert_equal(a_table["c"].as_string(), "value2") -fn test_deeply_dotted_key() raises: +def test_deeply_dotted_key() raises: """Test deeply nested dotted key.""" var data = parse(""" a.b.c.d.e = 42 @@ -43,7 +43,7 @@ a.b.c.d.e = 42 assert_equal(d["e"].as_int(), 42) -fn test_dotted_key_with_table_header() raises: +def test_dotted_key_with_table_header() raises: """Test dotted key combined with table header.""" var data = parse(""" [section] @@ -58,7 +58,7 @@ c = "flat" assert_equal(a["b"].as_string(), "nested") -fn test_dotted_key_mixed_values() raises: +def test_dotted_key_mixed_values() raises: """Test dotted keys with different value types.""" var data = parse(""" server.host = "localhost" @@ -72,7 +72,7 @@ server.enabled = true assert_equal(server["enabled"].as_bool(), True) -fn test_dotted_key_with_inline_table() raises: +def test_dotted_key_with_inline_table() raises: """Test dotted key with inline table value.""" var data = parse(""" a.b = {c = "value"} @@ -83,7 +83,7 @@ a.b = {c = "value"} assert_equal(b["c"].as_string(), "value") -fn test_dotted_key_array() raises: +def test_dotted_key_array() raises: """Test dotted key with array value.""" var data = parse(""" a.b = [1, 2, 3] diff --git a/tests/test_fixtures.mojo b/tests/test_fixtures.mojo index 38c1c73..b8bb34b 100644 --- a/tests/test_fixtures.mojo +++ b/tests/test_fixtures.mojo @@ -5,10 +5,10 @@ across various domains: apps, builds, ML, APIs, and games. """ from toml import parse -from testing import assert_equal, assert_true, assert_false, TestSuite +from std.testing import assert_equal, assert_true, assert_false, TestSuite -fn read_fixture(filename: String) raises -> String: +def read_fixture(filename: String) raises -> String: """Read a fixture file from the fixtures directory.""" var path = "fixtures/" + filename @@ -16,7 +16,7 @@ fn read_fixture(filename: String) raises -> String: return f.read() -fn test_app_config() raises: +def test_app_config() raises: """Test parsing a typical application configuration file.""" var content = read_fixture("app_config.toml") var config = parse(content) @@ -51,7 +51,7 @@ fn test_app_config() raises: assert_equal(config["cache_size"].as_int(), 1024) -fn test_build_config() raises: +def test_build_config() raises: """Test parsing a build configuration file.""" var content = read_fixture("build_config.toml") var config = parse(content) @@ -79,7 +79,7 @@ fn test_build_config() raises: assert_equal(config["coverage_threshold"].as_float(), 80.0) -fn test_ml_config() raises: +def test_ml_config() raises: """Test parsing a machine learning model configuration file.""" var content = read_fixture("ml_config.toml") var config = parse(content) @@ -120,7 +120,7 @@ fn test_ml_config() raises: assert_equal(config["scale_method"].as_string(), "standard") -fn test_api_config() raises: +def test_api_config() raises: """Test parsing a REST API configuration file.""" var content = read_fixture("api_config.toml") var config = parse(content) @@ -160,7 +160,7 @@ fn test_api_config() raises: assert_equal(config["session_timeout"].as_float(), 3600.0) -fn test_game_settings() raises: +def test_game_settings() raises: """Test parsing a game engine settings file.""" var content = read_fixture("game_settings.toml") var config = parse(content) diff --git a/tests/test_inline.mojo b/tests/test_inline.mojo index 5d3fc83..3ee997b 100644 --- a/tests/test_inline.mojo +++ b/tests/test_inline.mojo @@ -4,11 +4,11 @@ Tests TOML inline table parsing including simple tables, nested tables, tables with various value types, and tables within arrays. """ -from testing import assert_equal, assert_true, assert_false, TestSuite +from std.testing import assert_equal, assert_true, assert_false, TestSuite from toml import parse -fn test_empty_inline_table() raises: +def test_empty_inline_table() raises: """Test parsing empty inline table.""" var data = parse("empty = {}") @@ -19,7 +19,7 @@ fn test_empty_inline_table() raises: assert_equal(len(table), 0) -fn test_simple_inline_table() raises: +def test_simple_inline_table() raises: """Test parsing simple inline table.""" var data = parse('point = {x = 1, y = 2}') @@ -33,7 +33,7 @@ fn test_simple_inline_table() raises: assert_equal(table["y"].as_int(), 2) -fn test_inline_table_strings() raises: +def test_inline_table_strings() raises: """Test inline table with string values.""" var data = parse('person = {name = "Alice", role = "Engineer"}') @@ -45,7 +45,7 @@ fn test_inline_table_strings() raises: assert_equal(table["role"].as_string(), "Engineer") -fn test_inline_table_mixed_types() raises: +def test_inline_table_mixed_types() raises: """Test inline table with mixed value types.""" var data = parse('config = {port = 8080, host = "localhost", debug = true, timeout = 30.5}') @@ -59,7 +59,7 @@ fn test_inline_table_mixed_types() raises: assert_equal(table["timeout"].as_float(), 30.5) -fn test_inline_table_with_array() raises: +def test_inline_table_with_array() raises: """Test inline table containing an array.""" var data = parse('data = {values = [1, 2, 3], name = "test"}') @@ -78,7 +78,7 @@ fn test_inline_table_with_array() raises: assert_equal(table["name"].as_string(), "test") -fn test_nested_inline_table() raises: +def test_nested_inline_table() raises: """Test inline table containing another inline table.""" var data = parse('server = {address = {host = "localhost", port = 8080}, name = "main"}') @@ -96,7 +96,7 @@ fn test_nested_inline_table() raises: assert_equal(address["port"].as_int(), 8080) -fn test_array_of_inline_tables() raises: +def test_array_of_inline_tables() raises: """Test array containing inline tables.""" var data = parse('users = [{name = "Alice", age = 30}, {name = "Bob", age = 25}]') @@ -118,7 +118,7 @@ fn test_array_of_inline_tables() raises: assert_equal(user2["age"].as_int(), 25) -fn test_inline_table_single_pair() raises: +def test_inline_table_single_pair() raises: """Test inline table with single key-value pair.""" var data = parse('singleton = {key = "value"}') @@ -129,7 +129,7 @@ fn test_inline_table_single_pair() raises: assert_equal(table["key"].as_string(), "value") -fn test_inline_table_with_spaces() raises: +def test_inline_table_with_spaces() raises: """Test inline table with extra spacing.""" var data = parse('spaced = { a = 1 , b = 2 }') @@ -141,7 +141,7 @@ fn test_inline_table_with_spaces() raises: assert_equal(table["b"].as_int(), 2) -fn test_multiple_inline_tables() raises: +def test_multiple_inline_tables() raises: """Test parsing multiple inline tables.""" var data = parse(""" point1 = {x = 1, y = 2} @@ -166,7 +166,7 @@ point3 = {x = 5, y = 6} assert_equal(p3["y"].as_int(), 6) -fn test_inline_table_with_quoted_keys() raises: +def test_inline_table_with_quoted_keys() raises: """Test inline table with quoted keys.""" var data = parse('data = {"127.0.0.1" = "localhost", "special-key" = "value"}') @@ -178,7 +178,7 @@ fn test_inline_table_with_quoted_keys() raises: assert_equal(table["special-key"].as_string(), "value") -fn test_inline_table_booleans() raises: +def test_inline_table_booleans() raises: """Test inline table with boolean values.""" var data = parse('flags = {enabled = true, debug = false, verbose = true}') @@ -191,7 +191,7 @@ fn test_inline_table_booleans() raises: assert_true(table["verbose"].as_bool()) -fn test_deeply_nested_inline_table() raises: +def test_deeply_nested_inline_table() raises: """Test deeply nested inline tables.""" var data = parse('root = {a = {b = {c = {value = 42}}}}') diff --git a/tests/test_lexer.mojo b/tests/test_lexer.mojo index f5e567b..f4a7484 100644 --- a/tests/test_lexer.mojo +++ b/tests/test_lexer.mojo @@ -4,11 +4,11 @@ Comprehensive tests for the tokenisation of TOML input into token streams. Covers all token types, syntax elements, and lexer functionality. """ -from testing import assert_equal, assert_true, TestSuite +from std.testing import assert_equal, assert_true, TestSuite from toml.lexer import Lexer, TokenKind -fn test_empty_input() raises: +def test_empty_input() raises: """Test lexing empty input.""" var lexer = Lexer("") var tokens = lexer.tokenize() @@ -17,7 +17,7 @@ fn test_empty_input() raises: assert_true(tokens[0].kind == TokenKind.EOF()) -fn test_simple_key_value() raises: +def test_simple_key_value() raises: """Test basic key = value tokenisation.""" var lexer = Lexer("name = \"mojo-toml\"") var tokens = lexer.tokenize() @@ -32,7 +32,7 @@ fn test_simple_key_value() raises: assert_true(tokens[3].kind == TokenKind.EOF()) -fn test_integers() raises: +def test_integers() raises: """Test integer tokenisation.""" var test_cases = List[String]() test_cases.append("42") @@ -47,7 +47,7 @@ fn test_integers() raises: assert_true(tokens[0].kind == TokenKind.INTEGER(), msg="Expected INTEGER token") -fn test_floats() raises: +def test_floats() raises: """Test float tokenisation.""" var test_cases = List[String]() test_cases.append("3.14") @@ -62,7 +62,7 @@ fn test_floats() raises: assert_true(tokens[0].kind == TokenKind.FLOAT(), msg="Expected FLOAT token") -fn test_special_floats() raises: +def test_special_floats() raises: """Test special float values (inf, nan).""" var lexer1 = Lexer("inf") var tokens1 = lexer1.tokenize() @@ -80,7 +80,7 @@ fn test_special_floats() raises: assert_equal(tokens3[0].value, "nan") -fn test_booleans() raises: +def test_booleans() raises: """Test boolean tokenisation.""" var lexer1 = Lexer("true") var tokens1 = lexer1.tokenize() @@ -93,7 +93,7 @@ fn test_booleans() raises: assert_equal(tokens2[0].value, "false") -fn test_basic_string() raises: +def test_basic_string() raises: """Test basic string with escape sequences.""" var lexer = Lexer('"hello world"') var tokens = lexer.tokenize() @@ -101,7 +101,7 @@ fn test_basic_string() raises: assert_equal(tokens[0].value, "hello world") -fn test_literal_string() raises: +def test_literal_string() raises: """Test literal string (no escape processing).""" var lexer = Lexer("'C:\\\\Users\\\\name'") var tokens = lexer.tokenize() @@ -110,7 +110,7 @@ fn test_literal_string() raises: assert_equal(tokens[0].value, "C:\\\\Users\\\\name") -fn test_string_escapes() raises: +def test_string_escapes() raises: """Test escape sequences in basic strings.""" var lexer = Lexer('"line1\\nline2\\ttab"') var tokens = lexer.tokenize() @@ -118,7 +118,7 @@ fn test_string_escapes() raises: assert_equal(tokens[0].value, "line1\nline2\ttab") -fn test_multiline_basic_string() raises: +def test_multiline_basic_string() raises: """Test multiline basic string with triple quotes.""" var input = '"""line 1\nline 2\nline 3"""' var lexer = Lexer(input) @@ -127,7 +127,7 @@ fn test_multiline_basic_string() raises: assert_equal(tokens[0].value, "line 1\nline 2\nline 3") -fn test_comments() raises: +def test_comments() raises: """Test comment tokenisation.""" var lexer = Lexer("# This is a comment") var tokens = lexer.tokenize() @@ -135,7 +135,7 @@ fn test_comments() raises: assert_equal(tokens[0].value, " This is a comment") -fn test_inline_comment() raises: +def test_inline_comment() raises: """Test inline comment after value.""" var lexer = Lexer('name = "value" # comment') var tokens = lexer.tokenize() @@ -149,7 +149,7 @@ fn test_inline_comment() raises: assert_equal(tokens[3].value, " comment") -fn test_punctuation() raises: +def test_punctuation() raises: """Test all punctuation tokens.""" var lexer = Lexer("= . , [ ] { }") var tokens = lexer.tokenize() @@ -164,7 +164,7 @@ fn test_punctuation() raises: assert_true(tokens[7].kind == TokenKind.EOF()) -fn test_array_syntax() raises: +def test_array_syntax() raises: """Test array tokenisation.""" var lexer = Lexer("[1, 2, 3]") var tokens = lexer.tokenize() @@ -179,7 +179,7 @@ fn test_array_syntax() raises: assert_true(tokens[6].kind == TokenKind.RIGHT_BRACKET()) -fn test_inline_table_syntax() raises: +def test_inline_table_syntax() raises: """Test inline table tokenisation.""" var lexer = Lexer('{name = "value"}') var tokens = lexer.tokenize() @@ -192,7 +192,7 @@ fn test_inline_table_syntax() raises: assert_true(tokens[4].kind == TokenKind.RIGHT_BRACE()) -fn test_table_header() raises: +def test_table_header() raises: """Test table header tokenisation.""" var lexer = Lexer("[package]") var tokens = lexer.tokenize() @@ -204,7 +204,7 @@ fn test_table_header() raises: assert_true(tokens[2].kind == TokenKind.RIGHT_BRACKET()) -fn test_dotted_key() raises: +def test_dotted_key() raises: """Test dotted key tokenisation.""" var lexer = Lexer("a.b.c = 1") var tokens = lexer.tokenize() @@ -222,7 +222,7 @@ fn test_dotted_key() raises: assert_true(tokens[6].kind == TokenKind.INTEGER()) -fn test_newlines() raises: +def test_newlines() raises: """Test newline handling.""" var lexer = Lexer("key1 = 1\nkey2 = 2") var tokens = lexer.tokenize() @@ -235,7 +235,7 @@ fn test_newlines() raises: assert_true(tokens[4].kind == TokenKind.KEY()) -fn test_whitespace_handling() raises: +def test_whitespace_handling() raises: """Test whitespace is properly skipped.""" var lexer = Lexer(" key = \"value\" ") var tokens = lexer.tokenize() @@ -247,7 +247,7 @@ fn test_whitespace_handling() raises: assert_true(tokens[3].kind == TokenKind.EOF()) -fn test_position_tracking() raises: +def test_position_tracking() raises: """Test that tokens track their position correctly.""" var lexer = Lexer("key = 1\nname = \"value\"") var tokens = lexer.tokenize() @@ -260,7 +260,7 @@ fn test_position_tracking() raises: assert_equal(tokens[4].pos.line, 2) -fn test_unquoted_keys() raises: +def test_unquoted_keys() raises: """Test various unquoted key formats.""" var test_cases = List[String]() test_cases.append("simple") @@ -276,7 +276,7 @@ fn test_unquoted_keys() raises: assert_equal(tokens[0].value, test_cases[i]) -fn test_quoted_keys() raises: +def test_quoted_keys() raises: """Test quoted keys (allows any characters).""" var lexer = Lexer('"127.0.0.1" = "localhost"') var tokens = lexer.tokenize() @@ -287,7 +287,7 @@ fn test_quoted_keys() raises: assert_true(tokens[2].kind == TokenKind.STRING()) -fn test_empty_string() raises: +def test_empty_string() raises: """Test empty string parsing.""" var lexer = Lexer('name = ""') var tokens = lexer.tokenize() @@ -296,7 +296,7 @@ fn test_empty_string() raises: assert_equal(tokens[2].value, "") -fn test_number_with_underscores() raises: +def test_number_with_underscores() raises: """Test numbers with underscore separators.""" var lexer = Lexer("big = 1_000_000") var tokens = lexer.tokenize() @@ -306,7 +306,7 @@ fn test_number_with_underscores() raises: assert_equal(tokens[2].value, "1000000") -fn test_complex_toml_line() raises: +def test_complex_toml_line() raises: """Test a realistic TOML line.""" var lexer = Lexer('[package]\nname = "mojo-toml" # First TOML parser\nversion = "0.1.0"') var tokens = lexer.tokenize() diff --git a/tests/test_number_bases.mojo b/tests/test_number_bases.mojo index 43356b5..f1104d0 100644 --- a/tests/test_number_bases.mojo +++ b/tests/test_number_bases.mojo @@ -6,11 +6,11 @@ Tests TOML 1.0 alternative integer formats: - Binary: 0b1101, 0b1111_0000 """ -from testing import assert_equal, TestSuite +from std.testing import assert_equal, TestSuite from toml import parse -fn test_hex_lowercase() raises: +def test_hex_lowercase() raises: """Test lowercase hexadecimal integers.""" var toml = "value = 0xdead" var data = parse(toml) @@ -19,7 +19,7 @@ fn test_hex_lowercase() raises: assert_equal(value, 57005) -fn test_hex_uppercase() raises: +def test_hex_uppercase() raises: """Test uppercase hexadecimal integers.""" var toml = "value = 0xDEAD" var data = parse(toml) @@ -27,7 +27,7 @@ fn test_hex_uppercase() raises: assert_equal(value, 57005) -fn test_hex_mixed_case() raises: +def test_hex_mixed_case() raises: """Test mixed case hexadecimal integers.""" var toml = "value = 0xDeAd" var data = parse(toml) @@ -35,7 +35,7 @@ fn test_hex_mixed_case() raises: assert_equal(value, 57005) -fn test_hex_with_underscores() raises: +def test_hex_with_underscores() raises: """Test hexadecimal with underscores for readability.""" var toml = "value = 0xdead_beef" var data = parse(toml) @@ -44,7 +44,7 @@ fn test_hex_with_underscores() raises: assert_equal(value, 3735928559) -fn test_hex_simple() raises: +def test_hex_simple() raises: """Test simple hexadecimal values.""" var toml = "a = 0xFF\nb = 0x00\nc = 0x10" var data = parse(toml) @@ -53,7 +53,7 @@ fn test_hex_simple() raises: assert_equal(data["c"].as_int(), 16) -fn test_octal_basic() raises: +def test_octal_basic() raises: """Test basic octal integers.""" var toml = "value = 0o755" var data = parse(toml) @@ -62,7 +62,7 @@ fn test_octal_basic() raises: assert_equal(value, 493) -fn test_octal_with_leading_zero() raises: +def test_octal_with_leading_zero() raises: """Test octal with leading zero.""" var toml = "value = 0o0755" var data = parse(toml) @@ -70,7 +70,7 @@ fn test_octal_with_leading_zero() raises: assert_equal(value, 493) -fn test_octal_with_underscores() raises: +def test_octal_with_underscores() raises: """Test octal with underscores.""" var toml = "value = 0o7_5_5" var data = parse(toml) @@ -78,7 +78,7 @@ fn test_octal_with_underscores() raises: assert_equal(value, 493) -fn test_octal_zero() raises: +def test_octal_zero() raises: """Test octal zero.""" var toml = "value = 0o0" var data = parse(toml) @@ -86,7 +86,7 @@ fn test_octal_zero() raises: assert_equal(value, 0) -fn test_binary_basic() raises: +def test_binary_basic() raises: """Test basic binary integers.""" var toml = "value = 0b1101" var data = parse(toml) @@ -95,7 +95,7 @@ fn test_binary_basic() raises: assert_equal(value, 13) -fn test_binary_with_underscores() raises: +def test_binary_with_underscores() raises: """Test binary with underscores.""" var toml = "value = 0b1111_0000" var data = parse(toml) @@ -104,7 +104,7 @@ fn test_binary_with_underscores() raises: assert_equal(value, 240) -fn test_binary_byte() raises: +def test_binary_byte() raises: """Test binary byte values.""" var toml = "a = 0b11111111\nb = 0b00000000\nc = 0b10101010" var data = parse(toml) @@ -113,7 +113,7 @@ fn test_binary_byte() raises: assert_equal(data["c"].as_int(), 170) -fn test_mixed_bases() raises: +def test_mixed_bases() raises: """Test document with mixed number bases.""" var toml = """ decimal = 42 @@ -128,7 +128,7 @@ fn test_mixed_bases() raises: assert_equal(data["binary"].as_int(), 10) -fn test_bases_in_array() raises: +def test_bases_in_array() raises: """Test alternative bases in arrays.""" var toml = "values = [0xFF, 0o77, 0b11, 42]" var data = parse(toml) diff --git a/tests/test_parser.mojo b/tests/test_parser.mojo index 759d010..6ee25dd 100644 --- a/tests/test_parser.mojo +++ b/tests/test_parser.mojo @@ -3,11 +3,11 @@ Tests the conversion of tokens into structured data. """ -from testing import assert_equal, assert_true, TestSuite +from std.testing import assert_equal, assert_true, TestSuite from toml import parse, TomlValue -fn test_parse_string_value() raises: +def test_parse_string_value() raises: """Test parsing simple string value.""" var data = parse('name = "mojo-toml"') @@ -16,7 +16,7 @@ fn test_parse_string_value() raises: assert_equal(data["name"].as_string(), "mojo-toml") -fn test_parse_integer_value() raises: +def test_parse_integer_value() raises: """Test parsing integer value.""" var data = parse("port = 8080") @@ -25,7 +25,7 @@ fn test_parse_integer_value() raises: assert_equal(data["port"].as_int(), 8080) -fn test_parse_float_value() raises: +def test_parse_float_value() raises: """Test parsing float value.""" var data = parse("pi = 3.14159") @@ -36,7 +36,7 @@ fn test_parse_float_value() raises: assert_true(diff < 0.00001 and diff > -0.00001) -fn test_parse_boolean_values() raises: +def test_parse_boolean_values() raises: """Test parsing boolean values.""" var data = parse("enabled = true\ndisabled = false") @@ -49,7 +49,7 @@ fn test_parse_boolean_values() raises: assert_true(not data["disabled"].as_bool()) -fn test_parse_multiple_keys() raises: +def test_parse_multiple_keys() raises: """Test parsing multiple key-value pairs.""" var data = parse('name = "test"\nversion = "0.1.0"\nport = 8080') @@ -62,7 +62,7 @@ fn test_parse_multiple_keys() raises: assert_equal(data["port"].as_int(), 8080) -fn test_parse_with_comments() raises: +def test_parse_with_comments() raises: """Test parsing with comments.""" var data = parse('# This is a comment\nname = "value" # inline comment') @@ -70,7 +70,7 @@ fn test_parse_with_comments() raises: assert_equal(data["name"].as_string(), "value") -fn test_parse_empty_string() raises: +def test_parse_empty_string() raises: """Test parsing empty string value.""" var data = parse('empty = ""') @@ -78,7 +78,7 @@ fn test_parse_empty_string() raises: assert_equal(data["empty"].as_string(), "") -fn test_parse_negative_numbers() raises: +def test_parse_negative_numbers() raises: """Test parsing negative numbers.""" var data = parse("negative_int = -42\nnegative_float = -3.14") @@ -90,7 +90,7 @@ fn test_parse_negative_numbers() raises: assert_true(val < -3.13 and val > -3.15) -fn test_parse_special_floats() raises: +def test_parse_special_floats() raises: """Test parsing special float values (inf, nan).""" var data = parse("infinity = inf\nnot_a_number = nan") @@ -105,7 +105,7 @@ fn test_parse_special_floats() raises: # nan != nan (standard floating point behavior) -fn test_parse_quoted_keys() raises: +def test_parse_quoted_keys() raises: """Test parsing with quoted keys.""" var data = parse('"127.0.0.1" = "localhost"') diff --git a/tests/test_parser_reset.mojo b/tests/test_parser_reset.mojo index 5d574dc..2dcbf6a 100644 --- a/tests/test_parser_reset.mojo +++ b/tests/test_parser_reset.mojo @@ -3,12 +3,12 @@ Verifies that Parser.reset() allows reusing the same parser instance. """ -from testing import assert_equal, assert_true, TestSuite +from std.testing import assert_equal, assert_true, TestSuite from toml.lexer import Lexer from toml.parser import Parser -fn test_parser_reset_simple() raises: +def test_parser_reset_simple() raises: """Test that parser can be reset and reused.""" # Parse first document var lexer1 = Lexer("name = \"first\"") @@ -27,7 +27,7 @@ fn test_parser_reset_simple() raises: assert_equal(data2["name"].as_string(), "second") -fn test_parser_reset_complex() raises: +def test_parser_reset_complex() raises: """Test parser reset with complex TOML structures.""" # First document with table var lexer1 = Lexer(""" @@ -56,7 +56,7 @@ port = 8080 assert_equal(section2["port"].as_int(), 8080) -fn test_parser_reset_multiple_times() raises: +def test_parser_reset_multiple_times() raises: """Test resetting parser multiple times.""" # Create initial parser var lexer0 = Lexer("count = 0") diff --git a/tests/test_real_world.mojo b/tests/test_real_world.mojo index 0c5377c..2d72fcc 100644 --- a/tests/test_real_world.mojo +++ b/tests/test_real_world.mojo @@ -4,12 +4,12 @@ Tests parsing actual TOML files like pixi.toml to validate against real-world us This is "dogfooding" - using our own project's config files to test the parser. """ -from testing import assert_equal, assert_true, TestSuite +from std.testing import assert_equal, assert_true, TestSuite from toml import parse from std.pathlib import Path -fn test_parse_pixi_toml() raises: +def test_parse_pixi_toml() raises: """Test parsing our own pixi.toml file. This validates that the parser can handle a real-world TOML file @@ -33,7 +33,7 @@ fn test_parse_pixi_toml() raises: print("Number of top-level keys:", len(data)) -fn test_parse_simple_toml_file() raises: +def test_parse_simple_toml_file() raises: """Test parsing a simple TOML file we create.""" # Create a simple test TOML file var simple_toml = """ @@ -73,7 +73,7 @@ timeout = 30.0 assert_true(timeout_val > 29.9 and timeout_val < 30.1) -fn test_parse_config_with_comments() raises: +def test_parse_config_with_comments() raises: """Test parsing TOML with extensive comments.""" var config = """ # Application Configuration @@ -118,7 +118,7 @@ timeout_seconds = 30.5 assert_true(timeout > 30.4 and timeout < 30.6) -fn test_parse_multiline_strings() raises: +def test_parse_multiline_strings() raises: """Test parsing TOML with multiline string values.""" var toml_with_multiline = ''' description = """ @@ -141,7 +141,7 @@ single_line = "This is just one line" assert_equal(data["single_line"].as_string(), "This is just one line") -fn test_parse_numbers_variations() raises: +def test_parse_numbers_variations() raises: """Test various number formats supported by TOML.""" var numbers_toml = """ # Integer variations diff --git a/tests/test_tables.mojo b/tests/test_tables.mojo index ff79e4b..7097574 100644 --- a/tests/test_tables.mojo +++ b/tests/test_tables.mojo @@ -3,11 +3,11 @@ Tests TOML table header parsing [section] and nested table structures. """ -from testing import assert_equal, assert_true, TestSuite +from std.testing import assert_equal, assert_true, TestSuite from toml import parse -fn test_simple_table() raises: +def test_simple_table() raises: """Test parsing simple table header.""" var data = parse(""" [database] @@ -23,7 +23,7 @@ port = 5432 assert_equal(db["port"].as_int(), 5432) -fn test_multiple_tables() raises: +def test_multiple_tables() raises: """Test parsing multiple table headers.""" var data = parse(""" [server] @@ -47,7 +47,7 @@ port = 5432 assert_equal(db["port"].as_int(), 5432) -fn test_nested_table() raises: +def test_nested_table() raises: """Test parsing nested table with dotted header.""" var data = parse(""" [database.primary] @@ -65,7 +65,7 @@ port = 5432 assert_equal(primary["port"].as_int(), 5432) -fn test_root_and_table() raises: +def test_root_and_table() raises: """Test mixing root-level keys with table headers.""" var data = parse(""" title = "MyApp" @@ -83,7 +83,7 @@ port = 8080 assert_equal(server["port"].as_int(), 8080) -fn test_deeply_nested_table() raises: +def test_deeply_nested_table() raises: """Test deeply nested table structure.""" var data = parse(""" [a.b.c.d] @@ -98,7 +98,7 @@ value = 42 assert_equal(d["value"].as_int(), 42) -fn test_table_with_arrays() raises: +def test_table_with_arrays() raises: """Test table containing arrays.""" var data = parse(""" [config] @@ -117,7 +117,7 @@ hosts = ["localhost", "127.0.0.1"] assert_equal(hosts[0].as_string(), "localhost") -fn test_table_with_inline_table() raises: +def test_table_with_inline_table() raises: """Test table containing inline table.""" var data = parse(""" [server] @@ -135,7 +135,7 @@ timeout = 30 assert_equal(server["timeout"].as_int(), 30) -fn test_multiple_nested_tables() raises: +def test_multiple_nested_tables() raises: """Test multiple nested table sections.""" var data = parse(""" [database.primary] diff --git a/tests/test_toml11_escapes.mojo b/tests/test_toml11_escapes.mojo index 013857c..fb8ba5a 100644 --- a/tests/test_toml11_escapes.mojo +++ b/tests/test_toml11_escapes.mojo @@ -5,11 +5,11 @@ Tests the TOML 1.1 additions: - backslash-xHH for codepoints 0-255 """ -from testing import assert_equal, TestSuite +from std.testing import assert_equal, TestSuite from toml import parse, to_toml -fn test_escape_character() raises: +def test_escape_character() raises: """Test backslash-e escape for ESC character (TOML 1.1).""" # Double-escape for Mojo compiler, will be single backslash in string var toml = '''csi = "\\e["''' @@ -25,14 +25,14 @@ fn test_escape_character() raises: assert_equal(csi_chars[1], "[") -fn test_xhh_escape_letter_a() raises: +def test_xhh_escape_letter_a() raises: """Test backslash-xHH for regular ASCII characters.""" var toml = '''letter = "\\x61"''' var data = parse(toml) assert_equal(data["letter"].as_string(), "a") # 0x61 = 'a' -fn test_xhh_escape_null_byte() raises: +def test_xhh_escape_null_byte() raises: """Test backslash-x00 escape for null byte.""" var toml = '''str = "null:\\x00end"''' var data = parse(toml) @@ -43,7 +43,7 @@ fn test_xhh_escape_null_byte() raises: assert_equal(ord(s_chars[5]), 0) # Null byte at position 5 -fn test_xhh_invalid_single_digit() raises: +def test_xhh_invalid_single_digit() raises: """Test that backslash-xH (single digit) raises an error.""" var toml = '''bad = "test\\x1"''' try: @@ -53,7 +53,7 @@ fn test_xhh_invalid_single_digit() raises: pass # Expected -fn test_xhh_invalid_non_hex() raises: +def test_xhh_invalid_non_hex() raises: """Test that backslash-xGG (non-hex) raises an error.""" var toml = '''bad = "test\\xGG"''' try: diff --git a/tests/test_validation.mojo b/tests/test_validation.mojo index 3a77f3d..3ea43fd 100644 --- a/tests/test_validation.mojo +++ b/tests/test_validation.mojo @@ -3,11 +3,11 @@ Tests that the parser correctly validates TOML and raises appropriate errors. """ -from testing import assert_equal, assert_true, TestSuite, assert_raises +from std.testing import assert_equal, assert_true, TestSuite, assert_raises from toml import parse -fn test_duplicate_key_error() raises: +def test_duplicate_key_error() raises: """Test that duplicate keys at root level raise an error.""" with assert_raises(contains="Duplicate key"): _ = parse(""" @@ -16,7 +16,7 @@ name = "second" """) -fn test_duplicate_key_in_table() raises: +def test_duplicate_key_in_table() raises: """Test that duplicate keys in table sections raise an error.""" with assert_raises(contains="Duplicate key"): _ = parse(""" @@ -26,7 +26,7 @@ key = "second" """) -fn test_duplicate_nested_key() raises: +def test_duplicate_nested_key() raises: """Test that duplicate nested keys raise an error.""" with assert_raises(contains="Duplicate key"): _ = parse(""" @@ -35,7 +35,7 @@ a.b.c = 2 """) -fn test_duplicate_key_different_tables() raises: +def test_duplicate_key_different_tables() raises: """Test that same key in different tables is allowed.""" # This should NOT raise an error var data = parse(""" @@ -52,7 +52,7 @@ key = "value2" assert_equal(section2["key"].as_string(), "value2") -fn test_redefining_table_as_value() raises: +def test_redefining_table_as_value() raises: """Test that redefining a table as a value raises an error.""" with assert_raises(contains="not a table"): _ = parse(""" @@ -64,7 +64,7 @@ port = 5432 """) -fn test_trailing_comma_in_inline_table() raises: +def test_trailing_comma_in_inline_table() raises: """Test that trailing comma in inline table raises error.""" with assert_raises(contains="Trailing comma"): _ = parse(""" diff --git a/tests/test_writer_basic.mojo b/tests/test_writer_basic.mojo index 48dc9c7..4502b14 100644 --- a/tests/test_writer_basic.mojo +++ b/tests/test_writer_basic.mojo @@ -3,12 +3,12 @@ Tests the serialisation of primitive types, strings, arrays, and simple structures. """ -from testing import assert_equal, assert_true, TestSuite +from std.testing import assert_equal, assert_true, TestSuite from toml import TomlValue, to_toml from std.collections import Dict, List -fn test_write_string() raises: +def test_write_string() raises: """Test writing a simple string value.""" var config = Dict[String, TomlValue]() config["name"] = TomlValue("mojo-toml") @@ -17,7 +17,7 @@ fn test_write_string() raises: assert_equal(output, "name = \"mojo-toml\"\n") -fn test_write_string_with_escapes() raises: +def test_write_string_with_escapes() raises: """Test writing strings with special characters that need escaping.""" var config = Dict[String, TomlValue]() config["message"] = TomlValue("Hello\nWorld") @@ -26,7 +26,7 @@ fn test_write_string_with_escapes() raises: assert_equal(output, "message = \"Hello\\nWorld\"\n") -fn test_write_string_with_quotes() raises: +def test_write_string_with_quotes() raises: """Test writing strings containing quotes.""" var config = Dict[String, TomlValue]() config["quote"] = TomlValue("He said \"hello\"") @@ -35,7 +35,7 @@ fn test_write_string_with_quotes() raises: assert_equal(output, "quote = \"He said \\\"hello\\\"\"\n") -fn test_write_string_with_backslash() raises: +def test_write_string_with_backslash() raises: """Test writing strings containing backslashes.""" var config = Dict[String, TomlValue]() config["path"] = TomlValue("C:\\Users\\test") @@ -44,7 +44,7 @@ fn test_write_string_with_backslash() raises: assert_equal(output, "path = \"C:\\\\Users\\\\test\"\n") -fn test_write_integer() raises: +def test_write_integer() raises: """Test writing integer values.""" var config = Dict[String, TomlValue]() config["port"] = TomlValue(8080) @@ -53,7 +53,7 @@ fn test_write_integer() raises: assert_equal(output, "port = 8080\n") -fn test_write_negative_integer() raises: +def test_write_negative_integer() raises: """Test writing negative integer values.""" var config = Dict[String, TomlValue]() config["temp"] = TomlValue(-42) @@ -62,7 +62,7 @@ fn test_write_negative_integer() raises: assert_equal(output, "temp = -42\n") -fn test_write_float() raises: +def test_write_float() raises: """Test writing float values.""" var config = Dict[String, TomlValue]() config["pi"] = TomlValue(3.14159) @@ -71,7 +71,7 @@ fn test_write_float() raises: assert_true(output.startswith("pi = 3.14")) -fn test_write_float_inf() raises: +def test_write_float_inf() raises: """Test writing positive infinity.""" var config = Dict[String, TomlValue]() var pos_inf = Float64(1.0) / Float64(0.0) @@ -81,7 +81,7 @@ fn test_write_float_inf() raises: assert_equal(output, "infinity = inf\n") -fn test_write_float_neg_inf() raises: +def test_write_float_neg_inf() raises: """Test writing negative infinity.""" var config = Dict[String, TomlValue]() var neg_inf = Float64(-1.0) / Float64(0.0) @@ -91,7 +91,7 @@ fn test_write_float_neg_inf() raises: assert_equal(output, "neg_infinity = -inf\n") -fn test_write_float_nan() raises: +def test_write_float_nan() raises: """Test writing NaN.""" var config = Dict[String, TomlValue]() var nan = Float64(0.0) / Float64(0.0) @@ -101,7 +101,7 @@ fn test_write_float_nan() raises: assert_equal(output, "not_a_number = nan\n") -fn test_write_boolean_true() raises: +def test_write_boolean_true() raises: """Test writing boolean true value.""" var config = Dict[String, TomlValue]() config["enabled"] = TomlValue(True) @@ -110,7 +110,7 @@ fn test_write_boolean_true() raises: assert_equal(output, "enabled = true\n") -fn test_write_boolean_false() raises: +def test_write_boolean_false() raises: """Test writing boolean false value.""" var config = Dict[String, TomlValue]() config["debug"] = TomlValue(False) @@ -119,7 +119,7 @@ fn test_write_boolean_false() raises: assert_equal(output, "debug = false\n") -fn test_write_empty_array() raises: +def test_write_empty_array() raises: """Test writing an empty array.""" var config = Dict[String, TomlValue]() var arr = List[TomlValue]() @@ -129,7 +129,7 @@ fn test_write_empty_array() raises: assert_equal(output, "items = []\n") -fn test_write_integer_array() raises: +def test_write_integer_array() raises: """Test writing an array of integers.""" var config = Dict[String, TomlValue]() var arr = List[TomlValue]() @@ -142,7 +142,7 @@ fn test_write_integer_array() raises: assert_equal(output, "numbers = [1, 2, 3]\n") -fn test_write_string_array() raises: +def test_write_string_array() raises: """Test writing an array of strings.""" var config = Dict[String, TomlValue]() var arr = List[TomlValue]() @@ -155,7 +155,7 @@ fn test_write_string_array() raises: assert_equal(output, "colors = [\"red\", \"green\", \"blue\"]\n") -fn test_write_mixed_array() raises: +def test_write_mixed_array() raises: """Test writing an array with mixed types.""" var config = Dict[String, TomlValue]() var arr = List[TomlValue]() @@ -169,7 +169,7 @@ fn test_write_mixed_array() raises: assert_true(output.startswith("mixed = [1, \"two\", 3")) -fn test_write_nested_array() raises: +def test_write_nested_array() raises: """Test writing nested arrays.""" var config = Dict[String, TomlValue]() @@ -191,7 +191,7 @@ fn test_write_nested_array() raises: assert_equal(output, "matrix = [[1, 2], [3, 4]]\n") -fn test_write_multiple_keys() raises: +def test_write_multiple_keys() raises: """Test writing multiple key-value pairs.""" var config = Dict[String, TomlValue]() config["name"] = TomlValue("test") @@ -206,7 +206,7 @@ fn test_write_multiple_keys() raises: assert_true(output.find("enabled = true") != -1) -fn test_write_single_key_table() raises: +def test_write_single_key_table() raises: """Test writing a single-key table (written inline).""" var config = Dict[String, TomlValue]() @@ -220,7 +220,7 @@ fn test_write_single_key_table() raises: assert_true(output.find("data = { value = 42 }") != -1 or output.find("[data]") != -1) -fn test_write_empty_string() raises: +def test_write_empty_string() raises: """Test writing an empty string value.""" var config = Dict[String, TomlValue]() config["empty"] = TomlValue("") diff --git a/tests/test_writer_roundtrip.mojo b/tests/test_writer_roundtrip.mojo index 0a8bbe4..a5f92cf 100644 --- a/tests/test_writer_roundtrip.mojo +++ b/tests/test_writer_roundtrip.mojo @@ -3,12 +3,12 @@ Tests that parse → write → parse produces semantically equivalent results. """ -from testing import assert_equal, assert_true, TestSuite +from std.testing import assert_equal, assert_true, TestSuite from toml import TomlValue, parse, to_toml from std.collections import Dict, List -fn compare_toml_values(left: TomlValue, right: TomlValue) raises -> Bool: +def compare_toml_values(left: TomlValue, right: TomlValue) raises -> Bool: """Compare two TomlValue instances for semantic equality. Returns True if values are semantically equal (same type and value). @@ -54,7 +54,7 @@ fn compare_toml_values(left: TomlValue, right: TomlValue) raises -> Bool: return False -fn compare_toml_dicts(left: Dict[String, TomlValue], right: Dict[String, TomlValue]) raises -> Bool: +def compare_toml_dicts(left: Dict[String, TomlValue], right: Dict[String, TomlValue]) raises -> Bool: """Compare two TOML dictionaries for semantic equality.""" if len(left) != len(right): return False @@ -68,7 +68,7 @@ fn compare_toml_dicts(left: Dict[String, TomlValue], right: Dict[String, TomlVal return True -fn test_roundtrip_simple() raises: +def test_roundtrip_simple() raises: """Test round-trip with simple key-value pairs.""" var original_toml = """ name = "test-app" @@ -84,7 +84,7 @@ debug = false assert_true(compare_toml_dicts(parsed1, parsed2)) -fn test_roundtrip_with_arrays() raises: +def test_roundtrip_with_arrays() raises: """Test round-trip with arrays.""" var original_toml = """ numbers = [1, 2, 3, 4, 5] @@ -99,7 +99,7 @@ mixed = [1, "two", 3.0, true] assert_true(compare_toml_dicts(parsed1, parsed2)) -fn test_roundtrip_with_table() raises: +def test_roundtrip_with_table() raises: """Test round-trip with a simple table.""" var original_toml = """ title = "My App" @@ -118,7 +118,7 @@ enabled = true assert_true(compare_toml_dicts(parsed1, parsed2)) -fn test_roundtrip_nested_tables() raises: +def test_roundtrip_nested_tables() raises: """Test round-trip with nested tables.""" var original_toml = """ [database.primary] @@ -137,7 +137,7 @@ port = 5433 assert_true(compare_toml_dicts(parsed1, parsed2)) -fn test_roundtrip_special_floats() raises: +def test_roundtrip_special_floats() raises: """Test round-trip with special float values.""" var original_toml = """ pos_infinity = inf @@ -152,7 +152,7 @@ not_a_number = nan assert_true(compare_toml_dicts(parsed1, parsed2)) -fn test_roundtrip_string_escapes() raises: +def test_roundtrip_string_escapes() raises: """Test round-trip with escaped strings.""" # Simple newline escape test var original_toml = 'message = "Hello\\nWorld"' @@ -164,7 +164,7 @@ fn test_roundtrip_string_escapes() raises: assert_true(compare_toml_dicts(parsed1, parsed2)) -fn test_roundtrip_nested_arrays() raises: +def test_roundtrip_nested_arrays() raises: """Test round-trip with nested arrays.""" var original_toml = """ matrix = [[1, 2], [3, 4], [5, 6]] @@ -177,7 +177,7 @@ matrix = [[1, 2], [3, 4], [5, 6]] assert_true(compare_toml_dicts(parsed1, parsed2)) -fn test_roundtrip_complex_structure() raises: +def test_roundtrip_complex_structure() raises: """Test round-trip with complex nested structure.""" var original_toml = """ title = "Complex App" @@ -206,7 +206,7 @@ timeout = 45.0 assert_true(compare_toml_dicts(parsed1, parsed2)) -fn test_roundtrip_root_tables() raises: +def test_roundtrip_root_tables() raises: """Test round-trip with root-level tables.""" var config = Dict[String, TomlValue]() @@ -228,7 +228,7 @@ fn test_roundtrip_root_tables() raises: assert_true(compare_toml_dicts(config, parsed)) -fn test_roundtrip_pixi_toml() raises: +def test_roundtrip_pixi_toml() raises: """Test round-trip with the project's own pixi.toml file.""" # Read pixi.toml var content: String diff --git a/tests/test_writer_tables.mojo b/tests/test_writer_tables.mojo index 205fe68..79ca572 100644 --- a/tests/test_writer_tables.mojo +++ b/tests/test_writer_tables.mojo @@ -3,12 +3,12 @@ Tests the serialisation of tables with [section] headers and nested structures. """ -from testing import assert_equal, assert_true, TestSuite +from std.testing import assert_equal, assert_true, TestSuite from toml import TomlValue, to_toml from std.collections import Dict, List -fn test_write_simple_table() raises: +def test_write_simple_table() raises: """Test writing a simple table with [section] header.""" var config = Dict[String, TomlValue]() @@ -29,7 +29,7 @@ fn test_write_simple_table() raises: assert_true(output.find("enabled = true") != -1) -fn test_write_multiple_tables() raises: +def test_write_multiple_tables() raises: """Test writing multiple tables.""" var config = Dict[String, TomlValue]() @@ -55,7 +55,7 @@ fn test_write_multiple_tables() raises: assert_true(output.find("[database]") != -1) -fn test_write_nested_table() raises: +def test_write_nested_table() raises: """Test writing nested tables.""" var config = Dict[String, TomlValue]() @@ -76,7 +76,7 @@ fn test_write_nested_table() raises: assert_true(output.find("port = 5432") != -1) -fn test_write_deeply_nested_tables() raises: +def test_write_deeply_nested_tables() raises: """Test writing deeply nested tables (3 levels).""" var config = Dict[String, TomlValue]() @@ -100,7 +100,7 @@ fn test_write_deeply_nested_tables() raises: assert_true(output.find("[database.primary.replica]") != -1) -fn test_write_table_with_root_keys() raises: +def test_write_table_with_root_keys() raises: """Test writing mix of root keys and tables.""" var config = Dict[String, TomlValue]() @@ -128,7 +128,7 @@ fn test_write_table_with_root_keys() raises: assert_true(output.find("host = \"localhost\"") != -1) -fn test_write_small_section_table() raises: +def test_write_small_section_table() raises: """Test that 2-key tables use section format at root level.""" var config = Dict[String, TomlValue]() @@ -146,7 +146,7 @@ fn test_write_small_section_table() raises: assert_true(output.find("y = 20") != -1) -fn test_write_table_with_array() raises: +def test_write_table_with_array() raises: """Test writing table containing arrays.""" var config = Dict[String, TomlValue]() @@ -170,7 +170,7 @@ fn test_write_table_with_array() raises: assert_true(output.find("ports = [8080, 8081, 8082]") != -1) -fn test_write_mixed_nested_structure() raises: +def test_write_mixed_nested_structure() raises: """Test complex structure with root keys and nested tables.""" var config = Dict[String, TomlValue]() @@ -207,7 +207,7 @@ fn test_write_mixed_nested_structure() raises: assert_true(output.find("[database.replica]") != -1) -fn test_write_table_with_nested_section() raises: +def test_write_table_with_nested_section() raises: """Test table containing a nested section table.""" var config = Dict[String, TomlValue]() @@ -235,7 +235,7 @@ fn test_write_table_with_nested_section() raises: assert_true(output.find("[database.credentials]") != -1) -fn test_write_empty_table() raises: +def test_write_empty_table() raises: """Test writing an empty table.""" var config = Dict[String, TomlValue]() @@ -248,7 +248,7 @@ fn test_write_empty_table() raises: assert_equal(output, "empty = { }\n") -fn test_write_table_hierarchy() raises: +def test_write_table_hierarchy() raises: """Test proper hierarchy in nested tables.""" var config = Dict[String, TomlValue]()