Source code for can.util

#!/usr/bin/env python3
"""
Configuration file parsing.
"""
try:
    from configparser import ConfigParser
except ImportError:
    from ConfigParser import SafeConfigParser as ConfigParser
import os
import os.path
import sys
import platform
import re


REQUIRED_KEYS = [
    'interface',
    'channel',
]


CONFIG_FILES = ['~/can.conf']

if platform.system() == "Linux":
    CONFIG_FILES.extend(
        [
            '/etc/can.conf',
            '~/.can',
            '~/.canrc'
        ]
    )
elif platform.system() == "Windows" or platform.python_implementation() == "IronPython":
    CONFIG_FILES.extend(
        [
            'can.ini',
            os.path.join(os.getenv('APPDATA'), 'can.ini')
        ]
    )


[docs]def load_file_config(path=None): """ Loads configuration from file with following content:: [default] interface = socketcan channel = can0 :param path: path to config file. If not specified, several sensible default locations are tried depending on platform. """ config = ConfigParser() if path is None: config.read([os.path.expanduser(path) for path in CONFIG_FILES]) else: config.read(path) if not config.has_section('default'): return {} return dict( (key, val) for key, val in config.items('default') if key in REQUIRED_KEYS )
[docs]def load_environment_config(): """ Loads config dict from environmental variables (if set): * CAN_INTERFACE * CAN_CHANNEL """ mapper = { 'interface': 'CAN_INTERFACE', 'channel': 'CAN_CHANNEL', } return dict( (key, os.environ.get(val)) for key, val in mapper.items() if val in os.environ )
[docs]def load_config(path=None): """ Returns a dict with configuration details which is loaded from (in this order): * Environment variables CAN_INTERFACE, CAN_CHANNEL * Config files ``/etc/can.conf`` or ``~/.can`` or ``~/.canrc`` where the latter may add or replace values of the former. Interface can be kvaser, socketcan, socketcan_ctypes, socketcan_native, serial The returned dictionary may look like this:: { 'interface': 'python-can backend interface to use', 'channel': 'default channel to use', } :param path: Optional path to config file. """ config = load_file_config(path) config.update(load_environment_config()) # substitute None for all values not found for key in REQUIRED_KEYS: if key not in config: config[key] = None if config['interface'] == 'socketcan': config['interface'] = choose_socketcan_implementation() return config
[docs]def choose_socketcan_implementation(): """Set the best version of SocketCAN for this system. :param config: The can.rc configuration dictionary :raises Exception: If the system doesn't support SocketCAN """ # Check OS: SocketCAN is available only under Linux if not sys.platform.startswith('linux'): msg = 'SocketCAN not available under {}'.format( sys.platform) raise Exception(msg) else: # Check release: SocketCAN was added to Linux 2.6.25 rel_string = platform.release() m = re.match('\d+\.\d+\.\d', rel_string) if m is None: msg = 'Bad linux release {}'.format(rel_string) raise Exception(msg) rel_num = [int(i) for i in rel_string[:m.end()].split('.')] if (rel_num >= [2, 6, 25]): # Check Python version: SocketCAN was added in 3.3 return 'socketcan_native' if sys.version_info >= (3, 3) else 'socketcan_ctypes' else: msg = 'SocketCAN not available under Linux {}'.format( rel_string) raise Exception(msg)
if __name__ == "__main__": print("Searching for configuration named:") print("\n".join(CONFIG_FILES)) print("Settings:") print(load_config())