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

Setting ui.number min/max property is failing after version nicegui-1.4.19 #2950

Closed
mwarrens63 opened this issue Apr 24, 2024 · 1 comment
Closed
Assignees
Labels
bug Something isn't working
Milestone

Comments

@mwarrens63
Copy link

mwarrens63 commented Apr 24, 2024

Description

The code that follows implements a ScoreCard Class for a golf league application. It works perfectly if it is run in nicegui-1.4.19 virtual env. It fails with the following error if it is run in later envs (e.g., nicegui-1.4.20 or greater):

Error Output:

(bugTest) user@Puget-209007:bugTest$ /home/user/projects/bugTest/bin/python /home/user/projects/bugTest/scoreCard.py
setParList: [3, 4, 5, 3, 4, 5, 4, 4, 4]
Traceback (most recent call last):
  File "/home/user/projects/bugTest/scoreCard.py", line 231, in <module>
    main()
  File "/home/user/projects/bugTest/scoreCard.py", line 225, in main
    scc.setParList([3,4,5,3,4,5,4,4,4])
  File "/home/user/projects/bugTest/scoreCard.py", line 133, in setParList
    self.setCrseHoleRange(parList)
  File "/home/user/projects/bugTest/scoreCard.py", line 164, in setCrseHoleRange
    item.min = parvalue - 2 # Hole in one
  File "/home/user/projects/bugTest/lib/python3.10/site-packages/nicegui/elements/number.py", line 75, in min
    if self._props['min'] == value:
KeyError: 'min'

Code:

