Skip to content

Crash: AttributeError: 'AssignAttr' object has no attribute 'name'. Did you mean: 'frame'? #10694

@gerardlaine

Description

@gerardlaine

Bug description

"""
===============================================================================
File name: page_chords_types.py
Author: Gerard
Date created: 20 feb 2020
Date last modified: 4 june 2024
Date last modified: 23 nov 2024
pylint : 23 nov 2024 Fatal error de pylint: astroid-error
Python Version: 3.12
===============================================================================
"""
import tkinter as tk

from constants import ARIAL_10_BOLD, COLORS_BG_INTERVALS, COLORS_FG_INTERVALS
from constants_chords import SHAPES, CHORDS
from doc import CHORDS_DOC
from functions import create_transient_win, get_chords_by_kind
from widgets import Bubble, create_text_box


def show_chord_doc(name, area):
    """

    :param name: name of chord
    :param area: the container : frame in which to place the transient windows
    :return:
    """
    win = create_transient_win(area, 10, 10, 'Chord Types')
    w = create_text_box(parent=win)
    # print(self.chord_name)
    doc_content = CHORDS_DOC.get(name)
    for text, tag in doc_content:
        w.insert("end", text, tag)

    # text = CHORDS_DOC[name]
    # win = create_transient_win(area)
    # doc = tk.Label(win, text=text, font=ARIAL_11, justify='left')
    # doc.grid(row=1, column=0, sticky="w", padx=10, pady=10)


