1

I have a small python application (about 6000 loc), where I keep my settings in a seperate module, settings.py. As the application grew, I started to add tests. Now after having more and more tests, and trying to test with different settings, I find that the module approach was not such a great idea, as its not very flexible - I always have to reason about where and when settings.py gets imported, so that I do my modifications at the right place etc.

Now I have a new approach, which still uses the settings.py, but it will get imported only once, and turned into an config object that I can pass around and modify locally without affecting anything else. I could now have different versions of settings.py, the config object constructor takes a filename as an optional argument. So I think I am better prepared for my testing.

Now comes the refactoring, and bevor I dive into it, I would like to get a second (or third ;)) opinion on how to tackle the refactoring. Here is my idea:

  1. All functions and methods that use the settings module get a keyword argument for a settings module (settings=None).
  2. Decorate all these functions with a decorator that injects the settings object if its not given by the original caller. Also, warn about the injection, so that I am aware of where I need to modify the call.

At this point, I should still have working code, and can start hunting for the callers. Also, step 1 and 2 could be done by a script, to reduce the tedium. Once I have removed all warnings by correcting the calls, I can remove the decorator.

In this way, in my thinking, I never have a state were I need to change a lot of things at once to have working code, thus having a smooth journey.

Does that sound like a reasonable approach? Or am i overthinking this? Or miss any important points?

  • 1
    why not use: pythonhosted.org/ConfigObject – Urban48 Dec 1 '16 at 9:20
  • That looks nice - however it does not do the refactoring itself ;) So I still need to refactor somehow. Since no one has objected to my above plan I assume that its at least not completely stupid. – Isaac Dec 1 '16 at 10:31
1

Personally I wouldn't do either option and just have each module/file to instantiate your Config object at import time.

So in most of your code your going to be replacing:

Import config

With:

from configuration import Config
config = Config()

You can then use the object in exactly the same way you did the module.

This will get you a separate Config object without having to modify every function in your app, frees you from global config and allows you to easily patch the config of module your testing without it affecting the config of your imports.

That's going to be easy to do and might by as deep as you need to go.

  • "That's going to be easy to do and might by as deep as you need to go." Exactly. I had the feeling I was making things more complicated then nessessary, but did not see the easy solution. Cheers! – Isaac Dec 8 '16 at 10:59
  • Isn't this solution prone to race conditions? – user857990 Dec 8 '16 at 11:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.