Repository navigation
Modernize IniFile.jl for 0.6.0: configparser-compatible parsing, ordered round-trips, strict typed getters - #38
Merged
Merged
Conversation
- Require Julia 1.10, the current LTS, and add a compat entry for Test. - CI: test on lts, release and nightly (nightly may fail) on Linux, macOS and Windows, using setup-julia@v3, julia-actions/cache, buildpkg, runtest and codecov@v7. Also run on workflow_dispatch and cancel superseded pull request builds. - Add CompatHelper, update TagBot to the current template, and group dependabot's GitHub Actions updates. - Add a .gitignore for manifests and coverage output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Parsing, following Python's configparser: - Skip only blank lines and comments. Short entries such as `a=` were dropped before because every line shorter than 3 characters was skipped. - Report malformed lines with @warn, giving the line number and file name, instead of println. With the new `strict=true` option they throw an ArgumentError instead. - Use the first `=` or `:` on the line as the delimiter, replacing the min/max over two findfirst calls. - Treat empty keys, `[]` and unterminated section headers as malformed. Accept a UTF-8 byte order mark and CRLF line endings. Storage and output: - Store sections and keys in OrderedDicts with String keys and String values, so insertion order is kept and lookups are type-stable. `set` stores `string(value)`. - `write` keeps the order, writes `key = value`, puts a blank line between sections, and returns the number of bytes written. - Two-argument `show` is now a one-line summary; the full contents are shown for MIME"text/plain" (the REPL). API: - `get(ini, section, key)` returns `nothing` instead of `:notfound` when the key is missing. - `get_bool` accepts what configparser's getboolean accepts (1/yes/true/on, 0/no/false/off, any case) and throws an ArgumentError naming the section, key and value otherwise, instead of reading typos as false. - `get_bool`, `get_int` and `get_float` take an optional default for missing keys and otherwise throw a KeyError((section, key)) instead of a MethodError. Unparseable values throw an ArgumentError naming the section, key and value. - Remove `get(ini, key, default)`: it was the same call as `get(ini, section, key)` whenever the default was a string (#16). Use `get(defaults(ini), key, default)`. - Add the `lowercase_keys` option, like configparser's default optionxform. Keys stay case-sensitive by default. - Add `read(Inifile, path_or_io; kwargs...)`. - Add docstrings for every exported function and the Base methods. - Drop `__precompile__()`, `== nothing` and the `import Base.x` lists. Tests are rewritten and extended to cover each change, including order-preserving round trips and the use case from #20, and run Aqua.jl. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Multi-line values work as in Python's configparser: a line indented more
than the line that started an entry continues its value. The lines are
joined with "\n", blank lines inside the value are kept, trailing blank
lines are dropped, and comment lines are skipped. `write` emits
multi-line values as tab-indented continuation lines, so they round-trip.
Inline comments are off by default, as in Python 3, and are enabled with
the new `inline_comment_prefixes` option, e.g. `(";", "#")`. A prefix
starts a comment only at the start of a line or after whitespace, so
`a = b;c` and URLs with `#` fragments keep their text.
This brings in the features proposed in #10 (multi-line values and
optional mid-line comments) and #8 (strip inline comments separated by
whitespace), adapted to configparser's syntax. #10 continued lines ending
in a backslash; configparser uses indentation instead, and a trailing
backslash would break Windows paths such as `C:\data\`. The test cases
from #10 are adapted in test/test.ini.
Uniformly indented entries are still separate entries, but an entry
indented more than the one before it is now part of that entry's value.
Co-authored-by: William Douglas <13699381+sleepywill@users.noreply.github.com>
Co-authored-by: Shoibal Chakravarty <1609634+shoibalc@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Document the API with examples, the options, the file format, the differences from Python's configparser, and the breaking changes since 0.5. 0.6.0 rather than 0.5.2: the release changes return types and removes a method, which is breaking, and for 0.x versions Julia's resolver treats a minor bump as breaking, so dependents with `IniFile = "0.5"` compat will not pick it up until they opt in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Welcome to Codecov 🎉Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests. Thanks for integrating Codecov - We've got you covered ☂️ |
Removed LTS and nightly versions from CI matrix.
This was referenced Nov 14, 2026
Dependabot now supports Julia, and CompatHelper's docs recommend migrating to it. Add a julia entry to dependabot.yml so [compat] bumps come from Dependabot, and remove the CompatHelper workflow. Dependabot's pull requests trigger CI without a deploy key. Run both the github-actions and julia updates monthly instead of weekly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In 0.5, `print(io, ini)` and `string(ini)` wrote the INI text, so code that saved a file with `print` would silently write a one-line summary instead. Define `print` to write the contents, as before. Two-argument `show` stays a compact summary, so an Inifile inside a container or in `repr` does not dump the whole file. Make the upgrade guide explicit about the two changes that break code without an error: `=== :notfound` checks stop matching, and `get_bool` now reads yes, on and 1 as true. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lower the julia compat floor from 1.10 to 1.6. The test suite passes on Julia 1.6.7 with OrderedCollections 1.7 and Aqua 0.8. Add a `min` CI job, which runs the oldest version allowed by [compat], on Linux only. macos-latest runs on Apple silicon, which has no Julia 1.6 build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This modernizes IniFile.jl and prepares the 0.6.0 release. It started from evaluating IniFile for Circuitscape.jl, which reads INI files written for Python's ConfigParser. The parser now follows Python's
configparser. On a file of edge cases (multi-line values with blank and comment lines, indented keys, delimiters, and inline comments on and off) it gives the same results as Python 3'sconfigparser.Fixes
a=were dropped, because every line shorter than 3 characters was skipped. Now only blank lines and comments are skipped.println. They are now reported with@warn, including the line number and file name. Withstrict=truethey throw instead.=or:on the line.get_boolread any typo, such asTure, asfalse. It now accepts 1/yes/true/on and 0/no/false/off in any case, and throws anArgumentErrornaming the section, key and value for anything else.get_bool,get_intandget_floatthrew aMethodErroron a missing key. They now take an optional default; without one they throwKeyError((section, key)). Values that cannot be parsed throw anArgumentErrornaming the section, key and value.writescrambled sections and keys, because they were stored inDicts. They are now stored in order, so files round-trip.writeemitskey = valueand puts a blank line between sections.Strings (OrderedDict{String,String}) instead ofDict{AbstractString,Union{...}}, so lookups are type-stable.get(ini, key, default)is removed. It was the same call asget(ini, section, key)whenever the default was a string (Ambiguity in get function #16).New features
configparser(adapted from Support for mutiline values and optional support for mid-line comments #10).inline_comment_prefixes=(";", "#"). A prefix starts a comment only after whitespace (adapted from strip leading/trailing white space and following inline comments from value #8 and Support for mutiline values and optional support for mid-line comments #10).lowercase_keys=true, likeconfigparser's defaultoptionxform.read(Inifile, path_or_io; kwargs...)creates anInifileand reads into it.showis a one-line summary, so anInifileinside a container does not print the whole file. The REPL,printandstringstill give the full contents.Breaking changes
setstoresstring(value), sogetalways returns aString. For example,getreturns"1.5"afterset(ini, "s", "k", 1.5).get(ini, section, key)andget(ini, key)returnnothinginstead of:notfoundfor a missing key.=== :notfoundchecks do not error, they stop matching.get(ini, key, default)is removed. Useget(defaults(ini), key, default).get_boolthrows for values other than 1/yes/true/on and 0/no/false/off, andyes,onand1now read astrue(they used to read asfalse). The typed getters throw aKeyErrorfor missing keys.sections,sectionanddefaultsreturnOrderedDicts withStringkeys and values.show(io, ini)andrepr(ini)give a one-line summary instead of the file contents.print,stringandwritestill give the contents.Inifileis an immutable struct with a keyword constructor.Infrastructure
[compat]entries for julia (1.6) and every dependency. OrderedCollections (1.6, 2) is the only new dependency.[compat]entries as well as GitHub Actions, monthly, instead of CompatHelper. TagBot is updated to the current template.Version
0.6.0. The changes above are breaking, and for 0.x versions Julia's resolver treats a minor bump as breaking, so packages with
IniFile = "0.5"keep 0.5 until they opt in.Closes #16
Closes #20
Supersedes #8 and #10, which have been open since 2014 and 2015; their authors are credited as co-authors of the commit that adds these features.
🤖 Generated with Claude Code