Python: Config Variables



  • I want to have a config file for the usual things, API keys, db connections etc.

    Before now, I have been just importing another python file with my vars set in the file. Is this an acceptable way of doing it?

    I done some googling and there are some other options but for the size of the project I am building are total overkill.

    Suggestions welcome.



  • Seems simple enough to me. You could use text/XML files but then you'd have to add parsing code too. Your method just works.


  • FoxDev

    for small to medium projects i have no real issue with that.

    of course if your target is anyone other than techies and ed users then that's probably not a good idea... ;-)



  • I believe YAML is kind of the "industry standard" in this environment. It's a INI-like file, and there's an easy-to-use PyYAML library you can use to read from it.



  • This is an example project to show code to potential employers, I am fed up of being given "coding challenges" which are fooking boring to build and take up a lot of my free time. I rather work on something I like doing and then say look "here is my github account ... take a look at my demo apps".



  • I will check it out.


  • FoxDev

    oh in that case... i'd say do a super simple parsing of an external file.

    doing JSON in Python's always been fairly painless. you don't have to all out on the parsing/validating, just show that you are familiar with it and understand some best practices (like: no touchy my code unless you is developer!!)

    Edit: that's the second time today i've caught me doing that spelling error!



  • Oh! That's not gonna work. Been there, done that, and it always ends up the same way.

    Anyway, Python has good support for .ini files with ConfigParser

    Here's some code I wrote 5 years ago as my first take with Python (which still works, so it wasn't that bad)



  • I think I will just do the simple config file for now. The PyYAML stuff that @blakeyrat mentioned looks fairly straightforward after looking at a few examples.



  • I will check that out too.

    I've done the odd small REST service or similar using python for internal stuff so nothing that seen the outside world. I wanna have some solid examples of the code I produce for my next gig.



  • @lucas said:

    Before now, I have been just importing another python file with my vars set in the file. Is this an acceptable way of doing it?

    Watch our for feature creep. If the values ever become user-settable, this will become a code-injection vector.



  • I was worried about that. TBH It is a readonly Soccer website I am building with a Flask. I am thinking you mean user in the sense of someone running the code instead of someone using the website?


  • đźš˝ Regular

    I second the vote for ConfigParser. Although when I used it years ago the decision of using .ini files had already been taken, it was extremely straightforward to use and I'd use it again.

    Other than that, maybe this helps? http://lybniz2.sourceforge.net/safeeval.html
    I haven't tried it myself, frankly, but it looks good. There an execfile builtin which could be used similarly.

    Edit: ok, I should have gone to bed already, so this may or may not make sense, but to elaborate on the execfile thing, my idea is that you set as the environment for execfile a single config object implementing __setattr__ so you can have a sandbox with sane defaults and validation.



  • nothing wrong with simple config class for a small projects and simple configuration.

    class Config(object):
        @staticmethod
        def db():
             return {"user":"user1", "pass":"1234"}
        def facebook():
             return {'api_key':'ABCDEF'}
        @staticmethod
        def get(key,set):
            return getattr(Config,set)()[key]
    
    
    
    print(Config.get("user","db"))   # user1
    print(Config.get("api_key","facebook"))   # ABCDEF
    
    

  • FoxDev

    @Monarch said:

    ```
    class Config(object):
    @staticmethod
    def db():
    return {"user":"user1", "pass":"1234"}
    @staticmethod
    def facebook():
    return {'api_key':'ABCDEF'}
    @staticmethod
    def get(key,set):
    return getattr(Config,set)()[key]

    print(Config.get("user","db")) # user1
    print(Config.get("api_key","facebook")) # ABCDEF

    
    i think you were missing an @staticmethod there...
    
    actually i'm pretty sure but i'm not going to bother SSHing to the linux box to check... sorry?


  • what do you mean? missed?

    Edit: oh, I see know, good observation. it worked for me, and now I see that it works without any @staticmethod decorator at all

    python 3 ... Works
    python 2 ... Doesn't

    class Config(object):
      
        def db():
             return {"user":"user1", "pass":"1234"}
    
        def facebook():
             return {'api_key':'ABCDEF'}
    
        def get(key,set):
            return getattr(Config,set)()[key]
    
    
    print(Config.get("user","db"))   # user1
    print(Config.get("api_key","facebook"))   # ABCDEF
    

    ps
    I find this website pretty useful, when not feeling like ssh to a linux box

    http://www.compileonline.com/execute_python3_online.php


  • Java Dev

    @Monarch said:

    print(Config.get("user","db")) # user1

    That reads like backward argument order.



  • @lucas said:

    I am thinking you mean user in the sense of someone running the code instead of someone using the website?

    I mean users, that's why I mentioned feature creep. V1 of the site allows you to configure something in the file, V2 allows the user to configure it. The easiest (and worst) way to implement V2 is to write the user input to the config file.


  • FoxDev

    Not so much really

    [spoiler]
    here's the call but a little clearer:
    python Config.get("key","default_value")
    [/spoiler]

    nevermind, on rereading it it seems very much a backwards argument order.

    7 edits in, i give up.... you can figure out what i was trying to do...


  • Discourse touched me in a no-no place

    @accalia said:

    you can figure out what i was trying to do...

    Are you sure? Because it seems like you can't!


  • FoxDev

    yeah well.... i'm only on my third cuppa tea.... gimme time.


  • Discourse touched me in a no-no place

    @accalia said:

    only on my third cuppa tea

    1. Well, there's your problem.
    2. I mentioned this a while ago--there's a perfect line here, but I can't find the video. It's the Ripped Pants episode of SpongeBob, where after he pretends to be dead, a surfer dude looks at him and sadly says "dude" and walks away. I might need to record the damn line myself and put it on YT.

  • FoxDev

    @FrostCat said:

    I mentioned this a while ago--there's a perfect line here, but I can't find the video. It's the Ripped Pants episode of SpongeBob, where after he pretends to be dead, a surfer dude looks at him and sadly says "dude" and walks away. I might need to record the damn line myself and put it on YT.

    1. i'd watch/listen to it.

    2. is this about me preferring tea over coffee, or about the amounts of tea i require to get my morning buzz (i know, i really should cut the stuff out for a week or so to reset my sensitivity, butt* here's so much coding to be done!)

    * i think i'll keep that typo


  • Discourse touched me in a no-no place

    @accalia said:

    is this about me preferring tea over coffee, or about the amounts of tea i require to get my morning buzz

    Yes. Although I don't like either, so you can put the first fork down to kibitzing.


  • FoxDev

    hmm... fair enough. Coffee is nice, but i've had too many places mess it up royally so it really does taste like poo in a cup.. and even if i make it there is still the risk of a bad batch, and when a bad batch is that bad..... nto worth it.

    Tea is much harder to mess up, and is even easier on the digestion thanks to all those antiopxidants (the tanic acid can be an issue though)

    and i really should detox and reset my sensitivity.... but as i said there's programming to be done!


  • Discourse touched me in a no-no place

    @accalia said:

    and i really should detox and reset my sensitivity.... but as i said there's programming to be done!

    I would much rather not be beholden to caffeine; I find I don't have a problem programming without it in my system, plus I sleep better.

    It's just that I like the taste of soda.


  • FoxDev

    @FrostCat said:

    It's just that I like the taste of soda.tea.

    ditto (with a small edit)



  • I need to detox but I would be non-functional at work during the process.

    I've actually had health complications in the past from caffeine, and overall I function much better without. But eventually I get a few days in a row where I don't sleep well and need coffee/Mountain Dew in the mornings to get me going, and blam I'm addicted again.


  • Discourse touched me in a no-no place

    @mott555 said:

    I need to detox but I would be non-functional at work during the process.

    The only problem I ever had is a headache that lasts a day or so, and Tylenol's always been enough to take care of that.

    If I go to sleep at a reasonable time I get enough sleep that I don't need it in the mornings to wake up. I went about 3 years without caffeine, and then started again, and I haven't summoned up the willpower to make myself stop.



  • It's much worse for me. Headaches, really irritable, unable to focus, lack of energy. If I don't have to work I can get through it but I have to be able to sleep in and take an afternoon nap too.

    I tried to detox back in June when some friends and I went camping in the Rockies, but by day three I was feeling awful. Caffeine withdrawal and altitude (campsite was around 10,000 feet) didn't mix for me. I chugged a couple cans of Mountain Dew and felt relatively normal within a couple hours.


  • Discourse touched me in a no-no place

    @accalia said:

    so it really does taste like poo in a cup..

    Which is actually quite nice.


  • FoxDev


  • Discourse touched me in a no-no place

    I bought some last year - it's quite expensive (for coffee) but it's good. It's not good enough to justify the cost over normal coffee though.


  • Discourse touched me in a no-no place

    @mott555 said:

    I've actually had health complications in the past from caffeine, and overall I function much better without.

    I can manage just fine on one not particularly large cup of coffee per day. Some days I'll drink a lot of it, but most days I keep the quantity down. If I'm on my 5th by lunchtime, either it's one of those days or I'm at a conference. Conference venues don't seem to understand just how much coffee a room of programmers really can drink…

    I'm so picky about the tea I drink that I'm functionally not a tea drinker.



  • You are right it wasn't very intuitive, switching the order make more sense

    class Config(object):
      
        def db():
             return {"user":"user1", "pass":"1234"}
        def facebook():
             return {'api_key':'ABCDEF'}
       
        def get(source, key=None, default=None):
            if hasattr(Config,source):
                source_dict = getattr(Config,source)()
                if key == None:
                    return source_dict
                elif key in source_dict:
                    return source_dict[key]
            return default
    
        def getPath(src,default=None):
            a = src.split(".")
            current_key = a.pop(0)
            current_pointer = None
            if hasattr(Config,current_key):
                current_pointer = getattr(Config,current_key)()
                for i in a:
                    if i in current_pointer:
                        current_pointer = current_pointer[i]
                    else:
                        return default #path not found 
                return current_pointer
            return default
    
    
    
    print(Config.get("db","user"))          # db.user => user1
    print(Config.get("facebook","api_key")) # facebook.api_key => ABCDEF
    print(Config.get("nonexists4","api_key",default = "$"))   #  $ 
    print(Config.get("facebook"))           # facebook => {'api_key': 'ABCDEF'}
    
    #By path
    
    print(Config.getPath("db.user",444))       # user1
    print(Config.getPath("db.user.errr",444))  # 444
    print(Config.getPath("db"))                # {'api_key': 'ABCDEF'}
    
    

Log in to reply