Table of contents
1.
Introduction
2.
Configuration in Bottle
3.
Configuration Basics
4.
Naming Convention
5.
Loading Configuration from a File
6.
Loading Configuration from a Python Module
7.
Loading Configuration from a Nested DICT
8.
Listening to Configuration Changes
9.
Filters and other Metadata
10.
API DOCUMENTATION
11.
Frequently Asked Questions
11.1.
Is Bottle an MVC framework?
11.2.
How do you run Python bottles?
11.3.
Is Flask better than a bottle?
11.4.
What is Django and the Bottle?
11.5.
What is Falcon for Python?
12.
Conclusion
Last Updated: Mar 27, 2024
Medium

Configuration Basics in the Bottle Web Framework

Author yuvatimankar
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

The bottle is a python micro-framework by which you can build the rest API in minutes. It is distributed as a single file module with only Python Standard Library dependency. Bottle helps in creating web development fastly and easily. 

Bottle Framework

The bottle consists of some terms which are as follows:

💥Templates: Bottle has a Pythonic and a fast built-in template engine and support for jinja2, mako, and cheetah templates.

💥 Routing: It requests function-call mapping with support for dynamic and clean URLs.

💥 Server: Bottle has a built-in HTTP development server, and it supports gae,bjoern, paste,cherypy, or other WSGI-capable HTTP servers.

💥 Utilities: Suitable access to form data, file uploads, headers, cookies, and other HTTP-related metadata.

Configuration in Bottle

Bottle applications can keep their configuration in Bottle.config, a dictionary-like object and central place for application-specific settings. This dictionary controls many features of the framework, tells plugins what to do, and can be used to keep(store) our configuration.

Configuration Basics

The Bottle.config object acts a lot like an ordinary dictionary. All the common dictionary methods work as expected. 

Configuration Basics

For example:

import bottle
app = bottle.default_app()             # or bottle.Bottle() if you prefer
app.config['autojson']    = False      # Turns off the "autojson" feature
app.config['sqlite.db']   = ':memory:' # Tells the sqlite plugin which db to use
app.config['myapp.param'] = 'value'    # Example for a custom config value.
# Change many values at once
app.config.update({
    'autojson': False,
    'sqlite.db': ':memory:',
    'myapp.param': 'value'
})
# Add default values
app.config.setdefault('myapp.param2', 'some default')
# Receive values
param  = app.config['myapp.param']
param2 = app.config.get('myapp.param2', 'fallback value')
# An example route using configuration values
@app.route('/about', view='about.rst')
def about():
    email = app.config.get('my.email', 'nomail@example.com')
    return {'email': email}
You can also try this code with Online Python Compiler
Run Code

 

The app object is not always accessible, but as long as we are in a request context, we can cause the request object to obtain the current application and also its configuration:

from bottle import request
def is_admin(user):
    return user == request.app.config['myapp.admin_user']
You can also try this code with Online Python Compiler
Run Code

Naming Convention

Naming conventions

For making life easier, applications and plugins should follow some rules when it comes to configuration parameter names:

