Source code for adapya.base.jconfig

"""
jconfig - Manage configuration data in a JSON file
==================================================

The default file name is .ztools located in the USERPROFILE/APPDATA/HOME directory.

"""
from __future__ import print_function          # PY3
import os
import json
from adapya.base import xtea
from adapya.base.xtea import fromhex, tohex    # PY3

debug = 0
withkeyring = 1  # set to 1 if to use keyring

if withkeyring:
    # check that keyring package is installed
    try:
        # If keyring is installed we try to get/set passwords in a save place.
        # On Windows this is Windows Credential Locker
        # Script keyring [get|set|del] service user
        # e.g. for ftpz set service = host-name
        import keyring
        if debug: print('keyring is installed')
    except:
        withkeyring = 0


#: indicator to request display of the settings in getparms() and setparms()
SHOWCONFIG=1

#: default config file name
CFGFN = '.ztools'

tostr = lambda s: s if type(s) == type('') else s.encode('latin1') # convert from unicode for PY2

# D:\Users\mm or D:\Users\mm\AppData\Roaming
cfgpath = os.environ.get('USERPROFILE','') or \
          os.environ.get('APPDATA','') or \
          os.environ.get('HOME','')
fullname = lambda fn: os.path.abspath(os.path.join(cfgpath,fn))

iv = 'ABCDEFGH'
ckey = '0123456789012345'

def crypt(string):
    global iv, ckey
    return xtea.crypt(ckey,string,iv)

[docs]def get(name, cf=CFGFN): """ get subject from config JSON file :param name: subject dictionary :param cf: config file name """ try: fp = open(fullname(cf),'r') toolsdict = json.load(fp) return toolsdict.get(name,'') fp.close() except IOError as e: # [Errno 2] No such file or directory: '.ztools' # [Errno 129] No such file or directory: '.ztools' / USS if str(e).startswith('[Errno 2]') or str(e).startswith('[Errno 129]'): return None else: raise
[docs]def set(name, value, cf=CFGFN): """ set subject in config JSON file :param name: subject dictionary :param cf: config file name """ try: fp = open(fullname(cf),'r') toolsdict = json.load(fp) fp.close() except IOError as e: # [Errno 2] No such file or directory: '.ztools' # [Errno 129] EDC5129I No such file or directory.: '.ztools' / USS if not str(e).startswith('[Errno 2]') and not str(e).startswith('[Errno 129]'): raise # file does not exist toolsdict={} except ValueError as e: print( "Ignoring error accessing configuration file: %s" % fullname) print( str(e)) # has no configuration dictionary yet toolsdict={} fp = open(fullname(cf),'w') toolsdict[name]=value json.dump(toolsdict,fp) fp.close()
[docs]def getparms(subject, show, cf=CFGFN, **parms): """ get for a subject configuration data unless provided by parameter values in parms :param subject: select parameters by subject e.g. 'ftp' :param parms: parameters that are requested :param show: if > 0: print parameters >>> setparms('ftp',False,cf='.test',host='big',password='secret',user='hugo') >>> getparms('ftp',False,cf='.test',host='',password='',user='') {'host': 'big', 'password': 'secret', 'user': 'hugo'} """ cfg = get(subject) or {} # print('cfg=',cfg) if cfg: # non-empty subject if parms: for k, v in parms.items(): if not v: # try to fill empty value for k with config vcfg = cfg.get(k,v) if k in ('pwd','password'): # crypted binary data if withkeyring: # keyring support for passwords # try to get user/host from parms as fallback from cfg kuser = parms.get('user',tostr(cfg.get('user',''))) khost = parms.get('host',tostr(cfg.get('host',''))) if khost and kuser: # used as parameter service,user for keyring vcfg = keyring.get_password(khost,kuser) if debug: print( '\nKeyring: service=%s, user=%s, password=%s' % (khost,kuser,vcfg)) elif vcfg: if debug: print(repr(vcfg)) vcfg = crypt( fromhex( vcfg )) if debug: print(repr(vcfg)) if vcfg: parms[k] = tostr(vcfg) if show: print( "The following configuration is stored in %r for %r:" % (cf, subject)) for k, t in parms.items(): if k in ('pwd', 'password') and not debug: t='*password*' print( '%15s: %s' % (k,t)) return parms
[docs]def setparms(subject, show, cf=CFGFN, **parms): """Set configuration parameters for a subject :param subject: select parameters by subject e.g. 'ftp' :param parms: parameter that should be set If the value of a parameter is None it is ignored. This simplifies setting up call: no dynamic creation of parms dictionary needed. :param show: if True print parameters >>> setparms('ftp',True,cf='.test',user='Anna',password='H2o',host='mojave') The following configuration is stored in '.test' for 'ftp': host: mojave password: *password* user: Anna """ cfg = get(subject) or {} if show: print( "\nThe following configuration is stored in %r for %r:" % (cf,subject)) for k, v in sorted(parms.items()): if v == None: # skip this parameter continue if k == 'cf': continue # skip configuration file name if k in ('pwd','password'): if withkeyring: # keyring support for passwords: user and host are keys to store password # if not passed as parameter: try to get it from stored configuration kuser = parms.get('user') if kuser == None: kuser = tostr(cfg.get('user','')) khost = parms.get('host') if khost == None: khost = tostr(cfg.get('host','')) if debug: print('password %s %s %r' % (khost, kuser, v)) if khost and kuser: # used as parameter service,user for keyring if v: keyring.set_password(khost,kuser,v) if debug: print('Password set in keyring: %s %s %s' % (khost, kuser, repr(v) if debug else '*password*')) else: # might be '' but not None try: keyring.delete_password(khost,kuser) if debug: print('Password deleted in keyring: %s %s' % (khost, kuser)) except: pass if show: print( '%15s: %s on keyring(service=%s, user=%s)' % (k, v if debug else '*password*', khost,kuser)) v = '' # reset in cfg else: v = tohex(crypt(v)) if show: print( '%15s: %s' % (k, v if debug else '*password*' )) else: if show: print( '%15s: %s' % (k,v)) if v == "''": cfg.pop(k,'') # remove value if stored else: cfg[k]=v set(subject,cfg)
if __name__ == "__main__": import doctest doctest.testmod()