ConfigPilot is a lightweight and powerful configuration parser for Python that automates checks and typecasting.
Do everything you did in fewer lines of code!
- Simple and concise syntax.
- Lightweight and fast.
- Automatic type casting.
- Automation of value checks.
- Support for primitive Python types and user-defined types.
- Support for multi-line values and lists.
- No dependency.
The recommended way to install ConfigPilot is to use pip3
:
$ pip3 install configpilot
ConfigPilot requires Python 3.6 or later.
Import ConfigPilot into your project:
from configpilot import ConfigPilot, OptionSpec
# Exceptions (optional)
from configpilot import ConfigPilotError, NoSectionError, \
NoOptionError, IllegalValueError
# This is a comment
[author]
name = 'John DOE' # This is an inline comment
age = 27
github = 'https://github.com'
skills = 'sleep well on airplanes'
'have a terrific family recipe for brownies'
'always up for dessert'
Quotes are optional for strings (unless you put special characters).
For this first example, we want to retrieve:
- The
name
as a string. - The
age
as an integer between0
and100
. - The
github
option as a string. - The
skills
as a list of strings.
To achieve this, we have to:
- Define the desired file structure.
- Instantiate a
ConfigPilot
object and indicate the structure of the file. - Read the file and check that it does not contain any errors in terms of format or content.
- Retrieve values.
options = [
OptionSpec(
section='author',
option='name'
),
OptionSpec(
section='author',
option='age',
allowed=range(0, 100),
type=int
),
OptionSpec(
section='author',
option='github'
),
OptionSpec(
section='author',
option='skills',
type=[str]
)
]
config = ConfigPilot()
config.register(*options)
config.read('/path/file.conf')
if not config.is_opened:
print('Error: unable to read the configuration file.')
exit(1)
if config.errors:
print('Error: some options are incorrect.')
exit(1)
name = config.author.name # 'John DOE'
age = config.author.age # 27
github = config.author.github # 'https://github.com'
skills = config.author.skills # ['sleep well on airplanes',
# 'have a terrific family recipe for brownies',
# 'always up for dessert']
# Alternative syntax
name = config['author']['name']
age = config['author']['age']
github = config['author']['github']
skills = config['author']['skills']
[general]
mode: master
interface: ens33
port: 5000
initDelay: 0.5
[logging]
enabled: false
[nodes]
slaves: 10.0.0.1
10.0.0.2
10.0.0.3
What we want to retrieve:
- The
mode
option as a string. Two values will be possible:master
orslave
. - The
interface
as a string. If the option is not specified, we will use the default valueens33
. - The
port
as an integer between1024
and49151
. The default value will be4000
. - The
initDelay
option as a float. The default value will be0.0
. - The
enabled
option, from thelogging
section, as a boolean. - The
slaves
, from thenodes
section, as a list ofIPv4Address
(from theipaddress
module).
from ipaddress import IPv4Address
options = [
OptionSpec(
section='general',
option='mode',
allowed=('master', 'slave')
),
OptionSpec(
section='general',
option='interface',
default='ens33'
),
OptionSpec(
section='general',
option='port',
allowed=range(1024, 49151),
default=4000,
type=int
),
OptionSpec(
section='general',
option='initDelay',
default=0.0,
type=float
),
OptionSpec(
section='logging',
option='enabled',
type=bool
),
OptionSpec(
section='nodes',
option='slaves',
type=[IPv4Address]
)
]
config = ConfigPilot()
config.register(*options)
config.read('/path/file.conf')
if not config.is_opened:
print('Error: unable to read the configuration file.')
exit(1)
if config.errors:
print('Error: some options are incorrect.')
exit(1)
mode = config.general.mode # 'master'
interface = config.general.interface # 'ens33'
port = config.general.port # 5000
init_delay = config.general.initDelay # 0.5
logs_enabled = config.logging.enabled # False
slaves = config.nodes.slaves # [IPv4Address('10.0.0.1'),
# IPv4Address('10.0.0.2'),
# IPv4Address('10.0.0.3')]
[boot]
hexCode: 0x2A
[statistics]
lastBoot: 2020-02-01 10:27:00
lastCrash: 2019-12-10 09:00:00
What we want to retrieve:
- The
hexCode
option as an integer (base 16). - The
lastBoot
option as adatetime
object. - The
lastCrash
option as adatetime
object.
We cannot set the type
parameter of the OptionSpec
objects to datetime
because the constructor of datetime
expects several parameters. The values contained in the configuration file are strings with a specific format. So, we have to process these data with a dedicated function.
from datetime import datetime
def string_to_datetime(value):
'''
Cast a string to a datetime object.
'''
# Do not handle any exceptions that can be raised in this function.
# They are processed by ConfigPilot: the option, which called the
# function, is considered wrong if an exception is thrown.
return datetime.strptime(value, '%Y-%m-%d %H:%M:%S')
options = [
OptionSpec(
section='boot',
option='hexCode',
type=lambda x: int(x, 16)
),
OptionSpec(
section='statistics',
option='lastBoot',
type=string_to_datetime
),
OptionSpec(
section='statistics',
option='lastCrash',
type=string_to_datetime
)
]
config = ConfigPilot()
config.register(*options)
config.read('/path/file.conf')
if not config.is_opened:
print('Error: unable to read the configuration file.')
exit(1)
if config.errors:
print('Error: some options are incorrect.')
exit(1)
boot_hex_code = config.boot.hexCode # 42
last_boot = config.statistics.lastBoot # datetime.datetime(2020, 2, 1, 10, 27)
last_crash = config.statistics.lastCrash # datetime.datetime(2019, 12, 10, 9, 0)
A user-created object that represents the constraints that an option must meet to be considered valid.
OptionSpec(section, option, allowed=None, default=None, type=str)
-
section
The name of a section in the file.
- Type:
str
- Type:
-
option
The name of an option in the specified section.
- Type:
str
- Type:
-
allowed
The list or range of allowed values.
- Type:
object that supports the 'in' operator (membership)
- Default:
None
- Type:
-
default
The default value of the option if it does not exist.
Must be an object of the same type as the value obtained after the cast (see thetype
parameter).- Type:
object
- Default:
None
- Type:
-
type
The expected value type for this option.
Set it toint
,float
,bool
,str
(default) or any other type of object.
If you expect a list of values, use instead[int]
,[float]
,[bool]
,[str]
(equivalent oflist
) or even[MyClass]
.- Type:
type
orlist
- Default:
str
- Type:
ConfigPilot()
-
register(*specifications)
Register one or several specifications. You can call this method multiple times.
Each option in the configuration file must have its own specification. Call theread
method next.*specifications
parameter: one or severalOptionSpec
.
-
read(filename, encoding='utf-8')
Read and parse a configuration file according to the registered specifications.
filename
parameter: the name of the configuration file to read.encoding
parameter: the name of the encoding used to decode the file. The default encoding isUTF-8
.
-
filename
The name of the last opened file.
- Type:
str
- Type:
-
is_opened
Return a boolean that indicates whether the file is opened or not.
- Type:
bool
- Type:
-
errors
Return a dictionary containing sections and options that do not meet the specifications.
- Type:
dict
- Type:
Comments and enhancements are welcome.
All development is done on GitHub. Use Issues to report problems and submit feature requests. Please include a minimal example that reproduces the bug.
ConfigPilot is completely free and open source. It has been fully developed on my free time. If you enjoy it, please consider donating to support the development.
Copyright 2017-2020 Valentin BELYN.
Code released under the MIT license. See the LICENSE for details.