class ChordsTypes:
    # pylint: disable=too-many-instance-attributes
    """
    define chords types
    """

    def __init__(self, container, area, nb_notes):
        self.idx = None
        self.container = container
        self.nb_of_notes = nb_notes

        self.area = area
        self.pad = 8
        # self.relief = "sunken"
        self.c = 'white'
        self.ct = 'lightgray'
        # = "groove"
        self.f = ARIAL_10_BOLD
        # ========
        # Titles
        # ========
        self.create_titles()

    def create_titles(self):
        """

        :return:
        """
        # first line of titles
        tk.Label(self.area, text='Chord Name', width=25, bg=self.ct, relief="groove", font=self.f).grid(
                row=0, column=0, sticky="ewns", pady=2, padx=0, rowspan=2)
        tk.Label(self.area, text='Name', bg=self.ct, relief="groove", font=self.f).grid(
                row=0, column=1, sticky="ew", pady=2, padx=0, columnspan=3)
        tk.Label(self.area, text='Type', width=4, bg=self.ct, relief="groove", font=self.f).grid(
                row=0, column=4, sticky="ewns", pady=2, padx=0, rowspan=2)
        tk.Label(self.area, text='Formula', bg=self.ct, relief="groove", font=self.f).grid(
                row=0, column=5, sticky="ewns", pady=2, padx=0, columnspan=17, rowspan=2)
        tk.Label(self.area, text='Degrees of scales where the chord is created', bg=self.ct, relief="groove",
                 font=self.f).grid(
                row=0, column=22, sticky="ew", pady=2, padx=0, columnspan=4)
        # second line of titles
        tk.Label(self.area, text='Letters', width=7, bg=self.ct, relief="groove", font=self.f).grid(
                row=1, column=1, sticky="ew", pady=2, padx=0)
        tk.Label(self.area, text='Shorts', width=7, bg=self.ct, relief="groove", font=self.f).grid(
                row=1, column=2, sticky="ew", pady=2, padx=0)
        tk.Label(self.area, text='Symbols', width=7, bg=self.ct, relief="groove", font=self.f).grid(
                row=1, column=3, sticky="ew", pady=2, padx=0)

        tk.Label(self.area, text='Major', width=8, bg=self.ct, relief="groove", font=self.f).grid(
                row=1, column=22, sticky="ew", pady=2, padx=0)
        tk.Label(self.area, text='Natural min', width=10, bg=self.ct, relief="groove", font=self.f).grid(
                row=1, column=23, sticky="ew", pady=2, padx=0)
        tk.Label(self.area, text='Harmonic min', width=12, bg=self.ct, relief="groove", font=self.f).grid(
                row=1, column=24, sticky="ew", pady=2, padx=0)
        tk.Label(self.area, text='Melodic min', width=10, bg=self.ct, relief="groove", font=self.f).grid(
                row=1, column=25, sticky="ew", pady=2, padx=0)

    def create_notes(self, idx, intervals, formula):
        """

        :param idx:
        :param intervals:
        :param formula:
        :return:
        """
        lbl = []
        # intervals_texts = [' 1 ', '   ', ' 2 ', ' b3', ' 3 ', ' 4 ', ' b5', ' 5 ', ' 5+', 'bb7', ' b7', ' 7 ', ' 8 ',
        #                    ' b9', ' 9 ', ' 9+']
        for i in range(16):
            bubble = Bubble(self.area, text='', color='white', fill=COLORS_BG_INTERVALS[i], col=i + 6,
                            row=2 + idx)  # intervals_texts[i]
            lbl.append(bubble)

        count = 0
        for i in intervals:
            # print(count)  # , formula[i])
            lbl[i].update_bubble(text=formula[count], color=COLORS_FG_INTERVALS[i])

            count = count + 1

    def line_label(self, idx, col, anchor, color, text):
        # pylint: disable=too-many-arguments
        # pylint: disable=too-many-positional-arguments
        """

        :param idx:
        :param col:
        :param anchor:
        :param color:
        :param text:
        :return:
        """
        tk.Label(self.area, text=text, anchor=anchor, font=ARIAL_10_BOLD, fg=color, bg=self.c, relief="groove").grid(
                row=idx + 2, column=col, sticky='ewns', pady=2, padx=0)

    def line_button(self, idx, col, anchor, color, text, name):

        # pylint: disable=too-many-arguments
        # pylint: disable=too-many-positional-arguments
        """

        :param idx:
        :param col:
        :param anchor:
        :param color:
        :param text:
        :param name:
        :return:
        """
        bt = tk.Button(self.area, text=text, anchor=anchor, font=ARIAL_10_BOLD, fg=color, bg=self.c, relief="groove",
                       command=lambda: show_chord_doc(name, self.container))  # self.area))
        bt.grid(row=idx + 2, column=col, sticky='ewns', pady=2, padx=0)

    def create_lines(self):
        """

        :return:
        """

        # get a chord line values
        # get a list of all the keys of the dict of names of chords (letters)

        # chords_list = list(CHORDS[nb_of_notes_str].keys())
        chords_list = get_chords_by_kind(self.nb_of_notes)
        # loop on all the chords found
        for self.idx, chord_name in enumerate(chords_list):
            # chord_name = chords_list[self.idx]
            # current_chord = CHORDS[nb_of_notes_str][chord_name]  # get the current chord
            current_chord = CHORDS[chord_name]  # get the current chord
            print(current_chord)
            # if there is no shape recorded for this chord that means the chord is unconventional
            if len(SHAPES[chords_list[self.idx]]) == 0:
                clr = 'red'
            else:
                clr = 'blue'
            self.line_button(self.idx, col=0, anchor='w', color=clr, text=current_chord['name'],
                             name=chords_list[self.idx])
            self.line_label(self.idx, col=1, anchor='center', color='red', text=chords_list[self.idx])
            self.line_label(self.idx, col=2, anchor='center', color='black', text=current_chord['short'])
            self.line_label(self.idx, col=3, anchor='center', color='black', text=current_chord['symb'])
            self.line_label(self.idx, col=4, anchor='center', color='black', text=current_chord['type'])

            self.create_notes(self.idx, current_chord['intervals'], current_chord['formula'])

            self.line_label(self.idx, col=22, anchor='w', color='black', text=current_chord['major'])
            self.line_label(self.idx, col=23, anchor='w', color='black', text=current_chord['nat'])
            self.line_label(self.idx, col=24, anchor='w', color='black', text=current_chord['harm'])
            self.line_label(self.idx, col=25, anchor='w', color='black', text=current_chord['mel'])

        tk.Label(self.area, text='Clic on chord names to get infos', anchor='w', fg='red').grid(
                row=self.idx + 10, column=0, sticky='ewns', pady=2, padx=0)
        if self.nb_of_notes == 5:
            lbl = tk.Label(self.area,
                           text='Note: If the name of the chord is written in red, '
                                'it means that the chord is unconventional and is not used ',
                           anchor='w',
                           fg='red')
            lbl.grid(row=self.idx + 20, column=0, sticky='ewns', pady=2, padx=0, columnspan=15)

    def clear(self):
        """

        :return:
        """
        if len(self.area.winfo_children()) > 0:
            for widget in self.area.winfo_children():
                widget.destroy()

    def build_page(self):
        """

        :return:
        """
        self.clear()
        self.create_titles()
        self.create_lines()


