LINUX.ORG.RU

Появляется NoneType объект treeview path Gtk3 + Python3

 , ,


0

1

Всем доброго времени суток. Не пойму появления «пустого» объекта treeview path при подключении treeview к сигналу 'cursor_changed'. При каждом первом (только первом) срабатывании функции по сигналу первая попытка получить treepath приводит к TypeError. Последующие уже нормально. Приходится либо через try либо через if отлавливать nonetype obj.

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import re
import gi
import subprocess
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk, Gdk


class Get_Data:

    def __init__(self):
        self.s_list = []

    def ret_soft_info(self, n_soft):
        self.s_list = []
        with subprocess.Popen(["snap", "info", n_soft], stdout=subprocess.PIPE) as proc:
            self.s_list = proc.stdout.read().decode('utf-8')

        return self.s_list

    def ret_soft_find(self, n_soft):
        c = []
        self.s_list = []
        with subprocess.Popen(["snap", "find", n_soft], stdout=subprocess.PIPE) as proc:
            b = re.findall(r'(.+?)\n', proc.stdout.read().decode('utf-8'), re.M)
        if b == []:
            return ['', 'No matching snaps']
        for x in b:
            c.append(re.findall(r'^(.+?)\s{2,}(.+?)\s{2,}(.+?)\s{2,}(.+?)\s{2,}(.+?)$', x, re.M))
        for x in c:
            for z in x:
                self.s_list.append(list(z))

        return self.s_list


    # Функция отображения существующих пакетов
    def ret_soft_list(self):
        z = []
        s_list = []
        with subprocess.Popen(["snap", "list"], stdout=subprocess.PIPE) as proc:
            for x in re.findall(r'(^.*?$)', proc.stdout.read().decode('utf-8'), re.MULTILINE):
                y = re.sub(r'\s{2,}', ' ', x)
                if y != '':
                    z.append(y)
        for x in z:
            s_list.append(x.split(' '))

        return s_list


class TreeViews(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="View snap packet")
        self.set_border_width(5)
        self.set_default_size(700, 490)
        self.set_position(Gtk.WindowPosition(1))

        self.m_gdata = Get_Data()
        self.state_b = "off"
        self.state_find = "off"
        self.m_run_prog = ''

        self.m_menu_r = Gtk.Menu()
        self.m_menu_run = Gtk.MenuItem("Run")
        self.m_menu_r.append(self.m_menu_run)
        self.m_menu_run.connect("activate", self.run_snap_prog)
        self.m_menu_r.show_all()

        self.m_menu_i = Gtk.Menu()
        self.m_menu_inst = Gtk.MenuItem("Install")
        self.m_menu_i.append(self.m_menu_inst)
        self.m_menu_inst.connect("activate", self.install_snap_prog)
        self.m_menu_i.show_all()

        self.treeview = Gtk.TreeView.new()
        self.treeview.connect('cursor_changed', self.curs_chenge)
        self.treeview.connect("button_press_event", self.mouse_r_click)
        self.treeview.props.activate_on_single_click = True
        self.treeview.props.enable_grid_lines = True
        self.treeview.props.enable_tree_lines = True
        self.treeview.props.enable_search = True
        self.treeview.props.search_column = 0

        self.m_fixed = Gtk.Fixed()
        self.add(self.m_fixed)

        self.scrollable_t = Gtk.ScrolledWindow()
        self.scrollable_t.set_shadow_type(Gtk.ShadowType(1))
        self.scrollable_t.set_size_request(650, 350)
        self.scrollable_t.add(self.treeview)

        self.m_fixed.put(self.scrollable_t, 20, 1)

        self.m_label = Gtk.Label('')
        self.m_label.set_selectable(True)

        self.m_frame = Gtk.Frame.new('Info')
        self.m_frame.set_shadow_type(Gtk.ShadowType(2))
        self.m_frame.set_size_request(650, 50)
        self.m_frame.add(self.m_label)

        self.m_fixed.put(self.m_frame, 20, 360)

        self.m_entry = Gtk.Entry.new_with_buffer(Gtk.EntryBuffer.new(None, -1))
        self.m_entry.connect('key-press-event', self.on_ent_pres)

        self.m_fixed.put(self.m_entry, 20, 430)

        self.m_checkbutton = Gtk.CheckButton("Find paket")
        self.m_checkbutton.connect("toggled", self.check_b_find_toggled, 'f')

        self.m_fixed.put(self.m_checkbutton, 190, 435)

        self.m_button_сlear = Gtk.Button.new_with_label("Clear")
        self.m_button_сlear.connect("clicked", self.on_click_button_c)
        self.m_button_сlear.set_size_request(100, 25)

        self.m_fixed.put(self.m_button_сlear, 300, 430)

        self.m_button_present = Gtk.Button.new_with_label("InSystem")
        self.m_button_present.set_size_request(100, 25)
        self.m_button_present.connect("clicked", self.present_pakets)

        self.m_fixed.put(self.m_button_present, 410, 430)

        self.m_button_exit = Gtk.Button.new_with_label("Exit")
        self.m_button_exit.connect("clicked", self.m_exit)
        self.m_button_exit.set_size_request(100, 25)

        self.m_fixed.put(self.m_button_exit, 520, 430)

    def install_snap_prog(self, menuitem):
        if self.m_run_prog != '':
            subprocess.run(["snap", "install", self.m_run_prog])

    def run_snap_prog(self, menuitem):
        if self.m_run_prog != '':
            subprocess.Popen(["snap", "run", self.m_run_prog])

    def curs_chenge(self, widget):
        model = self.treeview.get_model()
        mpath, mcol = self.treeview.get_cursor()
        print(mpath, mcol)
        if mpath == None:
            return False
        else:
            m_iter = model.get_iter(mpath)
            self.m_run_prog = model.get_value(m_iter, 0)
            self.m_label.set_text(self.m_run_prog)
            self.m_label.set_tooltip_text(self.m_gdata.ret_soft_info(self.m_run_prog))

    def mouse_r_click(self, widget, event):
        if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3 and self.state_find == 'off':
            self.m_menu_r.popup(None, None, None, None, event.button, event.time)
        if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3 and self.state_find == 'on':
            self.m_menu_i.popup(None, None, None, None, event.button, event.time)

    def check_b_find_toggled(self, button, name):
        if button.get_active():
            self.state_b = "on"
        else:
            self.state_b = "off"

    def on_ent_pres(self, entry_obj, event_key):
        if Gdk.keyval_name(event_key.keyval) == 'Return':
            if self.state_b == "on":
                self.find_pakets()
                self.m_checkbutton.set_active(False)

    # Функция поиска пакетов
    def find_pakets(self):
        self.treeview.set_model(Gtk.ListStore(str, str, str, str, str))
        for software_ref in self.m_gdata.ret_soft_find(self.m_entry.get_text())[1:]:
            if 'No matching snaps' in software_ref:
                self.m_label.set_text('No matching snaps for "' + self.m_entry.get_text() + '"')
                return False
            else:
                self.treeview.get_model().append(software_ref)
        for i, column_title in enumerate(["Name", "Version", "Publisher", "Notes", "Summary"]):
            renderer = Gtk.CellRendererText()
            column = Gtk.TreeViewColumn(column_title, renderer, text=i)
            column.set_expand(True)
            self.treeview.append_column(column)
        self.show_all()
        self.state_find = 'on'

    # Функция отображения существующих пакетов
    def present_pakets(self, batton):
        self.treeview.set_model(Gtk.ListStore(str, str, str, str, str, str))
        for software_ref in self.m_gdata.ret_soft_list()[1:]:
            self.treeview.get_model().append(software_ref)
        for i, column_title in enumerate(["Name", "Version", "Rev", "Tracking", "Publisher", "Notes"]):
            renderer = Gtk.CellRendererText()
            column = Gtk.TreeViewColumn(column_title, renderer, text=i)
            column.set_expand(True)
            self.treeview.append_column(column)
        self.show_all()
        self.state_find = 'off'

    def on_click_button_c(self, button):
        for x in self.treeview.get_columns():
            self.treeview.remove_column(x)
        self.state_find = 'off'
        self.m_entry.set_text('')
        self.m_label.set_text('')
        self.m_label.set_tooltip_text('')

    def m_exit(self, button):
        Gtk.main_quit()