📌 All keys must be lowercase strings and follow all the rules for python identifiers (don't use special characters but can only use underscore)

📌 Namespaces should be separated by dots (e.g., namespace.fieldname)

📌 Root namespace is used by the Bottle for its configuration. Plugins should contain all their variables in their namespace(e.g sqlite.db)

📌 Own own application should use a distinct namespace.

Loading Configuration from a File

Loading Configuration from a file

Configuration files are helpful if we want to enable non-programmers to configure our application or if we just don't want to hack python modules to change the database port. Familiar syntax for the configuration files is shown below:

[sqlite]
db = /tmp/test.db
commit = auto
[myapp]
admin_user = defnull
You can also try this code with Online Python Compiler
Run Code

 

With configDict.load_config() we can load these *.ini style configuration files disk and also import the values into our existing configuration:

app.config.load_config('/etc/myapp.conf')
You can also try this code with Online Python Compiler
Run Code

Loading Configuration from a Python Module

Loading Configuration

For a python programmer, loading configuration from a Python module is a usual pattern. Bottle framework assumes that configuration keys are all UpperCase:

We can load this Python module with met:’ConfigDict.load_module’:

>>> c = ConfigDict()
>>> c.load_module('config')
{DEBUG: True, 'SQLITE.DB': 'memory'}
>>> c.load_module("config", False)
{'DEBUG': True, 'SQLITE': {'DB': 'memory'}}
You can also try this code with Online Python Compiler
Run Code


Do not forget to note the second parameter to disable loading as namespaced items in configDict.load_dict(). Loading from a python module will call this method by default unless you individually call this method with False as the second argument.

Loading Configuration from a Nested DICT

Another helpful method is configDict.load_dict(). This method takes the whole structure of nested dictionaries and transforms it into a flat list of keys and values with namespaced keys:

# Load an entire dict structure
app.config.load_dict({
    'autojson': False,
    'sqlite': { 'db': ':memory:' },
    'myapp': {
        'param': 'value',
        'param2': 'value2'
    }
})
assert app.config['myapp.param'] == 'value'
# Load configuration from a json file
with open('/etc/myapp.json') as fp:
    app.config.load_dict(json.load(fp))
You can also try this code with Online Python Compiler
Run Code

Listening to Configuration Changes

Configuration changes

The config hook on the application object is activated every time a value in Bottle.config is changed. At runtime, this hook can be used to act on configuration changes, for example connecting a new database, changing the debug settings on a background service, or changing the size of worker thread pools. The hook callback receives two arguments, key and new_value, and is called before the value is changed in the dictionary. If we raise an exception from a hook, callback change is prevented, and the old value is preserved.

Following is the example:

@app.hook('config')
def on_config_change(key, value):
  if key == 'debug':
      switch_own_debug_mode_to(value)
You can also try this code with Online Python Compiler
Run Code


The value cannot be changed by the hook callbacks that are to be stored in the dictionary. Because of that, we use filters.

Filters and other Metadata

Filters and Metadata

configDict allows you to contain metadata along with configuration keys. Two fields are defined as follows:

  • help: A help string, also known as a description string, can be used by introspection, debugging, or admin tools to help maintainers of the site configure their application.
  • filter: A filter is a callable that accepts and returns a single value. If we define a filter for a key, a new value stored in that key is first passed through the filter callback. The filter can be useful to cast the value to a different type, check for invalid values, or activate (trigger) side effects.

 

This feature is most helpful for plugins. They can authenticate their configuration parameters or can trigger side effects with the help of filters and document their configuration via help fields:

class SomePlugin(object):
    def setup(app):
        app.config.meta_set('some.int', 'filter', int)
        app.config.meta_set('some.list', 'filter',
            lambda val: str(val).split(';'))
        app.config.meta_set('some.list', 'help',
            'A semicolon-separated list.')

 def apply(self, callback, route):
        ...
import bottle
app = bottle.default_app()
app.install(SomePlugin())
app.config['some.list'] = 'a;b;c'     # Actually stores ['a', 'b', 'c']
app.config['some.int'] = 'not an int' # raises ValueError
You can also try this code with Online Python Compiler
Run Code

API DOCUMENTATION

API Documentation

🗒 class ConfigDict: A dictionary-like configuration storage with extra support for validators, namespaces,meta-data, overlays, and more. This dictionary-like class is highly optimized for reading access. All the read-only methods and item access should be done as fast as the built-in dictionary..

✍️ load_module(path, squash=True):

Below is the example of config.py:

DEBUG = True
SQLITE = {
    "db": ":memory:"
}
>>> c = ConfigDict()
>>> c.load_module('config')
{DEBUG: True, 'SQLITE.DB': 'memory'}
>>> c.load_module("config", False)
{'DEBUG': True, 'SQLITE': {'DB': 'memory'}}
You can also try this code with Online Python Compiler
Run Code

 

  • Squash:  If it is default i.e. True, dict values are supposed to represent namespaces 
  • Source


✍️ load_config(filename, **options):       

Thus Load values from a *.ini style configuration file.

A config file has sections; each section is led by a [section] header, followed by key or value entries separated by either: or =.  

  • The names and keys section are case sensitive. 
  • From the keys and values section leading and trailing whitespaces is removed.
  • Commands are prefixed by or # and only appear on their own.
  • Both key names and sections may consist of dots(.) as namespace separators.
  • The true configuration parameter name is constructed by appending the section name and key name together and converting them to lower case.
  • BOTTLE and ROOT are special sections. These sections refer to the root namespace, and the DEFAULT section decides default values for all other sections.
  • Now with Python 3, extended string interpolation is possible.
  • filename:  A list of paths or the path of a config file.
  • options: Every keyword parameter is passed to the configparser.ConfigParser constructor call.
  • Source 


✍️ local dict(source, namespace=”)

 It loads values from the dictionary structure. Also, nesting can be helpful for representing namespace.

>>> c = ConfigDict()
>>> c.load_dict({'some': {'namespace': {'key': 'value'} } })
{'some.namespace.key': 'value'}
You can also try this code with Online Python Compiler
Run Code

 

✍️update(*a, **ka)

 With this namespace, all keys are prefixed if the starting parameter is a string. In addition, it works similar to the usual dict.update().

>>> c = ConfigDict()
>>> c.update('some.namespace', key='value')
You can also try this code with Online Python Compiler
Run Code

 

✍️meta_get(key,metafield, default=None)

It returns the value of a key or a meta field.

 

✍️ meta_set(key, metafield, value)

It sets the meta field for a key to a new value.

 

✍️ meta_list(key)

This returns an iterable of the meta field names defined for a key.

Frequently Asked Questions

Is Bottle an MVC framework?

Similar to most frameworks, Bottle uses an MVC software paradigm. Model, View, and Controller, or MVC, is an acronym for the choice to divide a user interface's various functions.

How do you run Python bottles?

Go to http://localhost:8080/ in your browser after running the script or pasting it into a Python console. Use pip install bottle to install the most recent stable version, or download bottle.py (unstable) and place it in your project directory.

Is Flask better than a bottle?

Bottle and Flask are both extensively used as Python's backend web frameworks. In any case, Flask is thought to be more effective, so programmers frequently select it over Bottle.

What is Django and the Bottle?

Model-template-view (MTV) is the basis for its design. It includes many tools that application developers require, including an ORM framework, admin panel, directory structure, and more.

What is Falcon for Python?

Falcon is a dependable, high-performance Python web framework for creating microservices and the backends of large-scale applications. It supports the REST architectural movement and strives to be as efficient as possible by doing the bare minimum.

Conclusion

This article discussed the bottle framework and Configuration Bottle Framework. We started with introducing the bottle framework, and then we saw the Configuration Basics, Naming convention, Loading configuration from a file, Loading configuration from python module, Loading configuration from a nested DICT, Listening to configuration changes, Filters, and other Metadata and API documentation.

To learn more about  Bottle Web Framework, see Bottle DocumentationBottleand Python Frameworks.

Also check out - Data Dictionary In Software Engineering.

Refer to our guided paths on Coding Ninjas Studio to learn more about DSA, Competitive Programming, JavaScript, System Design, etc. Enroll in our courses, refer to the mock test and problems; look at the interview experiences and interview bundle for placement preparations.

Do upvote our blogs if you find them helpful and engaging!

Happy Learning, Ninjas!

Thankyou
Live masterclass