Source code for httk.config.config

#
#    The high-throughput toolkit (httk)
#    Copyright (C) 2012-2015 Rickard Armiento
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""
Read and setup httk configuration and versioning data.

httk_python_root is derived as the directory config.py is in + ..

config is a configparser.config object where:

- All assignments in a distdata.py file in httk_python_root are read into the section [general]
- Read httk.cfg in httk_python_root
- Using the latest definition of [general]/httk_root, read httk.cfg in that directory
- Read ~/.httk/config

In this config object, the section [general] is looked up for 'httk_root', which is exported as httk_root. If not present, 'root' is looked up in
the section 'distdata'. If that is not present, the default of httk_python_root + ../.. is used.

If the file distdata.py in httk_python_root exists, the config object section [distdata] is looked up for version, version_date, and copyright_note,
which are exported as httk_version, httk_version_date, httk_copyright_note. If this file does not exist, they identifiers are instead derived using the 'git' command.
If that does not work, they are set to 'unknown', except for httk_copyright_note, which is set to a sensible default.

This python file has no dependencies except for the standard library (neither within httk or outside).
It will always remain safe to import by itself, e.g.::

  (cd src/httk/config; python -c "import sys, config; sys.stdout.write(config.httk_version + '\\n')")

Or::

  python -c "import sys; here = path.abspath(path.dirname(__file__)); sys.path.insert(1, os.path.join(here,'src/httk/config')); import config; sys.stdout.write(config.httk_version + '\\n')"


"""

_default_httk_root = '../..'
_default_copyright_name = "Rickard Armiento, et al."
_default_copyright_note = "(c) 2012 - 2018, " + _default_copyright_name

import sys, os, inspect, subprocess, datetime
import codecs

try:
    python_major_version = sys.version_info[0]
    python_minor_version = sys.version_info[1]
except Exception:
    raise RuntimeError("Python version too old, this appears to be a version of python older than python 2.0!")

if sys.version_info[0] == 3:
    from io import StringIO
    import configparser
else:
    from StringIO import StringIO
    import ConfigParser as configparser

python_root = os.path.realpath(os.path.join(os.path.abspath(os.path.split(inspect.getfile(inspect.currentframe()))[0]),'..'))
httk_root = None
_config = configparser.ConfigParser()

[docs]def read_config(): global python_root, httk_root, _config try: with open(os.path.join(python_root, "distdata.py"), 'r') as fp: distdata_str = fp.read() ini_str = '[distdata]\n' + distdata_str ini_fp = StringIO(ini_str) _config.readfp(ini_fp) httk_root = os.path.realpath(os.path.join(python_root,_config.get('distdata','root').strip('"'))) except (IOError, configparser.NoSectionError, configparser.NoOptionError): httk_root = os.path.realpath(os.path.join(python_root,_default_httk_root)) config_files = [] internal_cfgpathstr = os.path.join(python_root, 'httk.cfg') _config.read([internal_cfgpathstr]) try: httk_root_cfg = _config.get('general','httk_root') httk_root = os.path.join(python_root,httk_root_cfg) except (configparser.NoSectionError, configparser.NoOptionError): pass global_cfgpathstr = os.path.join(python_root, 'httk.cfg') local_cfgpathstr = os.path.expanduser('~/.httk/config') try: httk_root_cfg = _config.get('general','httk_root') httk_root = os.path.join(python_root,httk_root_cfg) except (configparser.NoSectionError, configparser.NoOptionError): pass _config.read([global_cfgpathstr, local_cfgpathstr])
[docs]def determine_version_data(): global python_root, httk_root, _config httk_version = None if os.path.exists(os.path.join(python_root, "distdata.py")): try: httk_version = _config.get('distdata','version').strip('"') httk_version_date = _config.get('distdata','version_date').strip('"') httk_copyright_note = _config.get('distdata','copyright_note').strip('"') except (configparser.NoSectionError, configparser.NoOptionError): pass if httk_version is None: if (not _config.getboolean('general', 'bypass_git_version_lookup')) and os.path.exists(os.path.join(httk_root,'.git')): try: httk_version = subprocess.check_output(["git", "describe","--dirty","--always"], cwd=python_root).strip() httk_version = codecs.decode(httk_version, 'utf-8') if httk_version.endswith('-dirty'): _git_commit_datetime = datetime.datetime.now() else: _git_commit_datetime = datetime.datetime.fromtimestamp(int(subprocess.check_output(["git", "log","-1",'--format=%ct'],cwd=python_root))) httk_version_date = "%d-%02d-%02d" % (_git_commit_datetime.year,_git_commit_datetime.month, _git_commit_datetime.day) httk_copyright_note = "(c) 2012 - " + str(_git_commit_datetime.year) + " " + _default_copyright_name # PEP 440 compliance httk_version = httk_version[1:] httk_version = httk_version.replace('-','.dev',1) httk_version = httk_version.replace('-','+',1) if httk_version.endswith('-dirty'): httk_version = httk_version.replace('-dirty','.d') except Exception as e: sys.stderr.write("Note: failed to obtain httk version from git: " + str(e) + "\n") httk_version = 'unknown' httk_version_date = 'unknown' httk_copyright_note = _default_copyright_note else: httk_version = 'unknown' httk_version_date = 'unknown' httk_copyright_note = _default_copyright_note return {'httk_version':httk_version, 'httk_version_date':httk_version_date, 'httk_copyright_note':httk_copyright_note}
read_config() _version_data = determine_version_data() version = _version_data['httk_version'] if version == 'unknown': major_version = '0' minor_version = '0' patch_version = 'unknown' else: try: _version_list = version.split('.') major_version = int(_version_list[0]) minor_version = int(_version_list[1]) patch_version = '.'.join(_version_list[2:]) except Exception: print("Warning: could not determine version numbers. Version string was:"+str(version)) major_version = '0' minor_version = '0' patch_version = 'unknown' version_date = _version_data['httk_version_date'] copyright_note = _version_data['httk_copyright_note']
[docs]class ExceptionlessConfig(object): def __init__(self, config): self._config = config def __getattr__(self, attr): configattr = getattr(self._config, attr) if hasattr(configattr, '__call__'): def wrapped_func(*args): try: return configattr(*args) except (configparser.NoSectionError, configparser.NoOptionError): return None return wrapped_func else: return configattr
config = ExceptionlessConfig(_config)