class ChordsTypes_3(tk.Frame):
    """

    """

    def __init__(self, frame_viewer, main_window):
        tk.Frame.__init__(self, frame_viewer)
        # self.nb_of_notes = kwargs.get('nb_of_notes', None)
        # print(self.nb_of_notes)
        self.nb_of_notes = 3
        self.main_window = main_window
        self.pad = 8

        set_title(self)

        # ==============================================================================================================
        # CHOOSE AREA
        # ==============================================================================================================

        self.choose_area = tk.Frame(self)
        self.choose_area.grid(row=1, column=0, sticky="ew", columnspan=8, padx=self.pad, pady=self.pad)

        # ==============================================================================================================
        # FRAME AREA
        # ==============================================================================================================

        self.area = tk.LabelFrame(self, text="3 NOTES CHORDS", font=ARIAL_10_BOLD)
        self.area.grid(row=2, column=0, sticky="ew", columnspan=8, padx=self.pad, pady=self.pad)

        button_3 = tk.Button(self.choose_area, text='3 notes chords', bg='red')
        button_3.grid(row=0, column=0, padx=5)

        button_4 = tk.Button(self.choose_area, text='4 notes chords',
                             command=lambda: self.main_window.show_page(ChordsTypes_4))
        button_4.grid(row=0, column=1, padx=5)

        button_5 = tk.Button(self.choose_area, text='5 notes chords',
                             command=lambda: self.main_window.show_page(ChordsTypes_5))
        button_5.grid(row=0, column=2, padx=5)

        self.build_page(self.nb_of_notes)

    def build_page(self, nb_notes):
        """

        :param nb_notes:
        :return:
        """
        p = ChordsTypes(self.main_window, self.area, nb_notes)
        p.build_page()


class ChordsTypes_4(tk.Frame):

    def __init__(self, frame_viewer, main_window):
        tk.Frame.__init__(self, frame_viewer)
        # self.nb_of_notes = kwargs.get('nb_of_notes', None)
        # print(self.nb_of_notes)
        self.nb_of_notes = 4
        self.main_window = main_window
        self.pad = 8

        set_title(self)

        # ==============================================================================================================
        # CHOOSE AREA
        # ==============================================================================================================

        self.choose_area = tk.Frame(self)
        self.choose_area.grid(row=1, column=0, sticky="ew", columnspan=8, padx=self.pad, pady=self.pad)

        # ==============================================================================================================
        # FRAME AREA
        # ==============================================================================================================

        self.area = tk.LabelFrame(self, text="4 NOTES CHORDS", font=ARIAL_10_BOLD)
        self.area.grid(row=2, column=0, sticky="ew", columnspan=8, padx=self.pad, pady=self.pad)

        button_3 = tk.Button(self.choose_area, text='3 notes chords',
                             command=lambda: self.main_window.show_page(ChordsTypes_3))
        button_3.grid(row=0, column=0, padx=5)

        button_4 = tk.Button(self.choose_area, text='4 notes chords', bg='red')
        button_4.grid(row=0, column=1, padx=5)

        button_5 = tk.Button(self.choose_area, text='5 notes chords',
                             command=lambda: self.main_window.show_page(ChordsTypes_5))
        button_5.grid(row=0, column=2, padx=5)

        self.build_page(self.nb_of_notes)

    def build_page(self, nb_notes):
        """

        :param nb_notes:
        :return:
        """
        p = ChordsTypes(self.main_window, self.area, nb_notes)
        p.build_page()


class ChordsTypes_5(tk.Frame):

    def __init__(self, frame_viewer, main_window):
        tk.Frame.__init__(self, frame_viewer)
        self.nb_of_notes = 5
        self.main_window = main_window
        self.pad = 8

        set_title(self)

        # ==============================================================================================================
        # CHOOSE AREA
        # ==============================================================================================================

        self.choose_area = tk.Frame(self)
        self.choose_area.grid(row=1, column=0, sticky="ew", columnspan=8, padx=self.pad, pady=self.pad)

        # ==============================================================================================================
        # FRAME AREA
        # ==============================================================================================================

        self.area = tk.LabelFrame(self, text="5 NOTES CHORDS", font=ARIAL_10_BOLD)
        self.area.grid(row=2, column=0, sticky="ew", columnspan=8, padx=self.pad, pady=self.pad)

        button_3 = tk.Button(self.choose_area, text='3 notes chords',
                             command=lambda: self.main_window.show_page(ChordsTypes_3))
        button_3.grid(row=0, column=0, padx=5)

        button_4 = tk.Button(self.choose_area, text='4 notes chords',
                             command=lambda: self.main_window.show_page(ChordsTypes_4))
        button_4.grid(row=0, column=1, padx=5)

        button_5 = tk.Button(self.choose_area, text='5 notes chords', bg='red')
        button_5.grid(row=0, column=2, padx=5)

        self.build_page(self.nb_of_notes)

    def build_page(self, nb_notes):
        """

        :param nb_notes:
        :return:
        """
        p = ChordsTypes(self.main_window, self.area, nb_notes)
        p.build_page()