class ScoreCard:
    """
    ScoreCard: A component class used by the tournamentTeamPlayer class
    for entering tournament team player scores.
    """
    def __init__(self, ui, test: bool = False):
        """
        __init__ Defines class variables and instance variables. Defines screen widgets and layout
        for displaying and entering team player score cards.

        Args:
            ui (class): ui reference imported from nicegui
            test (bool, optional): Test mode, Defaults to False.
        """
        
        self.parList = []
        self.crseHoleParList = []
        self.crseScoreCard = []
        self.scoreCardScores = []
        self.points = 0
        
        
        with ui.card().tight().classes('window-width row justify-left items-left text-sm bg-gray-100'):
            with ui.element('div').classes('text-left text-lg underline'):
                self.scoreCardTitle = ui.label("")
            ui.separator().classes('h-1')  
            with ui.row().classes(add = 'text-center underline'):
                ui.label("Hole:").classes(add = 'text-left w-20')
                self.crseHoleLabel1 = ui.label("1").classes(add = 'w-20')
                self.crseHoleLabel2 = ui.label("2").classes(add = 'w-20')
                self.crseHoleLabel3 = ui.label("3").classes(add = 'w-20')
                self.crseHoleLabel4 = ui.label("4").classes(add = 'w-20')
                self.crseHoleLabel5 = ui.label("5").classes(add = 'w-20')
                self.crseHoleLabel6 = ui.label("6").classes(add = 'w-20')
                self.crseHoleLabel7 = ui.label("7").classes(add = 'w-20')
                self.crseHoleLabel8 = ui.label("8").classes(add = 'w-20')
                self.crseHoleLabel9 = ui.label("9").classes(add = 'w-20')
            with ui.row().classes(add = 'text-center'):
                ui.label("Par:").classes(add = 'text-left w-20')
                self.crseHolePar1 = ui.label("").classes(add = 'w-20')
                self.crseHoleParList.append(self.crseHolePar1)
                
                self.crseHolePar2 = ui.label("").classes(add = 'w-20')
                self.crseHoleParList.append(self.crseHolePar2)
                
                self.crseHolePar3 = ui.label("").classes(add = 'w-20')
                self.crseHoleParList.append(self.crseHolePar3)
                
                self.crseHolePar4 = ui.label("").classes(add = 'w-20')
                self.crseHoleParList.append(self.crseHolePar4)
                
                self.crseHolePar5 = ui.label("").classes(add = 'w-20')
                self.crseHoleParList.append(self.crseHolePar5)
                
                self.crseHolePar6 = ui.label("").classes(add = 'w-20')
                self.crseHoleParList.append(self.crseHolePar6)
                
                self.crseHolePar7 = ui.label("").classes(add = 'w-20')
                self.crseHoleParList.append(self.crseHolePar7)
                
                self.crseHolePar8 = ui.label("").classes(add = 'w-20')
                self.crseHoleParList.append(self.crseHolePar8)
                
                self.crseHolePar9 = ui.label("").classes(add = 'w-20')
                self.crseHoleParList.append(self.crseHolePar9)
            ui.separator().classes('h-1')
            with ui.row().classes(add = 'text-center'):
                ui.label("Score:").classes(add = 'text-left w-20')
                self.crseHole1 = ui.number(label='Score').props('outlined border-4').classes(add = 'w-20')
                self.crseScoreCard.append(self.crseHole1)
                
                self.crseHole2 = ui.number(label='Score').props('outlined border-4').classes(add = 'w-20')
                self.crseScoreCard.append(self.crseHole2)
                
                self.crseHole3 = ui.number(label='Score').props('outlined border-4').classes(add = 'w-20')
                self.crseScoreCard.append(self.crseHole3)
                
                self.crseHole4 = ui.number(label='Score').props('outlined border-4').classes(add = 'w-20')
                self.crseScoreCard.append(self.crseHole4)
                
                self.crseHole5 = ui.number(label='Score').props('outlined border-4').classes(add = 'w-20')
                self.crseScoreCard.append(self.crseHole5)
                
                self.crseHole6 = ui.number(label='Score').props('outlined border-4').classes(add = 'w-20')
                self.crseScoreCard.append(self.crseHole6)
                
                self.crseHole7 = ui.number(label='Score').props('outlined border-4').classes(add = 'w-20')
                self.crseScoreCard.append(self.crseHole7)
                
                self.crseHole8 = ui.number(label='Score').props('outlined border-4').classes(add = 'w-20')
                self.crseScoreCard.append(self.crseHole8)
                
                self.crseHole9 = ui.number(label='Score').props('outlined border-4').classes(add = 'w-20')
                self.crseScoreCard.append(self.crseHole9)
            ui.separator().classes('h-1')
            # Note addition of buttons for testing this class.  These are turned off when used by the TournamentTeamPlayer class
            if test:
                self.clrButton = ui.button("Clear", on_click = self.clear).classes(add = 'items-left')
                ui.separator().classes('h-1')    
    #--End __init__()------------------------------------------------------------------------------------------
    
    #--Methods-------------------------------------------------------------------------------------------------
    def setScoreCardTitle(self, title: str) -> None:
        """
        setScoreCardTitle Sets score card title (usually course name)

        Args:
            title (str): Course name
        """
        self.scoreCardTitle.set_text('')
        self.scoreCardTitle.set_text('Score Card: {}'.format(title))
        return()
    
    
    def setParList(self, parList: list) -> None:
        """
        setParList Sets the par score for each of the holes, and
        the score range (e.g., 2-6 for par 4 hole) for each of the course holes.

        Args:
            parList (list): List of 9 par scores
        """
        print("setParList: {}".format(parList))
        self.parList = parList
        for label,item in zip(self.crseHoleParList, parList):
            label.text = item
            
        # print('In scoreCard.py: Executing setCrseHoleRange()')
        self.setCrseHoleRange(parList)
        return()
    
    
    def setScores(self, scoreList: list) -> None:
        """
        setScores Set scores

        Args:
            scoreList (list): List of scores for the course
        """
        print("ScoreCard: setScores")
        if scoreList != []:
            for score,item in zip(scoreList, self.crseScoreCard):
                item.value = score
        else:
            for item in self.crseScoreCard:
                item.value = None
        return()
    
    
    def setCrseHoleRange(self, parList) -> None:
        """
        setCrseHoleRange Set Stapleford scoring range for the course holes.

        Args:
            parList (_type_): The par list for the course holes.
        """
        # print("setCrseHoleRange: {}".format(parList))
        for item, parvalue in zip(self.crseScoreCard, parList):
            if parvalue == 3:
                item.min = parvalue - 2 # Hole in one
                item.max = parvalue + 2 # Double bogey'
            else:
                print(parvalue) 
                item.min = parvalue - 3 # Hole in one on par 4, double-eagle on par 5
                item.max = parvalue + 2 # Double bogey
                
            item.update() #Note: This is required
        return()
    
    
    def getScores(self) -> list:
        """
        getScores Retrieve list of scores from score card widget

        Returns:
            list: List of scores (int)
        """
        scoresList = []
        for item in self.crseScoreCard:
            scoresList.append(item.value)
        scoresList = [int(item) for item in scoresList if item != None]
        return(scoresList)
    
    
    def clear(self) -> None:
        """
        clear Executed when TEST <Clear Button> is clicked. 
        Clear score card widget par list and scores
        """
        self.setScoreCardTitle("")
        for label in self.crseHoleParList:
            label.text = ""
        for item in self.crseScoreCard:
                item.value = None
        return()
    
    
    def validateScoreCard(self) -> bool:
        """
        validateScoreCard Check score card widget for null values

        Returns:
            bool: False if any score card value is missing
        """
        for item in self.crseScoreCard:
            # print("hole value: ",item.value)
            if item.value == None:
                item.run_method('focus')
                ui.notify("Input required!", type='negative')
                return(False)
        
        return(True)
    
    #--End Methods---------------------------------------------------------------------------------------------
        
def main():

    scc = ScoreCard(ui, test=True)
    
    scc.setScoreCardTitle("Mike")
    scc.setParList([3,4,5,3,4,5,4,4,4])

    ui.run(reload = False)


if __name__ == '__main__':
	main()
@falkoschindler
Copy link
Contributor

Thanks for reporting this bug, @mwarrens63!
It looks like it has been introduced by PR #2753.

Here is a minimum reproduction:

number = ui.number()
number.min = 42

It should be an easy fix. 🙂

@falkoschindler falkoschindler self-assigned this Apr 24, 2024
@falkoschindler falkoschindler added the bug Something isn't working label Apr 24, 2024
@falkoschindler falkoschindler added this to the 1.4.23 milestone Apr 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants