Read, query, modify and write INI configuration files from Julia.
The format follows Python's
configparser, so files
written for Python programs read the same way. Sections and keys keep their
order, so a file read and written again keeps its layout.
using Pkg
Pkg.add("IniFile")Given settings.ini:
# Settings for the example
name = example
[server]
host = example.org
port = 8080
debug = off
[logging]
level = infousing IniFile
ini = read(Inifile, "settings.ini")
get(ini, "server", "host") # "example.org"
get(ini, "server", "timeout") # nothing
get(ini, "server", "timeout", "30") # "30"
get(ini, "server", "name") # "example", from the defaults
get_int(ini, "server", "port") # 8080
get_bool(ini, "server", "debug") # false
get_float(ini, "server", "timeout", 30.0) # 30.0
merged(ini)["level"] # "info": all keys in one dictionary
set(ini, "server", "port", 9090)
set(ini, "cache", "size", 100) # creates the section
write("settings.ini", ini)ini = read(Inifile, "file.ini") # from a file
ini = read(Inifile, io) # from any IO stream
ini = read(Inifile, "file.ini"; lowercase_keys=true, inline_comment_prefixes=(";",))
ini = Inifile() # or create an empty one
read(ini, "file.ini") # and read into it (merges with its content)Options of Inifile(...) and read(Inifile, ...):
| Keyword | Default | Effect |
|---|---|---|
lowercase_keys |
false |
Store and look up keys in lowercase, so Key and key are the same key, as Python's configparser does by default. Section names stay case-sensitive. |
inline_comment_prefixes |
() |
Prefixes such as (";", "#") that start a comment in the middle of a line, when they follow whitespace. Off by default, as in Python 3. |
multiline_values |
false |
Allow values that span several lines, written as indented continuation lines (see Multi-line values). |
strict |
false |
Throw an ArgumentError for a malformed line instead of logging a warning and skipping it. Repeated keys and sections are allowed either way. |
get(ini, "section", "key") # value as a String, or nothing
get(ini, "section", "key", default) # value, or default
get_bool(ini, "section", "key") # Bool: 1/yes/true/on or 0/no/false/off, any case
get_int(ini, "section", "key") # Int
get_float(ini, "section", "key") # Float64
get_int(ini, "section", "key", default) # default if the key is missing
has_section(ini, "section")
haskey(ini, "section", "key")
sections(ini) # OrderedDict of section name => OrderedDict of key => value
section(ini, "section") # OrderedDict of key => value
defaults(ini) # keys that appear before the first section header
get(ini, "key") # a key in the defaults, or nothing
merged(ini) # OrderedDict of all keys: the defaults, then each sectionA lookup in a section falls back to the defaults when the section does not have
the key. The typed getters throw a KeyError for a missing key when no default
is given, and an ArgumentError naming the section, key and value when the value
cannot be parsed. In particular get_bool rejects values such as Ture instead
of reading them as false.
merged(ini) returns a new OrderedDict{String,String} with the defaults and
then the keys of each section, in section order. A key in a later section
overrides the same key in the defaults or in an earlier section. This suits
programs that treat sections only as a way to group options:
solver = cg+amg
[Options for advanced mode]
solver = cholmod
mask_file = none
[Output options]
write_cur_maps = Trueopts = merged(read(Inifile, "job.ini"))
opts["solver"] # "cholmod"
collect(keys(opts)) # ["solver", "mask_file", "write_cur_maps"]set(ini, "section", "key", value) # value is a string, number or Bool, stored as a string
set(ini, "section", "key", nothing) # remove the key
set(ini, "key", value) # set a key in the defaults
write("file.ini", ini) # or write(io, ini)write keeps the order of sections and keys, writes key = value, and puts a
blank line between sections. Comments in the original file are not kept. A value
that contains newlines can only be written with multiline_values=true;
otherwise write throws an ArgumentError before writing anything, because the
value could not be read back. print(io, ini) and string(ini) give the same
text without this check, so they never throw.
; A comment
# Another comment
# Entries before the first section header are the defaults
default_key = value
[section name]
key = value
# The first `=` or `:` on a line separates the key and the value
other_key: value
empty =- Blank lines and lines starting with
#or;are ignored. - Whitespace around keys and values is removed, including indentation.
- Inline comments, as in
key = value ; note, are only removed when enabled withinline_comment_prefixes; otherwise they are part of the value. - Malformed lines are skipped with a warning that gives the line number.
With multiline_values=true, a line indented more than the line that started an
entry continues that entry's value, as in Python's configparser:
[paths]
search =
/usr/lib
/opt/libini = read(Inifile, "paths.ini"; multiline_values=true)
split(strip(get(ini, "paths", "search")), '\n') # ["/usr/lib", "/opt/lib"]The lines are joined with "\n". Blank lines inside a value are kept, and
comment lines are skipped. write puts each extra line on its own line,
indented with a tab. Whitespace at the start and end of each line is not kept,
and a line of the value that starts with # or ; reads back as a comment.
Multi-line values are off by default, so indentation does not change the meaning of a file: every line stands on its own, as in IniFile 0.5.
- A key that appears again in the same section replaces the earlier value and keeps its first position, so the last value wins. A line appended at the end of a section overrides an earlier one.
- A section header that appears again adds its entries to the earlier section, which keeps the position of its first header.
- In
merged(ini), a key in a later section overrides the same key in an earlier one. Sections are ordered by their first header, so a key in a later section wins even over a line further down the file in a repeated, earlier section. - Repeated keys and sections are never an error, even with
strict=true, which only concerns malformed lines.
- Entries before the first section header are allowed and become the defaults.
A
[DEFAULT]section is an ordinary section. - There is no value interpolation (
%(name)sor${name}). - Keys without a value (
allow_no_value) are malformed. - Multi-line values must be enabled with
multiline_values=true;configparseralways allows them. - Repeated sections are merged and repeated keys overwrite earlier ones, as in
configparserwithstrict=False. IniFile'sstrictoption is unrelated: it only makes malformed lines an error. - Python 2's
ConfigParseralways treated;after whitespace as a comment. To read such files the same way, useinline_comment_prefixes=(";",).
Version 0.6 has breaking changes:
- Values are always
Strings.setstoresstring(value), soset(ini, "s", "k", 1.5)followed byget(ini, "s", "k")returns"1.5". Useget_float,get_intorget_boolto get typed values. get(ini, section, key)andget(ini, key)returnnothinginstead of:notfoundfor a missing key. Checks such asvalue === :notfounddo not throw an error, they just stop matching, so search for:notfoundand change them tovalue === nothing.get(ini, key, default)is removed, because it was the same call asget(ini, section, key)when the default was a string (#16). Useget(defaults(ini), key, default).get_boolaccepts 1/yes/true/on and 0/no/false/off (in any case) and throws anArgumentErrorfor anything else. It used to returntrueonly fortrueandfalsefor everything else, soyes,onand1now read astrueinstead offalse.get_bool,get_intandget_floatthrow aKeyErrorfor a missing key (instead of aMethodError), and anArgumentErrorthat names the key for a value that cannot be parsed.sections(ini),section(ini, name)anddefaults(ini)returnOrderedDicts withStringkeys and values instead ofDict{AbstractString,...}.show(io, ini)andrepr(ini)give a one-line summary such asInifile(2 sections, 5 keys), which is also how anInifileappears inside arrays and other containers.print,stringandwritestill give the file contents.writethrows anArgumentErrorfor a value that contains a newline, unless theInifilewas created withmultiline_values=true. Such a value used to be written out as is, and the file could not be read back correctly.- Malformed lines are reported with
@warninstead of being printed tostdout. Inifileis now an immutable struct created with keyword arguments.- Julia 1.6 or later is required (0.5 supported Julia 1.0).