def set_title(parent):
    """

    :param parent:
    :return:
    """
    lbl = tk.Label(parent, text='Table of all the chords built by the diatonic harmonization '
                                'of the major, minor, harmonic minor and  melodic minor scales',
                   font=ARIAL_10_BOLD, relief="raised", bg='white')
    lbl.grid(row=0, column=0, sticky="ew", columnspan=8, padx=8, pady=8)


def main():
    """
    test
    :return:
    """
    # ATTENTION : this test don't allow to use the lambda command : self.main_window.show_page(ChordsTypes_5))
    # because ihe main_window (root) does not have the methode show_page() defined
    root = tk.Tk()
    f = tk.Frame(root)
    f.pack()
    n = ChordsTypes_3(frame_viewer=f, main_window=root)
    n.pack()

    root.mainloop()


if __name__ == '__main__':
    main()

Command used

pylint a.py

Pylint output

pylint crashed with a ``AstroidError`` and with the following stacktrace:
Traceback (most recent call last):
  File "C:\Users\Gerard\PycharmProjects\colored_fretboard\.venv\Lib\site-packages\pylint\lint\pylinter.py", line 788, in _lint_file
    check_astroid_module(module)
    ~~~~~~~~~~~~~~~~~~~~^^^^^^^^
  File "C:\Users\Gerard\PycharmProjects\colored_fretboard\.venv\Lib\site-packages\pylint\lint\pylinter.py", line 1020, in check_astroid_module
    retval = self._check_astroid_module(
        ast_node, walker, rawcheckers, tokencheckers
    )
  File "C:\Users\Gerard\PycharmProjects\colored_fretboard\.venv\Lib\site-packages\pylint\lint\pylinter.py", line 1072, in _check_astroid_module
    walker.walk(node)
    ~~~~~~~~~~~^^^^^^
  File "C:\Users\Gerard\PycharmProjects\colored_fretboard\.venv\Lib\site-packages\pylint\utils\ast_walker.py", line 90, in walk
    self.walk(child)
    ~~~~~~~~~^^^^^^^
  File "C:\Users\Gerard\PycharmProjects\colored_fretboard\.venv\Lib\site-packages\pylint\utils\ast_walker.py", line 90, in walk
    self.walk(child)
    ~~~~~~~~~^^^^^^^
  File "C:\Users\Gerard\PycharmProjects\colored_fretboard\.venv\Lib\site-packages\pylint\utils\ast_walker.py", line 90, in walk
    self.walk(child)
    ~~~~~~~~~^^^^^^^
  File "C:\Users\Gerard\PycharmProjects\colored_fretboard\.venv\Lib\site-packages\pylint\utils\ast_walker.py", line 87, in walk
    callback(astroid)
    ~~~~~~~~^^^^^^^^^
  File "C:\Users\Gerard\PycharmProjects\colored_fretboard\.venv\Lib\site-packages\pylint\checkers\refactoring\refactoring_checker.py", line 746, in visit_for
    self._check_unnecessary_list_index_lookup(node)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "C:\Users\Gerard\PycharmProjects\colored_fretboard\.venv\Lib\site-packages\pylint\checkers\refactoring\refactoring_checker.py", line 2375, in _check_unnecessary_list_index_lookup
    index.name != node.target.elts[0].name
                  ^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'AssignAttr' object has no attribute 'name'. Did you mean: 'frame'?

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\Gerard\PycharmProjects\colored_fretboard\.venv\Lib\site-packages\pylint\lint\pylinter.py", line 752, in _lint_files
    self._lint_file(fileitem, module, check_astroid_module)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Gerard\PycharmProjects\colored_fretboard\.venv\Lib\site-packages\pylint\lint\pylinter.py", line 790, in _lint_file
    raise astroid.AstroidError from e
astroid.exceptions.AstroidError

Expected behavior

No crash.

Pylint version

pylint 3.3.8
astroid 3.3.11
Python 3.13.7 (tags/v3.13.7:bcee1c3, Aug 14 2025, 14:15:11) [MSC v.1944 64 bit (AMD64)]

OS / Environment

win32 (Windows)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Crash 💥A bug that makes pylint crash

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions