From b3bac28d08dfd6d3ebe13953697276501b048dcf Mon Sep 17 00:00:00 2001 From: Lei Liu Date: Tue, 29 Jan 2019 17:06:35 +0800 Subject: [PATCH] pybind/mgr: PEP 8 code clean and fix typo Signed-off-by: Lei Liu --- src/pybind/mgr/hello/module.py | 3 +- src/pybind/mgr/mgr_module.py | 108 ++++++++++++---------- src/pybind/mgr/mgr_util.py | 9 +- src/pybind/mgr/prometheus/module.py | 134 ++++++++++++++++------------ 4 files changed, 142 insertions(+), 112 deletions(-) diff --git a/src/pybind/mgr/hello/module.py b/src/pybind/mgr/hello/module.py index e8a3aebbe62..94d532ee70b 100644 --- a/src/pybind/mgr/hello/module.py +++ b/src/pybind/mgr/hello/module.py @@ -53,14 +53,13 @@ class Hello(MgrModule): if 'person_name' in cmd: message = "Hello, " + cmd['person_name'] else: - message = "Hello " + self.get_module_option('place'); + message = "Hello " + self.get_module_option('place') if self.get_module_option('emphatic'): message += '!' return HandleCommandResult(retval=status_code, stdout=output_buffer, stderr=message + "\n" + output_string) - def serve(self): """ This method is called by the mgr when the module starts and can be diff --git a/src/pybind/mgr/mgr_module.py b/src/pybind/mgr/mgr_module.py index 2933389f47a..2ad0763e2df 100644 --- a/src/pybind/mgr/mgr_module.py +++ b/src/pybind/mgr/mgr_module.py @@ -10,36 +10,37 @@ import rados import time PG_STATES = [ - "active", - "clean", - "down", - "recovery_unfound", - "backfill_unfound", - "scrubbing", - "degraded", - "inconsistent", - "peering", - "repair", - "recovering", - "forced_recovery", - "backfill_wait", - "incomplete", - "stale", - "remapped", - "deep", - "backfilling", - "forced_backfill", - "backfill_toofull", - "recovery_wait", - "recovery_toofull", - "undersized", - "activating", - "peered", - "snaptrim", - "snaptrim_wait", - "snaptrim_error", - "creating", - "unknown"] + "active", + "clean", + "down", + "recovery_unfound", + "backfill_unfound", + "scrubbing", + "degraded", + "inconsistent", + "peering", + "repair", + "recovering", + "forced_recovery", + "backfill_wait", + "incomplete", + "stale", + "remapped", + "deep", + "backfilling", + "forced_backfill", + "backfill_toofull", + "recovery_wait", + "recovery_toofull", + "undersized", + "activating", + "peered", + "snaptrim", + "snaptrim_wait", + "snaptrim_error", + "creating", + "unknown"] + class CPlusPlusHandler(logging.Handler): def __init__(self, module_inst): @@ -62,7 +63,6 @@ class CPlusPlusHandler(logging.Handler): def configure_logger(module_inst, name): logger = logging.getLogger(name) - # Don't filter any logs at the python level, leave it to C++ logger.setLevel(logging.DEBUG) @@ -76,14 +76,17 @@ def configure_logger(module_inst, name): def unconfigure_logger(module_inst, name): logger = logging.getLogger(name) - rm_handlers = [h for h in logger.handlers if isinstance(h, CPlusPlusHandler)] + rm_handlers = [ + h for h in logger.handlers if isinstance(h, CPlusPlusHandler)] for h in rm_handlers: logger.removeHandler(h) + class CommandResult(object): """ Use with MgrModule.send_command """ + def __init__(self, tag=None): self.ev = threading.Event() self.outs = "" @@ -160,7 +163,9 @@ class OSDMap(ceph_module.BasePyOSDMap): return self._get_pools_by_take(take).get('pools', []) def calc_pg_upmaps(self, inc, - max_deviation=.01, max_iterations=10, pools=[]): + max_deviation=.01, max_iterations=10, pools=None): + if pools is None: + pools = [] return self._calc_pg_upmaps( inc, max_deviation, max_iterations, pools) @@ -219,7 +224,7 @@ class CRUSHMap(ceph_module.BasePyCRUSH): def get_take_weight_osd_map(self, root): uglymap = self._get_take_weight_osd_map(root) - return { int(k): v for k, v in six.iteritems(uglymap.get('weights', {})) } + return {int(k): v for k, v in six.iteritems(uglymap.get('weights', {}))} @staticmethod def have_default_choose_args(dump): @@ -429,6 +434,7 @@ class MgrStandbyModule(ceph_module.BaseMgrStandbyModule): r = default return r + class MgrModule(ceph_module.BaseMgrModule): COMMANDS = [] MODULE_OPTIONS = [] @@ -613,14 +619,16 @@ class MgrModule(ceph_module.BaseMgrModule): elif unit == self.BYTES: return "B/s" - def to_pretty_iec(self, n): + @staticmethod + def to_pretty_iec(n): for bits, suffix in [(60, 'Ei'), (50, 'Pi'), (40, 'Ti'), (30, 'Gi'), - (20, 'Mi'), (10, 'Ki')]: + (20, 'Mi'), (10, 'Ki')]: if n > 10 << bits: return str(n >> bits) + ' ' + suffix return str(n) + ' ' - def get_pretty_row(self, elems, width): + @staticmethod + def get_pretty_row(elems, width): """ Takes an array of elements and returns a string with those elements formatted as a table row. Useful for polling modules. @@ -673,7 +681,7 @@ class MgrModule(ceph_module.BaseMgrModule): This is information that ceph-mgr has gleaned from the daemon metadata reported by daemons running on a particular server. - :param hostname: a hostame + :param hostname: a hostname """ return self._ceph_get_server(hostname) @@ -722,7 +730,7 @@ class MgrModule(ceph_module.BaseMgrModule): Like ``get_server``, but gives information about all servers (i.e. all unique hostnames that have been mentioned in daemon metadata) - :return: a list of infomration about all servers + :return: a list of information about all servers :rtype: list """ return self._ceph_get_server(None) @@ -869,8 +877,8 @@ class MgrModule(ceph_module.BaseMgrModule): in their schema. """ if key not in [o['name'] for o in self.MODULE_OPTIONS]: - raise RuntimeError("Config option '{0}' is not in {1}.MODULE_OPTIONS".\ - format(key, self.__class__.__name__)) + raise RuntimeError("Config option '{0}' is not in {1}.MODULE_OPTIONS". + format(key, self.__class__.__name__)) def _get_module_option(self, key, default): r = self._ceph_get_module_option(key) @@ -885,6 +893,7 @@ class MgrModule(ceph_module.BaseMgrModule): Retrieve the value of a persistent configuration setting :param str key: + :param str default: :return: str """ self._validate_module_option(key) @@ -967,7 +976,7 @@ class MgrModule(ceph_module.BaseMgrModule): """ Set localized configuration for this ceph-mgr instance :param str key: - :param str default: + :param str val: :return: str """ self._validate_module_option(key) @@ -999,7 +1008,6 @@ class MgrModule(ceph_module.BaseMgrModule): def set_localized_store(self, key, val): return self._set_localized(key, val, self.set_store) - def self_test(self): """ Run a self-test on the module. Override this function and implement @@ -1023,18 +1031,20 @@ class MgrModule(ceph_module.BaseMgrModule): return self._ceph_get_osdmap() def get_latest(self, daemon_type, daemon_name, counter): - data = self.get_latest_counter(daemon_type, daemon_name, counter)[counter] + data = self.get_latest_counter( + daemon_type, daemon_name, counter)[counter] if data: return data[1] else: return 0 def get_latest_avg(self, daemon_type, daemon_name, counter): - data = self.get_latest_counter(daemon_type, daemon_name, counter)[counter] + data = self.get_latest_counter( + daemon_type, daemon_name, counter)[counter] if data: - return (data[1], data[2]) + return data[1], data[2] else: - return (0, 0) + return 0, 0 def get_all_perf_counters(self, prio_limit=PRIO_USEFUL, services=("mds", "mon", "osd", @@ -1053,7 +1063,6 @@ class MgrModule(ceph_module.BaseMgrModule): result = defaultdict(dict) - for server in self.list_servers(): for service in server['services']: if service['type'] not in services: @@ -1068,7 +1077,8 @@ class MgrModule(ceph_module.BaseMgrModule): # Value is returned in a potentially-multi-service format, # get just the service we're asking about - svc_full_name = "{0}.{1}".format(service['type'], service['id']) + svc_full_name = "{0}.{1}".format( + service['type'], service['id']) schema = schema[svc_full_name] # Populate latest values diff --git a/src/pybind/mgr/mgr_util.py b/src/pybind/mgr/mgr_util.py index 38c33d80cbc..fed3c54e9a6 100644 --- a/src/pybind/mgr/mgr_util.py +++ b/src/pybind/mgr/mgr_util.py @@ -7,7 +7,7 @@ BLUE, MAGENTA, CYAN, -GRAY + GRAY ) = range(8) RESET_SEQ = "\033[0m" @@ -16,6 +16,7 @@ COLOR_DARK_SEQ = "\033[0;%dm" BOLD_SEQ = "\033[1m" UNDERLINE_SEQ = "\033[4m" + def colorize(msg, color, dark=False): """ Decorate `msg` with escape sequences to give the requested color @@ -23,12 +24,14 @@ def colorize(msg, color, dark=False): return (COLOR_DARK_SEQ if dark else COLOR_SEQ) % (30 + color) \ + msg + RESET_SEQ + def bold(msg): """ Decorate `msg` with escape sequences to make it appear bold """ return BOLD_SEQ + msg + RESET_SEQ + def format_units(n, width, colored, decimal): """ Format a number without units, so as to fit into `width` characters, substituting @@ -48,7 +51,7 @@ def format_units(n, width, colored, decimal): if truncated_float[-1] == '.': truncated_float = " " + truncated_float[0:-1] else: - truncated_float = "%{wid}d".format(wid=width-1) % n + truncated_float = "%{wid}d".format(wid=width - 1) % n formatted = "%s%s" % (truncated_float, units[unit]) if colored: @@ -61,8 +64,10 @@ def format_units(n, width, colored, decimal): else: return formatted + def format_dimless(n, width, colored=True): return format_units(n, width, colored, decimal=True) + def format_bytes(n, width, colored=True): return format_units(n, width, colored, decimal=False) diff --git a/src/pybind/mgr/prometheus/module.py b/src/pybind/mgr/prometheus/module.py index 5487849e157..ab92bee1511 100644 --- a/src/pybind/mgr/prometheus/module.py +++ b/src/pybind/mgr/prometheus/module.py @@ -25,7 +25,6 @@ def os_exit_noop(*args, **kwargs): os._exit = os_exit_noop - # to access things in class Module from subclass Root. Because # it's a dict, the writer doesn't need to declare 'global' for access @@ -38,7 +37,6 @@ def global_instance(): def health_status_to_number(status): - if status == 'HEALTH_OK': return 0 elif status == 'HEALTH_WARN': @@ -46,6 +44,7 @@ def health_status_to_number(status): elif status == 'HEALTH_ERR': return 2 + DF_CLUSTER = ['total_bytes', 'total_used_bytes', 'total_used_raw_bytes'] DF_POOL = ['max_avail', 'stored', 'stored_raw', 'objects', 'dirty', @@ -59,7 +58,8 @@ FS_METADATA = ('data_pools', 'fs_id', 'metadata_pool', 'name') MDS_METADATA = ('ceph_daemon', 'fs_id', 'hostname', 'public_addr', 'rank', 'ceph_version') -MON_METADATA = ('ceph_daemon', 'hostname', 'public_addr', 'rank', 'ceph_version') +MON_METADATA = ('ceph_daemon', 'hostname', + 'public_addr', 'rank', 'ceph_version') OSD_METADATA = ('back_iface', 'ceph_daemon', 'cluster_addr', 'device_class', 'front_iface', 'hostname', 'objectstore', 'public_addr', @@ -76,7 +76,8 @@ RGW_METADATA = ('ceph_daemon', 'hostname', 'ceph_version') RBD_MIRROR_METADATA = ('ceph_daemon', 'id', 'instance_id', 'hostname', 'ceph_version') -DISK_OCCUPATION = ('ceph_daemon', 'device', 'db_device', 'wal_device', 'instance') +DISK_OCCUPATION = ('ceph_daemon', 'device', 'db_device', + 'wal_device', 'instance') NUM_OBJECTS = ['degraded', 'misplaced', 'unfound'] @@ -101,7 +102,8 @@ class Metric(object): def promethize(path): ''' replace illegal metric name characters ''' - result = path.replace('.', '_').replace('+', '_plus').replace('::', '_') + result = path.replace('.', '_').replace( + '+', '_plus').replace('::', '_') # Hyphens usually turn into underscores, unless they are # trailing @@ -159,11 +161,11 @@ class Module(MgrModule): ] MODULE_OPTIONS = [ - {'name': 'server_addr'}, - {'name': 'server_port'}, - {'name': 'scrape_interval'}, - {'name': 'rbd_stats_pools'}, - {'name': 'rbd_stats_pools_refresh_interval'}, + {'name': 'server_addr'}, + {'name': 'server_port'}, + {'name': 'scrape_interval'}, + {'name': 'rbd_stats_pools'}, + {'name': 'rbd_stats_pools_refresh_interval'}, ] def __init__(self, *args, **kwargs): @@ -175,21 +177,21 @@ class Module(MgrModule): self.collect_timeout = 5.0 self.collect_cache = None self.rbd_stats = { - 'pools' : {}, - 'pools_refresh_time' : 0, - 'counters_info' : { - 'write_ops' : {'type' : self.PERFCOUNTER_COUNTER, - 'desc' : 'RBD image writes count'}, - 'read_ops' : {'type' : self.PERFCOUNTER_COUNTER, - 'desc' : 'RBD image reads count'}, - 'write_bytes' : {'type' : self.PERFCOUNTER_COUNTER, - 'desc' : 'RBD image bytes written'}, - 'read_bytes' : {'type' : self.PERFCOUNTER_COUNTER, - 'desc' : 'RBD image bytes read'}, - 'write_latency' : {'type' : self.PERFCOUNTER_LONGRUNAVG, - 'desc' : 'RBD image writes latency (msec)'}, - 'read_latency' : {'type' : self.PERFCOUNTER_LONGRUNAVG, - 'desc' : 'RBD image reads latency (msec)'}, + 'pools': {}, + 'pools_refresh_time': 0, + 'counters_info': { + 'write_ops': {'type': self.PERFCOUNTER_COUNTER, + 'desc': 'RBD image writes count'}, + 'read_ops': {'type': self.PERFCOUNTER_COUNTER, + 'desc': 'RBD image reads count'}, + 'write_bytes': {'type': self.PERFCOUNTER_COUNTER, + 'desc': 'RBD image bytes written'}, + 'read_bytes': {'type': self.PERFCOUNTER_COUNTER, + 'desc': 'RBD image bytes read'}, + 'write_latency': {'type': self.PERFCOUNTER_LONGRUNAVG, + 'desc': 'RBD image writes latency (msec)'}, + 'read_latency': {'type': self.PERFCOUNTER_LONGRUNAVG, + 'desc': 'RBD image reads latency (msec)'}, }, } _global_instance['plugin'] = self @@ -349,7 +351,8 @@ class Module(MgrModule): active_daemons = [] for fs in fs_map['filesystems']: # collect fs metadata - data_pools = ",".join([str(pool) for pool in fs['mdsmap']['data_pools']]) + data_pools = ",".join([str(pool) + for pool in fs['mdsmap']['data_pools']]) self.metrics['fs_metadata'].set(1, ( data_pools, fs['id'], @@ -359,7 +362,7 @@ class Module(MgrModule): self.log.debug('mdsmap: {}'.format(fs['mdsmap'])) for gid, daemon in fs['mdsmap']['info'].items(): id_ = daemon['name'] - host_version = servers.get((id_, 'mds'), ('','')) + host_version = servers.get((id_, 'mds'), ('', '')) self.metrics['mds_metadata'].set(1, ( 'mds.{}'.format(id_), fs['id'], host_version[0], daemon['addr'], @@ -372,7 +375,7 @@ class Module(MgrModule): for mon in mon_status['monmap']['mons']: rank = mon['rank'] id_ = mon['name'] - host_version = servers.get((id_, 'mon'), ('','')) + host_version = servers.get((id_, 'mon'), ('', '')) self.metrics['mon_metadata'].set(1, ( 'mon.{}'.format(id_), host_version[0], mon['public_addr'].split(':')[0], rank, @@ -393,7 +396,8 @@ class Module(MgrModule): reported_states = {} for pg in pg_status['pgs_by_state']: for state in pg['state_name'].split('+'): - reported_states[state] = reported_states.get(state, 0) + pg['count'] + reported_states[state] = reported_states.get( + state, 0) + pg['count'] for state in reported_states: path = 'pg_{}'.format(state) @@ -407,7 +411,8 @@ class Module(MgrModule): try: self.metrics['pg_{}'.format(state)].set(0) except KeyError: - self.log.warn("skipping pg in unknown state {}".format(state)) + self.log.warn( + "skipping pg in unknown state {}".format(state)) def get_osd_stats(self): osd_stats = self.get('osd_stats') @@ -463,7 +468,7 @@ class Module(MgrModule): id_)) continue - host_version = servers.get((str(id_), 'osd'), ('','')) + host_version = servers.get((str(id_), 'osd'), ('', '')) # collect disk occupation metadata osd_metadata = self.get_metadata("osd", str(id_)) @@ -495,17 +500,19 @@ class Module(MgrModule): osd_objectstore = osd_metadata.get('osd_objectstore', None) if osd_objectstore == "filestore": - # collect filestore backend device - osd_dev_node = osd_metadata.get('backend_filestore_dev_node', None) - # collect filestore journal device + # collect filestore backend device + osd_dev_node = osd_metadata.get( + 'backend_filestore_dev_node', None) + # collect filestore journal device osd_wal_dev_node = osd_metadata.get('osd_journal', '') osd_db_dev_node = '' elif osd_objectstore == "bluestore": - # collect bluestore backend device - osd_dev_node = osd_metadata.get('bluestore_bdev_dev_node', None) - # collect bluestore wal backend + # collect bluestore backend device + osd_dev_node = osd_metadata.get( + 'bluestore_bdev_dev_node', None) + # collect bluestore wal backend osd_wal_dev_node = osd_metadata.get('bluefs_wal_dev_node', '') - # collect bluestore db backend + # collect bluestore db backend osd_db_dev_node = osd_metadata.get('bluefs_db_dev_node', '') if osd_dev_node and osd_dev_node == "unknown": osd_dev_node = None @@ -523,11 +530,12 @@ class Module(MgrModule): )) else: self.log.info("Missing dev node metadata for osd {0}, skipping " - "occupation record for this osd".format(id_)) + "occupation record for this osd".format(id_)) pool_meta = [] for pool in osd_map['pools']: - self.metrics['pool_metadata'].set(1, (pool['pool'], pool['pool_name'])) + self.metrics['pool_metadata'].set( + 1, (pool['pool'], pool['pool_name'])) # Populate other servers metadata for key, value in servers.items(): @@ -545,7 +553,8 @@ class Module(MgrModule): mirror_metadata['ceph_daemon'] = '{}.{}'.format(service_type, service_id) self.metrics['rbd_mirror_metadata'].set( - 1, (mirror_metadata.get(k, '') for k in RBD_MIRROR_METADATA) + 1, (mirror_metadata.get(k, '') + for k in RBD_MIRROR_METADATA) ) def get_num_objects(self): @@ -599,7 +608,7 @@ class Module(MgrModule): if pools: next_refresh = self.rbd_stats['pools_refresh_time'] + \ self.get_localized_module_option( - 'rbd_stats_pools_refresh_interval', 300) + 'rbd_stats_pools_refresh_interval', 300) if rbd_stats_pools != pools or time.time() >= next_refresh: self.refresh_rbd_stats_pools(pools) pools_refreshed = True @@ -617,13 +626,14 @@ class Module(MgrModule): break if nspace_names: namespace_regex = '^(' + \ - '|'.join([re.escape(x) for x in set(nspace_names)]) + ')$' + "|".join([re.escape(x) + for x in set(nspace_names)]) + ')$' else: namespace_regex = '^(.*)$' if 'query' in self.rbd_stats and \ (pool_id_regex != self.rbd_stats['query']['key_descriptor'][0]['regex'] or - namespace_regex != self.rbd_stats['query']['key_descriptor'][1]['regex']): + namespace_regex != self.rbd_stats['query']['key_descriptor'][1]['regex']): self.remove_osd_perf_query(self.rbd_stats['query_id']) del self.rbd_stats['query_id'] del self.rbd_stats['query'] @@ -721,7 +731,7 @@ class Module(MgrModule): label_names, ) self.metrics[path].set(counters[i][1], labels) - i += 1; + i += 1 def refresh_rbd_stats_pools(self, pools): self.log.debug('refreshing rbd pools %s' % (pools)) @@ -733,7 +743,7 @@ class Module(MgrModule): pool_id = self.rados.pool_lookup(pool_name) with self.rados.open_ioctx(pool_name) as ioctx: if pool_id not in self.rbd_stats['pools']: - self.rbd_stats['pools'][pool_id] = {'images' : {}} + self.rbd_stats['pools'][pool_id] = {'images': {}} pool = self.rbd_stats['pools'][pool_id] pool['name'] = pool_name pool['ns_names'] = cfg_ns_names @@ -746,7 +756,7 @@ class Module(MgrModule): del pool['images'][nspace_name] for nspace_name in nspace_names: if (nspace_name and - not rbd.namespace_exists(ioctx, nspace_name)): + not rbd.namespace_exists(ioctx, nspace_name)): self.log.debug('unknown namespace %s for pool %s' % (nspace_name, pool_name)) continue @@ -756,7 +766,7 @@ class Module(MgrModule): namespace = pool['images'][nspace_name] images = {} for image_meta in RBD().list2(ioctx): - image = {'n' : image_meta['name']} + image = {'n': image_meta['name']} image_id = image_meta['id'] if image_id in namespace: image['c'] = namespace[image_id]['c'] @@ -798,7 +808,8 @@ class Module(MgrModule): continue # Get the value of the counter - value = self._perfvalue_to_value(counter_info['type'], counter_info['value']) + value = self._perfvalue_to_value( + counter_info['type'], counter_info['value']) # Represent the long running avgs as sum/count pairs if counter_info['type'] & self.PERFCOUNTER_LONGRUNAVG: @@ -831,7 +842,7 @@ class Module(MgrModule): ) self.metrics[path].set(value, (daemon,)) - self.get_rbd_stats(); + self.get_rbd_stats() # Return formatted metrics and clear no longer used data _metrics = [m.str_expfmt() for m in self.metrics.values()] @@ -859,7 +870,7 @@ class Module(MgrModule): "prefix": "config-key get", 'key': "config/mgr/mgr/prometheus/{}/server_port".format(id_), }), - "") + "") r, outb, outs = result.wait() if r != 0: global_instance().log.error("Failed to retrieve port for mgr {}: {}".format(id_, outs)) @@ -917,9 +928,10 @@ class Module(MgrModule): finally: instance.collect_lock.release() - def _metrics(self, instance): + @staticmethod + def _metrics(instance): # Return cached data if available and collected before the cache times out - if instance.collect_cache and time.time() - instance.collect_time < instance.collect_timeout: + if instance.collect_cache and time.time() - instance.collect_time < instance.collect_timeout: cherrypy.response.headers['Content-Type'] = 'text/plain' return instance.collect_cache @@ -933,10 +945,13 @@ class Module(MgrModule): raise cherrypy.HTTPError(503, 'No MON connection') # Make the cache timeout for collecting configurable - self.collect_timeout = self.get_localized_module_option('scrape_interval', 5.0) + self.collect_timeout = self.get_localized_module_option( + 'scrape_interval', 5.0) - server_addr = self.get_localized_module_option('server_addr', DEFAULT_ADDR) - server_port = self.get_localized_module_option('server_port', DEFAULT_PORT) + server_addr = self.get_localized_module_option( + 'server_addr', DEFAULT_ADDR) + server_port = self.get_localized_module_option( + 'server_port', DEFAULT_PORT) self.log.info( "server_addr: %s server_port: %s" % (server_addr, server_port) @@ -977,8 +992,10 @@ class StandbyModule(MgrStandbyModule): def serve(self): server_addr = self.get_localized_module_option('server_addr', '::') - server_port = self.get_localized_module_option('server_port', DEFAULT_PORT) - self.log.info("server_addr: %s server_port: %s" % (server_addr, server_port)) + server_port = self.get_localized_module_option( + 'server_port', DEFAULT_PORT) + self.log.info("server_addr: %s server_port: %s" % + (server_addr, server_port)) cherrypy.config.update({ 'server.socket_host': server_addr, 'server.socket_port': int(server_port), @@ -988,7 +1005,6 @@ class StandbyModule(MgrStandbyModule): module = self class Root(object): - @cherrypy.expose def index(self): active_uri = module.get_active_uri() -- 2.39.5