Skip to content

Configuration¤

Configuration is provided by the asab.Config object, which you can access from any place in your code, without need of explicit initialization.

import asab

app = asab.Application() #(1)! 

...

my_conf_value = asab.Config['section_name']['key1'] #(2)!
  1. Configuration is initialized during the application init-time.
  2. You can access the configuration values from anywhere in the code.

Based on ConfigParser object¤

asab.Config is an instance of asab.config.ConfigParser class, derived from the Python standard configparser.ConfigParser. The class implements a basic configuration language that provides a structure similar to what's found in Microsoft Windows INI files.

Basic usage:

This is an example of the configuration file. We hope that it helps you quickly understand what the rules are:

configuration.conf
[section name]
key=value
keys can contain spaces = values can contain spaces

you can use = equal signs
as well as: colons
extra spaces are : removed

be careful: 'quotes are parsed as quotes'

[another section]
final answer = 42
are you sure = true

numerical values are held as: strings
booleans are held as: strings
use these functions: getint(), getfloat(), getboolean()

And this is how you access configuration values:

>>> asab.Config['section name']['key']
'value'
>>> asab.Config.get('another section', 'final answer')
'42'
>>> asab.Config.getint('another section', 'final answer')
42
>>> asab.Config.getboolean('another section', 'are you sure')
True

Be careful with comments:

[comments]
# Comments in empty lines are supported
key = value # inline comments are not supported!

# That would prevent URL fragments from being read:
path = https://www.netlog.org/path#fragment

Multiline configuration entry:

A multiline configuration entries are supported:

multiline_values = are
    handled just fine as
    long as they are indented
    deeper than the first line
    of a value
chorus: I'm a lumberjack, and I'm okay
    I sleep all night and I work all day

However, there are some configurable options where the newline is used as a separator, see .

Loading configuration from a file¤

If a configuration file name is specified,the configuration is automatically loaded from a configuration file during the Application init-time. There are two ways to include a configuration file:

  1. by using the -c command-line argument:

    python3 my_app.py -c ./etc/sample.conf
    
  2. by running the application with ASAB_CONFIG environment variable set:

    export ASAB_CONFIG="./etc/sample.conf"
    python3 my_app.py
    

Including other configuration files¤

You can specify one or more additional configuration files that are loaded and merged from a main configuration file:

