Adding the configuration file
In this section, we are going to create the configuration file for our application; the configuration file will be in YAML format. If you would like to know more about YAML, you can check the site http://yaml.org/, where you will find examples, the specification, and also a list of libraries in different programming languages that can be used to manipulate YAML files.
For our application, we are going to use PyYAML, which will allow us to read and write YAML files in a very simple manner. Our configuration file is quite simple so we will not need to use any advanced features of the library, we just want to read the content and write, and the data that we are going to add is quite flat; we will not have any nested objects or lists of any kind.
Let's get the information that we obtained from Twitter when we created our app and add it to the configuration file. Create a file called config.yaml in the application's twittervotes directory with the following content:
consumer_key: '<replace with your consumer_key>'
consumer_secret: '<replace with your consumer secret>'
request_token_url: 'https://api.twitter.com/oauth/request_token'
authorize_url: 'https://api.twitter.com/oauth/authorize'
access_token_url: 'https://api.twitter.com/oauth/access_token'
api_version: '1.1'
search_endpoint: 'https://api.twitter.com/1.1/search/tweets.json'
Great! Now we are going to create the first Python code in our project. If you have followed the previous chapters, the functions to read the configuration file will be familiar to you. The idea is simple: we are going to read the configuration file, parse it, and create a model that we can easily use to access the data we added to the config. First, we need to create the configuration model.
Create a file called models.py in twittervotes/core/models/ with the following content:
from collections import namedtuple
Config = namedtuple('Config', ['consumer_key',
'consumer_secret',
'request_token_url',
'access_token_url',
'authorize_url',
'api_version',
'search_endpoint', ])
There was a more extensive introduction to namedtuple in the previous chapter, so I will not go into as much detail about it again; if you haven't been going through the second chapter, it will suffice to know that namedtuple is a kind of class and this code will define a namedtuple called Config with the fields specified in the array in the second argument.
Great, now let's create another file called __init__.py in twittervotes/core/models and import the namedtuple that we just created:
from .models import Config
Now it is time to create the functions that will do the actual work of reading the YAML file and returning it to us. Create a file called config.py in twittervotes/core/. Let's get started by adding the import statements:
import os
import yaml
from .models import Config
We are going to use the os package to easily obtain the user's current directory and manipulate paths. We also import PyYAML so we can read the YAML files and, lastly, from the models module, we import the Config model that we just created.
Then we define two functions, starting with the _read_yaml_file function. This function gets two arguments—the filename, which is the name of the config file that we want to read, and also cls, which can be a class or namedtuple that we will use to store the configuration data.
In this case, we are going to pass the Config—namedtuple, which has the same properties as the YAML configuration file that we are going to read:
def _read_yaml_file(filename, cls):
core_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(core_dir, '..', filename)
with open(file_path, mode='r', encoding='UTF-8') as file:
config = yaml.load(file)
return cls(**config)
First, we use the os.path.abspath function, passing as an argument the special variable __file__. When a module is loaded, the variable __file__ will be set to the same name as the module. That will allow us to easily find where to load the configuration file. So the following snippet will return the path of the core module
/projects/twittervotes/core:
core_dir = os.path.dirname(os.path.abspath(__file__)) will return
We know that the configuration file will live in /projects/twittervotes/ so we need to join .. to the path to go up one level in the directory structure so we can read the file. That's why we build the complete configuration file's path as follows:
file_path = os.path.join(core_dir, '..', filename)
That will give us the flexibility of running this code from any location in our system.
We open the file in the reading mode using UTF-8 encoding and pass it to the yaml.load function, assigning the results to the config variable. The config variable will be a dictionary with all the data we have in the config file.
The last line of this function is the interesting part: if you recall, the cls argument was a class or a namedtuple so we spread the values of the config dictionary as an argument. Here, we are going to use the Config—namedtuple so cls(**config) is the same as Config, (**config) and passing the arguments with ** will be the same as passing all the arguments one by one:
Config(
consumer_key: ''
consumer_secret: ''
app_only_auth: 'https://api.twitter.com/oauth2/token'
request_token_url: 'https://api.twitter.com/oauth/request_token'
authorize_url: 'https://api.twitter.com/oauth/authorize'
access_token_url: 'https://api.twitter.com/oauth/access_token'
api_version: '1.1'
search_endpoint: '')
Now we are going to add the second function we are going to need, the read_config function:
def read_config():
try:
return _read_yaml_file('config.yaml', Config)
except IOError as e:
print(""" Error: couldn\'t file the configuration file
`config.yaml`
'on your current directory.
Default format is:',
consumer_key: 'your_consumer_key'
consumer_secret: 'your_consumer_secret'
request_token_url:
'https://api.twitter.com/oauth/request_token'
access_token_url:
'https://api.twitter.com/oauth/access_token'
authorize_url: 'https://api.twitter.com/oauth/authorize'
api_version: '1.1'
search_endpoint: ''
""")
raise
This function is pretty straightforward; it just makes use of the _read_yaml_file function that we just created, passing the config.yaml file in the first argument and also the Config, namedtuple in the second argument.
We catch the IOError exception that will be thrown if the file doesn't exist in the application's directory; in that case, we throw a help message showing the users of your application how the config file should be structured.
The final touch is to import it into the __init__.py in the twittervotes/core directory:
from .config import read_config
Let's try this out in the Python REPL:
Great, it worked just like we wanted! In the next section, we can start creating the code that will perform the authentication.