win = TreeViews()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
<Gtk.ListStore object at 0x7f00ee5b8af8 (GtkListStore at 0x296f150)> None None
Traceback (most recent call last):
  File "Gtk_win_3.py", line 152, in curs_chenge
    m_iter = model.get_iter(mpath)
  File "/usr/lib/python3/dist-packages/gi/overrides/Gtk.py", line 836, in get_iter
    path = self._coerce_path(path)
  File "/usr/lib/python3/dist-packages/gi/overrides/Gtk.py", line 811, in _coerce_path
    return TreePath(path)
  File "/usr/lib/python3/dist-packages/gi/overrides/Gtk.py", line 1175, in __new__
    path = ":".join(str(val) for val in path)
TypeError: 'NoneType' object is not iterable


Последнее исправление: ivsatel (всего исправлений: 1)

У меня всё работает. У тебя не работает — отлаживай, какие проблемы? Или вставь костыль, и пусть работает.

Virtuos86 ★★★★★
()
Ответ на: комментарий от Virtuos86

Думаю я не правильно в данном случае получаю path и collumn. Т.к. согласно документации:

 If the cursor isn’t currently set, the current path will be None. If no column currently has focus, the current focus column will be None. 

ivsatel
() автор топика
Ответ на: комментарий от Virtuos86

В процессе) Но вопрос остался. На сколько я понимаю,сигнал ‘cursor_changed’ также появляется при инициализации treeview, а так ка курсор не находится не в одной строке, это и порождает ошибку. Как я и говорил, можно через try или if фильтровать состояние объекта, но думаю есть более правильный путь получения path и column. Чем получать каждый раз эту ошибку.

ivsatel
() автор топика
Ответ на: комментарий от ivsatel

Да какой «правильный»? Это поведение описано в документации. Считай, это часть API. Через if обработать этот особый случай и будет правильно.

if mpath is None:
   return
Virtuos86 ★★★★★
()
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')

избыточно. не существовало никогда стабильных версий Gtk и Gdk ниже 3.0, в которых есть интроспекция

eternal_sorrow ★★★★★
()
Последнее исправление: eternal_sorrow (всего исправлений: 1)
Ответ на: комментарий от eternal_sorrow
$ python3
>>> from gi.repository import Gtk
__main__:1: PyGIWarning: Gtk was imported without specifying a version first. Use gi.require_version('Gtk', '3.0') before import to ensure that the right version gets loaded.
gag ★★★★★
()
Ответ на: комментарий от gag

не знал о таком ворнинге. сам всегда писал gi.require_version('Gtk', '3.x'), где x больше 0, потому что приложению нужны были фичи, добавленные в более поздних версиях

eternal_sorrow ★★★★★
()
Ответ на: комментарий от Andreezy

Я вообще пишу if not var: …

Это когда var может быть None? В скриптах сойдет :).

Virtuos86 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.