[general]
include=./etc/site.conf:./etc/site.d/*.conf

Multiple paths are separated by os.pathsep value, which is : on Unix and ; on Windows. The path can be specified as a glob (e.g. use of * and ? wildcard characters), it will be expanded by glob module.

Warning

If the additional configuration files do not exist, the situation is ignored silently!

You can also use a multiline configuration entry:

[general]
include=
    ./etc/site.conf
    ./etc/site.d/*.conf

Including ZooKeeper node in the configuration¤

The separator between 'include' items is a newline or space. This means that names of nodes in Zookeeper must not have the space character in them.

The ZooKeeper node can contain a configuration file in .conf, .json or .yaml format.

You can specify servers and path of the ZooKeeper node directly in the include option:

[general]
include=zookeeper://localhost:2181/asab/config/config-test.yaml

It is also possible to name only the node path in this section and use zookeeper configuration section to read the location of ZooKeeper servers. Using the environment variable ASAB_ZOOKEEPERS_SERVERS is also a possible option.

[general]
include=zookeeper:///asab/config/config-test.yaml

Default values¤

This is how you can extend configuration default values:

asab.Config.add_defaults(
    {
        'section_name': {
            'key1': 'value',
            'key2': 'another value'
        },
        'other_section': {
            'key3': 'value',
        },
    }
)

Warning

Only simple types (string, int and float) are allowed in the configuration values. Do not use complex types such as lists, dictionaries, or objects because these are impossible to provide via configuration files etc.

Environment variables¤

Environment variables found in values are automatically expanded.

[section_name]
persistent_dir=${HOME}/.myapp/
>>> asab.Config['section_name']['persistent_dir']
'/home/user/.myapp/'

There is a special environment variable ${THIS_DIR} that is expanded to a directory that contains a current configuration file. It is useful in complex configurations that utilizes included configuration files etc.

[section_name]
my_file=${THIS_DIR}/my_file.txt

Another environment variable ${HOSTNAME} contains the application hostname to be used, e.g. in logging file path.

[section_name]
my_file=${THIS_DIR}/${HOSTNAME}/my_file.txt

Passwords¤

[passwords] section in the configuration serves to securely store passwords, which are then not shown publicly in the default API config endpoint's output.

It is convenient for the user to store passwords at one place, so that they are not repeated in many sections of the config file(s).

Example

[connection:KafkaConnection]
password=${passwords:kafka_password}

[passwords]
kafka_password=<MY_SECRET_PASSWORD>

Reference¤

Environment variables¤

Name Usage
ASAB_CONFIG Path to the custom configuration file with which ASAB app will be using
ASAB_ZOOKEEPERS_SERVERS URL for Zookeeper node
THIS_DIR Directory that contains a current configuration file
HOSTNAME The application hostname

asab.Config = ConfigParser(interpolation=_Interpolation()) module-attribute ¤

Object for accessing the configuration of the ASAB application.

Examples:

my_conf_value = asab.Config['section_name']['key']

asab.config.ConfigParser ¤

Bases: ConfigParser

ConfigParser enhanced with new features such as adding default configuration, URL validation, automatic reading from Zookeeper etc.

Source code in asab/config.py
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
class ConfigParser(configparser.ConfigParser):
	"""
	ConfigParser enhanced with new features such as adding default configuration, URL validation, automatic reading from Zookeeper etc.
	"""
	_syslog_sockets = {
		'Darwin': '/var/run/syslog'
	}

	_syslog_format = {
		'Darwin': 'm'
	}

	_default_values = {

		'general': {
			'config_file': os.environ.get('ASAB_CONFIG', ''),
			'tick_period': 1,  # In seconds
			'var_dir': os.path.expanduser('~/.' + os.path.splitext(os.path.basename(sys.argv[0]))[0]),

			'changelog': '',
			'manifest': '',

			# Daemonization
			'pidfile': '!',  # '!' has a special meaning => it transforms into platform specific location of pid file
			'working_dir': '.',
			'uid': '',
			'gid': '',

			# Watchdog (event loop interactivity check)
			# If the threshold (in seconds) since the last tick/60! passed, the application is killed
			# If 0, the watchdog is not started
			'watchdog_threshold': 15 * 60,  # 15 minutes
		},

		"asab:metrics": {
			"native_metrics": "true",
			"web_requests_metrics": False,  # False is a default, web_requests_metrics won't be generated.
			"expiration": 60,
		},

		"asab:doc": {
			"default_route_tag": "module_name"
		},

		"logging": {
			'verbose': os.environ.get('ASAB_VERBOSE', False),
			"app_name": os.path.basename(sys.argv[0]),
			"sd_id": "sd",  # Structured data id, see RFC5424
			"level": "NOTICE",
			"levels": "",
		},

		"logging:console": {
			"format": "%(asctime)s %(levelname)s %(name)s %(struct_data)s%(message)s",
			"datefmt": "%d-%b-%Y %H:%M:%S.%f",
			"enabled": True
		},

		"logging:syslog": {
			"enabled": "false",
			# TODO: "facility": 'local1',
			"address": _syslog_sockets.get(platform.system(), "/dev/log"),
			"format": _syslog_format.get(platform.system(), "3"),
		},

		"logging:file": {
			"path": "",
			"format": "%(asctime)s %(levelname)s %(name)s %(struct_data)s%(message)s",
			"datefmt": "%d-%b-%Y %H:%M:%S.%f",
			"backup_count": 3,
			"backup_max_bytes": 0,
			"rotate_every": "",
		},

		"library": {
			"azure_cache": "false",  # true or the actual path of where the cache should be located
		},

		# "passwords" section serves to securely store passwords
		# in the configuration file; the passwords are not
		# shown in the default API
		#
		# Usage in the configuration file:
		#
		# [connection:KafkaConnection]
		# password=${passwords:kafka_password}
		#
		# [passwords]
		# kafka_password=<MY_SECRET_PASSWORD>
		"passwords": {
		},

		"housekeeping": {
			"at": "03:00",
			"limit": "05:00",
			"run_at_startup": "no",
		},

		"tenants": {
			# Whitespace/comma-separated list of tenant IDs
			"ids": "",

			# Web URL that provides a JSON array of tenant ID strings
			"tenant_url": "",
		},

		"auth": {
			# URL location containing the authorization server's public JWK keys
			# (often found at "/.well-known/jwks.json")
			"public_keys_url": "",

			# The "enabled" option switches authentication and authorization
			# on, off or activates mock mode. The default value is True (on).
			# In MOCK MODE
			# - no authorization server is needed,
			# - all incoming requests are mock-authorized with pre-defined user info,
			# - custom mock user info can supplied in a JSON file.
			# "enabled": "yes",
			"mock_user_info_path": "/conf/mock-userinfo.json",
		},
	}

	if 'ASAB_ZOOKEEPER_SERVERS' in os.environ:
		# If `ASAB_ZOOKEEPER_SERVERS` are specified, use that as a default value
		_default_values['zookeeper'] = {'servers': os.environ['ASAB_ZOOKEEPER_SERVERS']}

	def add_defaults(self, dictionary: dict) -> None:
		"""Add defaults to a current configuration.

		Args:
			dictionary: Arguments to be added to the default configuration.
		"""

		for section, keys in dictionary.items():
			section = str(section)

			if section not in self._sections:
				try:
					self.add_section(section)
				except ValueError:
					if self._strict:
						raise

			for key, value in keys.items():

				key = self.optionxform(str(key))
				if key in self._sections[section]:
					# Value exists, no default needed
					continue

				if value is not None:
					value = str(value)

				if value is not None and "$" in value:
					self.set(section, key, os.path.expandvars(value))
				else:
					self.set(section, key, value)


	def _traverse_includes(self, includes: str, this_dir: str) -> None:
		"""
		Read included config files. Nested including is supported.
		"""
		if '\n' in includes:
			sep = '\n'
		else:
			sep = " "

		for include_glob in includes.split(sep):
			include_glob = include_glob.strip()

			if len(include_glob) == 0:
				continue

			if include_glob.startswith("zookeeper"):
				self._include_from_zookeeper(include_glob)

			include_glob = os.path.expandvars(include_glob.strip())

			for include in glob.glob(include_glob):
				include = os.path.abspath(include)

				if include in self._included:
					# Preventing infinite dependency looping
					L.warn("Config file '{}' can be included only once.".format(include))
					continue

				self._included.add(include)
				self.set('general', 'include', '')

				self._load_dir_stack.append(os.path.dirname(include))
				try:
					self.read(include)
				finally:
					self._load_dir_stack.pop()

				includes = self.get('general', 'include', fallback='')
				self._traverse_includes(includes, os.path.dirname(include_glob))


	def _load(self):
		"""
		This method should be called only once, any subsequent call will lead to undefined behaviour.
		"""
		self._load_dir_stack = []
		self.config_contents_list = []
		self.config_name_list = []

		config_fname = ConfigParser._default_values['general']['config_file']
		if config_fname != '':
			if not os.path.isfile(config_fname):
				print("Config file '{}' not found".format(config_fname), file=sys.stderr)
				sys.exit(1)

			self._load_dir_stack.append(os.path.dirname(config_fname))
			try:
				self.read(config_fname)
			finally:
				self._load_dir_stack.pop()

		self.add_defaults(ConfigParser._default_values)

		includes = self.get('general', 'include', fallback='')

		self._included = set()
		self._traverse_includes(includes, this_dir=os.path.dirname(config_fname))

		del self._load_dir_stack


	def _include_from_zookeeper(self, zkurl):
		"""
		Load the configuration from a ZooKeeper server and append it to the `self.config_contents_list` attribute.

		The method establishes a connection to the ZooKeeper server specified in the configuration file mentioned above.
		It retrieves the configuration by accessing the path specified in the `general` section, using the key `includes`.
		The server URL is provided as a list of server names: server1, server2, server3.
		The path to the configuration file follows this format: 'zookeeper-1:2181,zookeeper-2:2181,zookeeper-3:2181/asab/etc/zk-site.conf.'

		The loaded configuration is then appended to the `self.config_contents_list` attribute, allowing further processing or usage.
		This method supports loading configuration files in various formats, such as .json, .yaml, and .conf.

		Example:

			```ini
			[asab:zookeeper]
			url=server1 server2 server3
			[general]
			include=zookeeper://zookeeper-1:2181,zookeeper-2:2181,zookeeper-3:2181/asab/etc/zk-site.conf.
			```
		"""
		# parse include value into hostname and path
		url_pieces = urllib.parse.urlparse(zkurl)
		url_path = url_pieces.path
		url_netloc = url_pieces.netloc

		if not url_netloc:
			if "asab:zookeeper" in self:
				# Backward compatibility
				url_netloc = self["asab:zookeeper"]["servers"]
			else:
				url_netloc = self["zookeeper"]["servers"]

		if url_path.startswith("./"):
			if "asab:zookeeper" in self:
				# Backward compatibility
				url_path = self["asab:zookeeper"]["path"] + url_path[1:]
			else:
				url_path = self["zookeeper"]["path"] + url_path[1:]

		head, tail = os.path.split(url_path)
		self.config_name_list.append(tail)

		try:
			# Delayed import to minimize a hard dependency footprint
			import kazoo.client
			import json
			import yaml
			zk = kazoo.client.KazooClient(url_netloc)
			zk.start()
			data = zk.get(url_path)[0]
			if url_path.endswith(".json"):
				config = json.loads(data)
				self.read_dict(config)
			elif url_path.endswith(".yaml"):
				config = yaml.safe_load(data)
				self.read_dict(config)
			elif url_path.endswith(".conf"):
				config = data.decode("utf-8")
				self.read_string(config)
			else:
				raise NotImplementedError("Unknown configuration format '{}'".format(url_path))

			zk.stop()
			zk.close()

			# Include in the list of config file contents
			self.config_contents_list.append(config)

		except Exception as e:
			L.error("Failed to obtain configuration from Zookeeper server(s): '{}'.".format(e))
			sys.exit(1)


	def get_config_contents_list(self):
		return self.config_contents_list, self.config_name_list


	def getseconds(self, section, option, *, raw=False, vars=None, fallback=None, **kwargs) -> float:
		"""
		Get time data from config and convert time string into seconds with `convert_to_seconds()` method.

		The available units are:

		- `y` - years
		- `M` - months
		- `w` - weeks
		- `d` - days
		- `h` - hours
		- `m` - minutes
		- `s` - seconds
		- `ms` - milliseconds

		Returns:
			float: Time in seconds.

		Examples:

		```python
		self.SleepTime = asab.Config["sleep"].getseconds("sleep_time")
		self.AnotherSleepTime = asab.Config.getseconds("sleep", "another_sleep_time")
		```
		"""

		if fallback is None:
			fallback = configparser._UNSET

		return self._get_conv(section, option, utils.convert_to_seconds, raw=raw, vars=vars, fallback=fallback, **kwargs)


	def geturl(self, section, option, *, raw=False, vars=None, fallback=None, scheme=None, **kwargs):
		"""
		Get URL from config and remove all leading and trailing whitespaces and trailing slashes.

		Args:
			scheme (str | tuple): URL scheme(s) awaited. If `None`, scheme validation is bypassed.

		Returns:
			Validated URL.

		Raises:
			ValueError: Scheme requirements are not met if set.

		Examples:

		```ini
		[urls]
		teskalabs=https://www.teskalabs.com/
		github=github.com
		```

		``` python
		asab.Config["urls"].geturl("teskalabs", scheme="https")
		asab.Config.geturl("urls", "github", scheme=None)
		```
		"""
		return utils.validate_url(self.get(section, option, raw=raw, vars=vars, fallback=fallback), scheme)


	def getmultiline(self, section, option, *, raw=False, vars=None, fallback=None, **kwargs) -> typing.List[str]:
		"""
		Get multiline data from config.

		Examples:

		```ini
		[places]
		visited:
			Praha
			Brno
			Pardubice Plzeň
		unvisited:
		```

		```python
		>>> asab.Config.getmultiline("places", "visited")
		["Praha", "Brno", "Pardubice", "Plzeň"]
		>>> asab.Config.getmultiline("places", "unvisited")
		[]
		>>> asab.Config.getmultiline("places", "nonexisting", fallback=["Gottwaldov"])
		["Gottwaldov"]
		```
		"""
		values = self.get(section, option, raw=raw, vars=vars, fallback=fallback)
		if isinstance(values, str):
			return [item.strip() for item in re.split(r"\s+", values) if len(item) > 0]
		else:
			# fallback can be anything
			return values

add_defaults(dictionary) ¤

Add defaults to a current configuration.

Parameters:

Name Type Description Default
dictionary dict

Arguments to be added to the default configuration.

required
Source code in asab/config.py
def add_defaults(self, dictionary: dict) -> None:
	"""Add defaults to a current configuration.

	Args:
		dictionary: Arguments to be added to the default configuration.
	"""

	for section, keys in dictionary.items():
		section = str(section)

		if section not in self._sections:
			try:
				self.add_section(section)
			except ValueError:
				if self._strict:
					raise

		for key, value in keys.items():

			key = self.optionxform(str(key))
			if key in self._sections[section]:
				# Value exists, no default needed
				continue

			if value is not None:
				value = str(value)

			if value is not None and "$" in value:
				self.set(section, key, os.path.expandvars(value))
			else:
				self.set(section, key, value)

getmultiline(section, option, *, raw=False, vars=None, fallback=None, **kwargs) ¤

Get multiline data from config.

Examples:

[places]
visited:
        Praha
        Brno
        Pardubice Plzeň
unvisited:
>>> asab.Config.getmultiline("places", "visited")
["Praha", "Brno", "Pardubice", "Plzeň"]
>>> asab.Config.getmultiline("places", "unvisited")
[]
>>> asab.Config.getmultiline("places", "nonexisting", fallback=["Gottwaldov"])
["Gottwaldov"]
Source code in asab/config.py
def getmultiline(self, section, option, *, raw=False, vars=None, fallback=None, **kwargs) -> typing.List[str]:
	"""
	Get multiline data from config.

	Examples:

	```ini
	[places]
	visited:
		Praha
		Brno
		Pardubice Plzeň
	unvisited:
	```

	```python
	>>> asab.Config.getmultiline("places", "visited")
	["Praha", "Brno", "Pardubice", "Plzeň"]
	>>> asab.Config.getmultiline("places", "unvisited")
	[]
	>>> asab.Config.getmultiline("places", "nonexisting", fallback=["Gottwaldov"])
	["Gottwaldov"]
	```
	"""
	values = self.get(section, option, raw=raw, vars=vars, fallback=fallback)
	if isinstance(values, str):
		return [item.strip() for item in re.split(r"\s+", values) if len(item) > 0]
	else:
		# fallback can be anything
		return values

getseconds(section, option, *, raw=False, vars=None, fallback=None, **kwargs) ¤

Get time data from config and convert time string into seconds with convert_to_seconds() method.

The available units are:

  • y - years
  • M - months
  • w - weeks
  • d - days
  • h - hours
  • m - minutes
  • s - seconds
  • ms - milliseconds

Returns:

Name Type Description
float float

Time in seconds.

Examples:

self.SleepTime = asab.Config["sleep"].getseconds("sleep_time")
self.AnotherSleepTime = asab.Config.getseconds("sleep", "another_sleep_time")
Source code in asab/config.py
def getseconds(self, section, option, *, raw=False, vars=None, fallback=None, **kwargs) -> float:
	"""
	Get time data from config and convert time string into seconds with `convert_to_seconds()` method.

	The available units are:

	- `y` - years
	- `M` - months
	- `w` - weeks
	- `d` - days
	- `h` - hours
	- `m` - minutes
	- `s` - seconds
	- `ms` - milliseconds

	Returns:
		float: Time in seconds.

	Examples:

	```python
	self.SleepTime = asab.Config["sleep"].getseconds("sleep_time")
	self.AnotherSleepTime = asab.Config.getseconds("sleep", "another_sleep_time")
	```
	"""

	if fallback is None:
		fallback = configparser._UNSET

	return self._get_conv(section, option, utils.convert_to_seconds, raw=raw, vars=vars, fallback=fallback, **kwargs)

geturl(section, option, *, raw=False, vars=None, fallback=None, scheme=None, **kwargs) ¤

Get URL from config and remove all leading and trailing whitespaces and trailing slashes.

Parameters:

Name Type Description Default
scheme str | tuple

URL scheme(s) awaited. If None, scheme validation is bypassed.

None

Returns:

Type Description

Validated URL.

Raises:

Type Description
ValueError

Scheme requirements are not met if set.

Examples:

[urls]
teskalabs=https://www.teskalabs.com/
github=github.com
asab.Config["urls"].geturl("teskalabs", scheme="https")
asab.Config.geturl("urls", "github", scheme=None)
Source code in asab/config.py
def geturl(self, section, option, *, raw=False, vars=None, fallback=None, scheme=None, **kwargs):
	"""
	Get URL from config and remove all leading and trailing whitespaces and trailing slashes.

	Args:
		scheme (str | tuple): URL scheme(s) awaited. If `None`, scheme validation is bypassed.

	Returns:
		Validated URL.

	Raises:
		ValueError: Scheme requirements are not met if set.

	Examples:

	```ini
	[urls]
	teskalabs=https://www.teskalabs.com/
	github=github.com
	```

	``` python
	asab.Config["urls"].geturl("teskalabs", scheme="https")
	asab.Config.geturl("urls", "github", scheme=None)
	```
	"""
	return utils.validate_url(self.get(section, option, raw=raw, vars=vars, fallback=fallback), scheme)

asab.config.Configurable ¤

Bases: object

Custom object whose attributes can be loaded from the configuration.

Example
class ConfigurableObject(asab.Configurable):

        ConfigDefaults = {
                'foo': 'bar',
        }

        def __init__(self, config_section_name, config=None):
                super().__init__(config_section_name=config_section_name, config=config)

                config_foo = self.Config.get('foo')
Source code in asab/config.py
class Configurable(object):
	"""
	Custom object whose attributes can be loaded from the configuration.

	Example:
		```python
		class ConfigurableObject(asab.Configurable):

			ConfigDefaults = {
				'foo': 'bar',
			}

			def __init__(self, config_section_name, config=None):
				super().__init__(config_section_name=config_section_name, config=config)

				config_foo = self.Config.get('foo')
		```
	"""

	ConfigDefaults: dict = {}


	def __init__(self, config_section_name: str, config: typing.Optional[dict] = None):
		self.Config = ConfigurableDict()

		for base_class in inspect.getmro(self.__class__):
			if not hasattr(base_class, 'ConfigDefaults'):
				continue
			if len(base_class.ConfigDefaults) == 0:
				continue

			# Merge config defaults of each base class in the 'inheritance' way
			for key, value in base_class.ConfigDefaults.items():

				if value is None:
					raise ValueError("None value not allowed in ConfigDefaults. Found in %s:%s " % (
						config_section_name, key))

				if key not in self.Config:
					self.Config[key] = value

		if Config.has_section(config_section_name):
			for key, value in Config.items(config_section_name):
				self.Config[key] = value

		if config is not None:
			self.Config.update(config)

asab.config.ConfigurableDict ¤

Bases: MutableMapping

A dictionary supplemented with custom methods for obtaining bools, seconds, urls etc.

Source code in asab/config.py
class ConfigurableDict(collections.abc.MutableMapping):
	"""
	A dictionary supplemented with custom methods for obtaining bools, seconds, urls etc.
	"""

	def __init__(self):
		self._data = {}

	def __getitem__(self, key):
		return self._data[key]

	def __setitem__(self, key, value):
		self._data[key] = value

	def __delitem__(self, key):
		del self._data[key]

	def __iter__(self):
		return iter(self._data)

	def __len__(self):
		return len(self._data)


	def getboolean(self, key) -> bool:
		"""
		Obtain the corresponding value of the key and convert it into bool.
		"""
		value = self._data[key]
		return utils.string_to_boolean(value)


	def getseconds(self, key) -> float:
		"""
		Obtain the corresponding value of the key and convert it into seconds via `convert_to_seconds()` method.
		"""
		value = self._data[key]
		return utils.convert_to_seconds(value)


	def getint(self, key) -> int:
		"""
		Obtain the corresponding value of the key and convert it into integer.
		"""
		value = self._data[key]
		return int(value)


	def getfloat(self, key) -> float:
		"""
		Obtain the corresponding value of the key and convert it into float.
		"""
		value = self._data[key]
		return float(value)


	def geturl(self, key, scheme):
		"""
		Obtain the corresponding value of the key and parse it via `validate_url()` method.
		"""
		value = self._data[key]
		return utils.validate_url(value, scheme)


	def __repr__(self):
		return "<%s %r>" % (self.__class__.__name__, self._data)

getboolean(key) ¤

Obtain the corresponding value of the key and convert it into bool.

Source code in asab/config.py
def getboolean(self, key) -> bool:
	"""
	Obtain the corresponding value of the key and convert it into bool.
	"""
	value = self._data[key]
	return utils.string_to_boolean(value)

getfloat(key) ¤

Obtain the corresponding value of the key and convert it into float.

Source code in asab/config.py
def getfloat(self, key) -> float:
	"""
	Obtain the corresponding value of the key and convert it into float.
	"""
	value = self._data[key]
	return float(value)

getint(key) ¤

Obtain the corresponding value of the key and convert it into integer.

Source code in asab/config.py
def getint(self, key) -> int:
	"""
	Obtain the corresponding value of the key and convert it into integer.
	"""
	value = self._data[key]
	return int(value)

getseconds(key) ¤

Obtain the corresponding value of the key and convert it into seconds via convert_to_seconds() method.

Source code in asab/config.py
def getseconds(self, key) -> float:
	"""
	Obtain the corresponding value of the key and convert it into seconds via `convert_to_seconds()` method.
	"""
	value = self._data[key]
	return utils.convert_to_seconds(value)

geturl(key, scheme) ¤

Obtain the corresponding value of the key and parse it via validate_url() method.

Source code in asab/config.py
def geturl(self, key, scheme):
	"""
	Obtain the corresponding value of the key and parse it via `validate_url()` method.
	"""
	value = self._data[key]
	return utils.validate_url(value, scheme)