Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash in consider-using-enumerate when using len(range()) and using the index to access an element of a list inside and element of a list #10099

Open
gerardlaine opened this issue Nov 25, 2024 · 1 comment
Labels
Crash 💥 A bug that makes pylint crash Needs PR This issue is accepted, sufficiently specified and now needs an implementation

Comments

@gerardlaine
Copy link

Bug description

When parsing the following a.py:

"""
===============================================================================
    File name: page_chords_types.py
    Author: Gerard
    Date created: 20 feb 2020
    Date last modified: 4 june 2024
    Python Version: 3.12

===============================================================================
"""
import tkinter as tk

from doc import CHORDS_DOC
from functions import create_transient_win
from widgets import Bubble
from constants import ARIAL_11, ARIAL_10_BOLD, COLORS_BG_INTERVALS, SHAPES, COLORS_FG_INTERVALS, CHORDS


def show_chord_doc(name, area):
    """

    :param name: name of chord
    :param area: the container : frame in which to place the transient windows
    :return:
    """

    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):
        """

        :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):
        """

        :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)
        nb_of_notes_str = ''
        if self.nb_of_notes == 3:
            nb_of_notes_str = 'chord_3_notes'
        if self.nb_of_notes == 4:
            nb_of_notes_str = 'chord_4_notes'
        if self.nb_of_notes == 5:
            nb_of_notes_str = 'chord_5_notes'

        chords_list = list(CHORDS[nb_of_notes_str].keys())

        # loop on all the chords found
        for self.idx in range(len(chords_list)):
            current_chord = CHORDS[nb_of_notes_str][chords_list[self.idx]]  # get the 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)

        # tk.Label(self.choose_area, text='3 notes chords', bg="red", fg='white', relief="raised").grid(
        # row=0, column=0, padx=5)
        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)

        # tk.Label(self.choose_area, text='4 notes chords', bg="red", fg='white', relief="raised").grid(
        # row=0, column=1, 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)
        # tk.Label(self.choose_area, text='5 notes chords', bg="red", fg='white', relief="raised").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 builts 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 lamba 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 "D:\PYTHON 3.12.2\Lib\site-packages\pylint\lint\pylinter.py", line 789, in _lint_file
    check_astroid_module(module)
  File "D:\PYTHON 3.12.2\Lib\site-packages\pylint\lint\pylinter.py", line 1018, in check_astroid_module
    retval = self._check_astroid_module(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\PYTHON 3.12.2\Lib\site-packages\pylint\lint\pylinter.py", line 1070, in _check_astroid_module
    walker.walk(node)
  File "D:\PYTHON 3.12.2\Lib\site-packages\pylint\utils\ast_walker.py", line 94, in walk
    self.walk(child)
  File "D:\PYTHON 3.12.2\Lib\site-packages\pylint\utils\ast_walker.py", line 94, in walk
    self.walk(child)
  File "D:\PYTHON 3.12.2\Lib\site-packages\pylint\utils\ast_walker.py", line 94, in walk
    self.walk(child)
  File "D:\PYTHON 3.12.2\Lib\site-packages\pylint\utils\ast_walker.py", line 91, in walk
    callback(astroid)
  File "D:\PYTHON 3.12.2\Lib\site-packages\pylint\checkers\refactoring\recommendation_checker.py", line 191, in visit_for
    self._check_consider_using_enumerate(node)
  File "D:\PYTHON 3.12.2\Lib\site-packages\pylint\checkers\refactoring\recommendation_checker.py", line 259, in _check_consider_using_enumerate
    if value.name == node.target.name and (
                     ^^^^^^^^^^^^^^^^
AttributeError: 'AssignAttr' object has no attribute 'name'

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

Traceback (most recent call last):
  File "D:\PYTHON 3.12.2\Lib\site-packages\pylint\lint\pylinter.py", line 753, in _lint_files
    self._lint_file(fileitem, module, check_astroid_module)
  File "D:\PYTHON 3.12.2\Lib\site-packages\pylint\lint\pylinter.py", line 791, in _lint_file
    raise astroid.AstroidError from e
astroid.exceptions.AstroidError

Expected behavior

No crash.

Pylint version

pylint 3.2.7
astroid 3.2.4
Python 3.12.2 (tags/v3.12.2:6abddd9, Feb  6 2024, 21:26:36) [MSC v.1937 64 bit (AMD64)]

OS / Environment

win32 (Windows)

Additional dependencies

@Pierre-Sassoulas
Copy link
Member

Thank you for opening the issue, I reproduced with :

def create_lines(self):
    for self.idx in range(len(chords_list)):
        current_chord = CHORDS[nb_of_notes_str][self.idx]

@Pierre-Sassoulas Pierre-Sassoulas added Crash 💥 A bug that makes pylint crash Needs PR This issue is accepted, sufficiently specified and now needs an implementation labels Nov 25, 2024
@Pierre-Sassoulas Pierre-Sassoulas changed the title Crash ````astroid-error Crash in consider-using-enumerate when using len(range()) and using the index to access an element of a list inside and element of a list Nov 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Crash 💥 A bug that makes pylint crash Needs PR This issue is accepted, sufficiently specified and now needs an implementation
Projects
None yet
Development

No branches or pull requests

2 participants