Ticket #1673: 0001-fix-network-disconnect-and-discard-history.2.patch

File 0001-fix-network-disconnect-and-discard-history.2.patch, 22.6 KB (added by quozl, 11 years ago)

fix network disconnect and discard history, see also sugarlabs.org #1802, #1737, #1736, #1608, and laptop.org 9977 and 9788.

  • extensions/cpsection/network/model.py

    From 7ae1a9903237c0d26bebbf699084eb258a533173 Mon Sep 17 00:00:00 2001
    From: James Cameron <quozl@laptop.org>
    Date: Tue, 25 May 2010 17:27:44 +1000
    Subject: [PATCH] fix network disconnect and discard history
    
    User interface changes:
    
    - enable the disconnect button on the access point menu in the
      neighbourhood view, (rather than the button doing nothing),
    
    - fix the disconnect button on the wireless device icon in the frame
      so that the disconnection remains effective, (rather than
      disconnecting and then reconnecting automatically),
    
    - enable the discard network history button in the network control
      panel, which also now forces a disconnect, and will be insensitive
      if there are no networks to be discarded, (rather than the button
      doing nothing),
    
    - enforce consistency between the neighbourhood view, the frame, and
      the control panel, with respect to how the access point is shown.
    
    References:
    
        http://dev.laptop.org/ticket/9977 (fixes a workaround)
        http://bugs.sugarlabs.org/ticket/1673
        http://bugs.sugarlabs.org/ticket/1802
        http://bugs.sugarlabs.org/ticket/1737
        http://bugs.sugarlabs.org/ticket/1736
        http://bugs.sugarlabs.org/ticket/1608
        http://dev.laptop.org/ticket/9788
    ---
     extensions/cpsection/network/model.py |   12 ++++--
     extensions/cpsection/network/view.py  |    8 ++++-
     extensions/deviceicon/network.py      |   37 ++++++++++---------
     src/jarabe/desktop/meshbox.py         |   61 +++++++++++++++++++++----------
     src/jarabe/model/network.py           |   62 ++++++++++++++++++++++++++------
     5 files changed, 125 insertions(+), 55 deletions(-)
    
    diff --git a/extensions/cpsection/network/model.py b/extensions/cpsection/network/model.py
    index e1c3dab..2bc5e3a 100644
    a b  
    1717
    1818import dbus
    1919from gettext import gettext as _
     20from jarabe.model import network
    2021import gconf
    2122
    2223_NM_SERVICE = 'org.freedesktop.NetworkManager'
    def get_radio(): 
    6869    try:
    6970        bus = dbus.SystemBus()
    7071        obj = bus.get_object(_NM_SERVICE, _NM_PATH)
    71         nm_props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
     72        nm_props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
    7273    except dbus.DBusException:
    7374        raise ReadError('%s service not available' % _NM_SERVICE)
    7475
    def set_radio(state): 
    8990        try:
    9091            bus = dbus.SystemBus()
    9192            obj = bus.get_object(_NM_SERVICE, _NM_PATH)
    92             nm_props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
     93            nm_props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
    9394        except dbus.DBusException:
    9495            raise ReadError('%s service not available' % _NM_SERVICE)
    9596        nm_props.Set(_NM_IFACE, 'WirelessEnabled', True)
    def set_radio(state): 
    9798        try:
    9899            bus = dbus.SystemBus()
    99100            obj = bus.get_object(_NM_SERVICE, _NM_PATH)
    100             nm_props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
     101            nm_props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
    101102        except dbus.DBusException:
    102103            raise ReadError('%s service not available' % _NM_SERVICE)
    103104        nm_props.Set(_NM_IFACE, 'WirelessEnabled', False)
    def clear_registration(): 
    116117def clear_networks():
    117118    """Clear saved passwords and network configurations.
    118119    """
    119     pass
     120    network.clear_wifi_connections()
     121
     122def count_networks():
     123    return network.count_wifi_connections()
    120124
    121125def get_publish_information():
    122126    client = gconf.client_get_default()
  • extensions/cpsection/network/view.py

    diff --git a/extensions/cpsection/network/view.py b/extensions/cpsection/network/view.py
    index 588daeb..b0f1336 100644
    a b class Network(SectionView): 
    104104        self._clear_history_button = gtk.Button()
    105105        self._clear_history_button.set_label(_('Discard network history'))
    106106        box_clear_history.pack_start(self._clear_history_button, expand=False)
     107        if self._model.count_networks() == 0:
     108            self._clear_history_button.set_sensitive(False)
    107109        self._clear_history_button.show()
    108110        box_wireless.pack_start(box_clear_history, expand=False)
    109111        box_clear_history.show()
    class Network(SectionView): 
    217219            self._radio_alert.props.msg = detail
    218220            self._radio_valid = False
    219221        else:
    220             self._radio_valid = True           
     222            self._radio_valid = True
     223            if self._model.count_networks() != 0:
     224                self._clear_history_button.set_sensitive(True)
    221225
    222226        self._validate()
    223227        return False
    class Network(SectionView): 
    248252
    249253    def __network_configuration_reset_cb(self, widget):
    250254        self._model.clear_networks()
     255        if self._model.count_networks() == 0:
     256            self._clear_history_button.set_sensitive(False)
  • extensions/deviceicon/network.py

    diff --git a/extensions/deviceicon/network.py b/extensions/deviceicon/network.py
    index 94a4293..a828497 100644
    a b class WirelessDeviceView(ToolButton): 
    352352        self.set_palette(self._palette)
    353353        self._palette.set_group_id('frame')
    354354
    355         self._device_props = dbus.Interface(self._device,
    356                                             'org.freedesktop.DBus.Properties')
     355        self._device_props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
    357356        self._device_props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
    358357                              reply_handler=self.__get_device_props_reply_cb,
    359358                              error_handler=self.__get_device_props_error_cb)
    class WirelessDeviceView(ToolButton): 
    394393                return
    395394            self._active_ap_op = active_ap_op
    396395            active_ap = self._bus.get_object(_NM_SERVICE, active_ap_op)
    397             props = dbus.Interface(active_ap, 'org.freedesktop.DBus.Properties')
     396            props = dbus.Interface(active_ap, dbus.PROPERTIES_IFACE)
    398397
    399398            props.GetAll(_NM_ACCESSPOINT_IFACE, byte_arrays=True,
    400399                         reply_handler=self.__get_all_ap_props_reply_cb,
    class WirelessDeviceView(ToolButton): 
    508507        self._icon.props.base_color = self._color
    509508
    510509    def __deactivate_connection_cb(self, palette, data=None):
     510        connection = network.find_connection_by_ssid(self._name)
     511        if connection:
     512            if self._mode == network.NM_802_11_MODE_INFRA:
     513                connection.set_disconnected()
     514
    511515        if self._active_ap_op is not None:
    512516            obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
    513517            netmgr = dbus.Interface(obj, _NM_IFACE)
    514             netmgr_props = dbus.Interface(
    515                 netmgr, 'org.freedesktop.DBus.Properties')
     518            netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
    516519            active_connections_o = netmgr_props.Get(_NM_IFACE,
    517520                                                    'ActiveConnections')
    518521
    519522            for conn_o in active_connections_o:
    520523                obj = self._bus.get_object(_NM_IFACE, conn_o)
    521                 props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
     524                props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
    522525                ap_op = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
    523526                if ap_op == self._active_ap_op:
    524527                    netmgr.DeactivateConnection(conn_o)
    class OlpcMeshDeviceView(ToolButton): 
    608611        self.set_palette(self._palette)
    609612        self._palette.set_group_id('frame')
    610613
    611         self._device_props = dbus.Interface(self._device,
    612                                             'org.freedesktop.DBus.Properties')
     614        self._device_props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
    613615        self._device_props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
    614616                              reply_handler=self.__get_device_props_reply_cb,
    615617                              error_handler=self.__get_device_props_error_cb)
    class OlpcMeshDeviceView(ToolButton): 
    681683    def __deactivate_connection(self, palette, data=None):
    682684        obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
    683685        netmgr = dbus.Interface(obj, _NM_IFACE)
    684         netmgr_props = dbus.Interface(netmgr, 'org.freedesktop.DBus.Properties')
     686        netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
    685687        active_connections_o = netmgr_props.Get(_NM_IFACE,
    686688                                                'ActiveConnections')
    687689
    688690        for conn_o in active_connections_o:
    689691            # The connection path for a mesh connection is the device itself.
    690692            obj = self._bus.get_object(_NM_IFACE, conn_o)
    691             props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
     693            props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
    692694            ap_op = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
    693695
    694696            try:
    695697                obj = self._bus.get_object(_NM_IFACE, ap_op)
    696                 props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
     698                props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
    697699                type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
    698700                if type == network.DEVICE_TYPE_802_11_OLPC_MESH:
    699701                    netmgr.DeactivateConnection(conn_o)
    class GsmDeviceView(TrayIcon): 
    756758
    757759        self._palette = palette
    758760
    759         props = dbus.Interface(self._device, 'org.freedesktop.DBus.Properties')
     761        props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
    760762        props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
    761763                     reply_handler=self.__current_state_check_cb,
    762764                     error_handler=self.__current_state_check_error_cb)
    class GsmDeviceView(TrayIcon): 
    785787    def __gsm_disconnect_cb(self, palette, data=None):
    786788        obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
    787789        netmgr = dbus.Interface(obj, _NM_IFACE)
    788         netmgr_props = dbus.Interface(netmgr, 'org.freedesktop.DBus.Properties')
     790        netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
    789791        active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections')
    790792
    791793        for conn_o in active_connections_o:
    792794            obj = self._bus.get_object(_NM_IFACE, conn_o)
    793             props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
     795            props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
    794796            devices = props.Get(_NM_ACTIVE_CONN_IFACE, 'Devices')
    795797            if self._device.object_path in devices:
    796798                netmgr.DeactivateConnection(
    class WiredDeviceObserver(object): 
    910912        self._device_view = None
    911913        self._tray = tray
    912914
    913         props = dbus.Interface(self._device, 'org.freedesktop.DBus.Properties')
     915        props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
    914916        props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
    915917                     reply_handler=self.__get_device_props_reply_cb,
    916918                     error_handler=self.__get_device_props_error_cb)
    class WiredDeviceObserver(object): 
    938940
    939941    def _update_state(self, state):
    940942        if state == network.DEVICE_STATE_ACTIVATED:
    941             props = dbus.Interface(self._device,
    942                                    'org.freedesktop.DBus.Properties')
     943            props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
    943944            address = props.Get(_NM_DEVICE_IFACE, 'Ip4Address')
    944945            speed = props.Get(_NM_WIRED_IFACE, 'Speed')
    945946            self._device_view = WiredDeviceView(speed, address)
    class NetworkManagerObserver(object): 
    997998
    998999    def _check_device(self, device_op):
    9991000        nm_device = self._bus.get_object(_NM_SERVICE, device_op)
    1000         props = dbus.Interface(nm_device, 'org.freedesktop.DBus.Properties')
     1001        props = dbus.Interface(nm_device, dbus.PROPERTIES_IFACE)
    10011002
    10021003        device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
    10031004        if device_type == network.DEVICE_TYPE_802_3_ETHERNET:
  • src/jarabe/desktop/meshbox.py

    diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py
    index a04922b..280adb9 100644
    a b class WirelessNetworkView(CanvasPulsingIcon): 
    8686        self._rsn_flags = initial_ap.rsn_flags
    8787        self._device_caps = 0
    8888        self._device_state = None
    89         self._connection = None
    9089        self._color = None
    9190
    9291        if self._mode == network.NM_802_11_MODE_ADHOC \
    class WirelessNetworkView(CanvasPulsingIcon): 
    115114        self.set_palette(self._palette)
    116115        self._palette_icon.props.xo_color = self._color
    117116
    118         if network.find_connection_by_ssid(self._name) is not None:
    119             self.props.badge_name = "emblem-favorite"
    120             self._palette_icon.props.badge_name = "emblem-favorite"
    121         elif initial_ap.flags == network.NM_802_11_AP_FLAGS_PRIVACY:
    122             self.props.badge_name = "emblem-locked"
    123             self._palette_icon.props.badge_name = "emblem-locked"
    124         else:
    125             self.props.badge_name = None
    126             self._palette_icon.props.badge_name = None
     117        self._update_badge()
    127118
    128         interface_props = dbus.Interface(self._device,
    129                                          'org.freedesktop.DBus.Properties')
     119        interface_props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
    130120        interface_props.Get(_NM_DEVICE_IFACE, 'State',
    131121                            reply_handler=self.__get_device_state_reply_cb,
    132122                            error_handler=self.__get_device_state_error_cb)
    class WirelessNetworkView(CanvasPulsingIcon): 
    174164    def __device_state_changed_cb(self, new_state, old_state, reason):
    175165        self._device_state = new_state
    176166        self._update_state()
     167        self._update_badge()
    177168
    178169    def __update_active_ap(self, ap_path):
    179170        if ap_path in self._access_points:
    class WirelessNetworkView(CanvasPulsingIcon): 
    214205    def _update(self):
    215206        self._update_state()
    216207        self._update_color()
     208        self._update_badge()
    217209
    218210    def _update_state(self):
    219211        if self._active_ap is not None:
    class WirelessNetworkView(CanvasPulsingIcon): 
    266258        else:
    267259            self.props.base_color = self._color
    268260
     261    def _update_badge(self):
     262        if network.find_connection_by_ssid(self._name) is not None:
     263            self.props.badge_name = "emblem-favorite"
     264            self._palette_icon.props.badge_name = "emblem-favorite"
     265        elif self._flags == network.NM_802_11_AP_FLAGS_PRIVACY:
     266            self.props.badge_name = "emblem-locked"
     267            self._palette_icon.props.badge_name = "emblem-locked"
     268        else:
     269            self.props.badge_name = None
     270            self._palette_icon.props.badge_name = None
     271
    269272    def _disconnect_activate_cb(self, item):
    270         pass
     273        connection = network.find_connection_by_ssid(self._name)
     274        if connection:
     275            if self._mode == network.NM_802_11_MODE_INFRA:
     276                connection.set_disconnected()
     277
     278        obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
     279        netmgr = dbus.Interface(obj, _NM_IFACE)
     280
     281        netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
     282        active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections')
     283
     284        for conn_o in active_connections_o:
     285            obj = self._bus.get_object(_NM_IFACE, conn_o)
     286            props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
     287            state = props.Get(_NM_ACTIVE_CONN_IFACE, 'State')
     288            if state == network.NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
     289                ap_o = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
     290                if ap_o != '/' and self.find_ap(ap_o) is not None:
     291                    netmgr.DeactivateConnection(conn_o)
     292                else:
     293                    logging.error('Could not determine AP for'
     294                                  ' specific object %s' % conn_o)
    271295
    272296    def _add_ciphers_from_flags(self, flags, pairwise):
    273297        ciphers = []
    class OlpcMeshView(CanvasPulsingIcon): 
    456480        self._greyed_out = False
    457481        self._name = ''
    458482        self._device_state = None
    459         self._connection = None
    460483        self._active = False
    461484        device = mesh_mgr.mesh_device
    462485
    463486        self.connect('button-release-event', self.__button_release_event_cb)
    464487
    465         interface_props = dbus.Interface(device,
    466                                          'org.freedesktop.DBus.Properties')
     488        interface_props = dbus.Interface(device, dbus.PROPERTIES_IFACE)
    467489        interface_props.Get(_NM_DEVICE_IFACE, 'State',
    468490                            reply_handler=self.__get_device_state_reply_cb,
    469491                            error_handler=self.__get_device_state_error_cb)
    class NetworkManagerObserver(object): 
    849871        # FIXME It would be better to do all of this async, but I cannot think
    850872        # of a good way to. NM could really use some love here.
    851873
    852         netmgr_props = dbus.Interface(
    853                             self._netmgr, 'org.freedesktop.DBus.Properties')
     874        netmgr_props = dbus.Interface(self._netmgr, dbus.PROPERTIES_IFACE)
    854875        active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections')
    855876
    856877        for conn_o in active_connections_o:
    857878            obj = self._bus.get_object(_NM_IFACE, conn_o)
    858             props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
     879            props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
    859880            state = props.Get(_NM_ACTIVE_CONN_IFACE, 'State')
    860881            if state == network.NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
    861882                ap_o = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
    class NetworkManagerObserver(object): 
    879900
    880901    def _check_device(self, device_o):
    881902        device = self._bus.get_object(_NM_SERVICE, device_o)
    882         props = dbus.Interface(device, 'org.freedesktop.DBus.Properties')
     903        props = dbus.Interface(device, dbus.PROPERTIES_IFACE)
    883904
    884905        device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
    885906        if device_type == network.DEVICE_TYPE_802_11_WIRELESS:
  • src/jarabe/model/network.py

    diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py
    index 3a949da..33088c4 100644
    a b class NMSettings(dbus.service.Object): 
    330330        self.secrets_request.send(self, connection=sender,
    331331                                  response=kwargs['response'])
    332332
     333    def clear_wifi_connections(self):
     334        for uuid in self.connections.keys():
     335            conn = self.connections[uuid]
     336            if conn.type == NM_CONNECTION_TYPE_802_11_WIRELESS:
     337                conn.Removed()
     338                self.connections.pop(uuid)
     339
    333340class SecretsResponse(object):
    334341    ''' Intermediate object to report the secrets from the dialog
    335342    back to the connection object and which will inform NM
    class NMSettingsConnection(dbus.service.Object): 
    358365        self._settings = settings
    359366        self._secrets = secrets
    360367
     368    @dbus.service.signal(dbus_interface=NM_CONNECTION_IFACE,
     369                         signature='')
     370    def Removed(self):
     371        pass
     372
     373    @dbus.service.signal(dbus_interface=NM_CONNECTION_IFACE,
     374                         signature='a{sa{sv}}')
     375    def Updated(self, settings):
     376        pass
     377
    361378    def set_connected(self):
    362379        if self._settings.connection.type == NM_CONNECTION_TYPE_GSM:
    363380            self._settings.connection.timestamp = int(time.time())
    class NMSettingsConnection(dbus.service.Object): 
    366383                self._settings.connection.autoconnect = True
    367384                self._settings.connection.timestamp = int(time.time())
    368385                if self._settings.connection.type == NM_CONNECTION_TYPE_802_11_WIRELESS:
     386                    self.Updated(self._settings.get_dict())
    369387                    self.save()
    370388
     389    def set_disconnected(self):
     390        if self._settings.connection.type != NM_CONNECTION_TYPE_GSM and \
     391               self._settings.connection.autoconnect:
     392            self._settings.connection.autoconnect = False
     393            self._settings.connection.timestamp = None
     394            self.Updated(self._settings.get_dict())
     395            self.save()
     396
    371397    def set_secrets(self, secrets):
    372398        self._secrets = secrets
    373399        if self._settings.connection.type == NM_CONNECTION_TYPE_802_11_WIRELESS:
    class NMSettingsConnection(dbus.service.Object): 
    377403        return self._settings
    378404
    379405    def save(self):
    380         profile_path = env.get_profile_path()
    381         config_path = os.path.join(profile_path, 'nm', 'connections.cfg')
     406        config_path = _get_wifi_connections_path()
    382407
    383408        config = ConfigParser.ConfigParser()
    384409        try:
    class AccessPoint(gobject.GObject): 
    477502        self.mode = 0
    478503
    479504    def initialize(self):
    480         model_props = dbus.Interface(self.model,
    481             'org.freedesktop.DBus.Properties')
     505        model_props = dbus.Interface(self.model, dbus.PROPERTIES_IFACE)
    482506        model_props.GetAll(NM_ACCESSPOINT_IFACE, byte_arrays=True,
    483507                           reply_handler=self._ap_properties_changed_cb,
    484508                           error_handler=self._get_all_props_error_cb)
    def add_connection(uuid, settings, secrets=None): 
    590614    _nm_settings.add_connection(uuid, conn)
    591615    return conn
    592616
    593 def load_wifi_connections():
     617def _get_wifi_connections_path():
    594618    profile_path = env.get_profile_path()
    595     config_path = os.path.join(profile_path, 'nm', 'connections.cfg')
     619    return os.path.join(profile_path, 'nm', 'connections.cfg')
    596620
    597     config = ConfigParser.ConfigParser()
     621def _create_wifi_connections(config_path):
     622    if not os.path.exists(os.path.dirname(config_path)):
     623        os.makedirs(os.path.dirname(config_path), 0755)
     624    f = open(config_path, 'w')
     625    f.close()
     626
     627def load_wifi_connections():
     628    config_path = _get_wifi_connections_path()
    598629
    599630    if not os.path.exists(config_path):
    600         if not os.path.exists(os.path.dirname(config_path)):
    601             os.makedirs(os.path.dirname(config_path), 0755)
    602         f = open(config_path, 'w')
    603         config.write(f)
    604         f.close()
     631        _create_wifi_connections(config_path)
    605632
     633    config = ConfigParser.ConfigParser()
    606634    try:
    607635        if not config.read(config_path):
    608636            logging.error('Error reading the nm config file')
    def find_gsm_connection(): 
    708736
    709737    logging.debug('There is no gsm connection in the NMSettings.')
    710738    return None
     739
     740def count_wifi_connections():
     741    return len(get_settings().connections)
     742
     743def clear_wifi_connections():
     744    if _nm_settings is not None:
     745        _nm_settings.clear_wifi_connections()
     746
     747    config_path = _get_wifi_connections_path()
     748    _create_wifi_connections(config_path)