-
Notifications
You must be signed in to change notification settings - Fork 0
Custom Configuration
In the configuration section we touched briefly on the concept of adding your own custom configuration section. In this section we will expand on that idea and provide a sample custom configuration object.
We learned in the configuration section that in order to declare a custom configuration section, at a minimum, we need to add the following into our crazyhorse.config:
{
"custom_sections":
[
{"name":"social", "type":"myapp.configuration.social.SocialSection", "notes":"Will be available as CUSTOM_SOCIAL"}
],
}When CreazyHorse reads the crazyhorse.config file at startup, it will initialize our SocialSection object and assign it to:
crazyhorse.configuration.manager.Configuration.CUSTOM_SOCIALRemember, it will always be assigned with the prefix CUSTOM_. Additionaly, if we give it a name with hyphens, social-configuration those hyphens will be converted to underscores. Thus, our assignment would be:
crazyhorse.configuration.manager.Configuration.CUSTOM_SOCIAL_CONFIGURATION
Now that we know where it goes after it's initialized, what are the rules for making one?
There are 3 rules when creating a custom configuration handler:
- It MUST be a class
- It MUST be callable
- It MUST extend crazyhorse.configuration.sections.ConfigurationSection
With those 3 rules in mind, and assuming we are building our handler for the section we defined above, lets see what a basic configuration handler looks like.
from crazyhorse.configuration.sections import ConfigurationSection
class SocialSection(ConfigurationSection):
def __init__(self):
self.dog = "Lucy"
self.cat = "Ollie"
def __call__(self):
return selfNote that __call__ returns self. You can return anything you like here, it does not have to be self. Whatever is returned from __call__ is what will be set in:
crazyhorse.configuration.manager.Configuration.CUSTOM_SOCIALWithin our application then I would be able to do this:
from crazyhorse.configuration.manager import Configuration
Configuration.CUSTOM_SOCIAL.dog # Lucy
Configuration.CUSTOM_SOCIAL.cat # OllieThat's all well and good, but what if we would like our values for dog and cat to be defined in our crazyhorse.config. No problem, lets see how that might look.
First, we need to amend our crazyhorse.config and include a section with the name we defined in our custom_sections collection.
{
"custom_sections":
[
{"name":"social", "type":"myapp.configuration.social.SocialSection", "notes":"Will be available as CUSTOM_SOCIAL"}
],
"social":
{
"dog":"Lucy the Dog",
"cat":"Ollie the Cat"
}
}Note that in our custom_section collection we defined the name attribute to "social". Consequently, we also placed a corresponding JSON section named "social".
CrazyHorse will now attempt to hand off that "social" section via a call to an instance of myapp.configuration.social.SocialSection. Since our custom handler is going to be called with an additional argument, the decoded JSON section, we need to update our class a bit:
from crazyhorse.configuration.sections import ConfigurationSection
class SocialSection(ConfigurationSection):
def __init__(self):
self.dog = None
self.cat = None
def __call__(self, section):
self.dog = section["dog"]
self.cat = section["cat"]
return selfTake a look at what changed.
First, we set our 2 instance variables to None, as we will be receiving those values from from the crazyhorse.config
Next, we altered the signature of __call__(self) to __call__(self, section). Section represents the decoded JSON section from the crazyhorse.config
Finally, we set our two instance variables to the values from the section that was passed in. We still return self here.
Thus, calling the values from this configuration section would look like this:
from crazyhorse.configuration.manager import Configuration
Configuration.CUSTOM_SOCIAL.dog # Lucy the Dog
Configuration.CUSTOM_SOCIAL.cat # Ollie the CatWe use the result of __call__ instead of just blindly setting your handler class as it gives you the opportunity to store any kind of object you like.
In our second example, we could have simply returned the decoded JSON section we were handed. That would have turned our access sample above into this:
from crazyhorse.configuration.manager import Configuration
Configuration.CUSTOM_SOCIAL["dog"] # Lucy the Dog
Configuration.CUSTOM_SOCIAL["cat"] # Ollie the CatWe could also decide to return a string, or another kind of object entirely. The point is, the handler gets to decide what the result should be.