-1

I am working on a simple GUI using pygame. At some point I was fed up with the constant indentation errors due to tabs and spaces mixing, so I decided to use vi to replace all tabs with 4 spaces. After that I get some error about pygame.font.SysFont not being initialized, even though it was before. Naturally I figure this has something to do with me just changing the tabs to spaces so I make sure everything is indented correctly etc. I comment out 95% of the code and start comparing with an old version of the code, copying lines from the old code to the new one. Since they seem to be identical (using cat -A file.py to compare also the invisible characters).

I finally find out that this is the culprit: trouble-maker

This is the only thing (that is not in triple quotes) that is different between both files. Changing this line to have a tab does indeed fix the problem. So, problem solved, I guess.

My question is: How is this possible? Shouldn't the spaces be less error-prone than the tab?

The code looks like this:

import pygame
pygame.init()

class GameMenu():
    def __init__(self, screen, items, bg_color=(237,237,223), font="Verdana", font_size=30,
                font_color=(237, 28, 36)):
        self.screen = screen
        self.scr_width = self.screen.get_rect().width
        self.scr_height = self.screen.get_rect().height

        self.bg_color = bg_color
        self.clock = pygame.time.Clock()

        self.items = items
        self.font = pygame.font.SysFont(font, font_size)
        self.font_color = font_color
        """
        rest of the code commented out
    """    
    pygame.quit()

if __name__ == "__main__":
    screensize = 0
    screen = pygame.display.set_mode((640, 480), screensize, 32)

    menu_items = ('1', '2', '3', '4', '5')

    pygame.display.set_caption('numbers')
    pygame.mouse.set_visible(True)
    gm = GameMenu(screen, menu_items)

What am I missing here? Why would a tab in front pygame.quit() work, but without 4 spaces it gives "pygame.error: font not initialized"

EDIT: Here is the traceback

Traceback (most recent call last):
  File "testMenu.py", line 168, in <module>
      gm = GameMenu(screen, menu_items)
        File "testMenu.py", line 31, in __init__
            self.font = pygame.font.SysFont(font, font_size)
              File "/usr/lib/python2.7/dist-packages/pygame/sysfont.py", 
              line 614, in SysFont
                  return constructor(fontname, size, set_bold, 
                  set_italic)
                    File 
                    "/usr/lib/python2.7/dist-packages/pygame/sysfont.py", line 537, in font_constructor
                        font = pygame.font.Font(fontpath, size)
                        pygame.error: font not initialized

Please also note that it is not required to do pygame.font.init(), see https://www.pygame.org/docs/tut/ImportInit.html

F. Pareto
  • 304
  • 2
  • 10
  • Can you provide the traceback, etc.? (The output the interpreter shows). – Willem Van Onsem Jan 19 '17 at 11:45
  • Tabs are [8 spaces in Python, not 4](https://docs.python.org/2/reference/lexical_analysis.html#indentation). – wildwilhelm Jan 19 '17 at 11:51
  • Is that `pygame.quit()` supposed to be inside the `__init__` method? FWIW, Python uses fixed tab stops of size 8. – PM 2Ring Jan 19 '17 at 11:52
  • For the exact details, please see the 2nd paragraph of [Indentation](https://docs.python.org/2/reference/lexical_analysis.html#indentation) in the _Lexical analysis_ section of _The Python Language Reference_ – PM 2Ring Jan 19 '17 at 12:00
  • @PM2Ring it should not be inside the `__init__` method, it should be at the end of the GameMenu class. Interesting what you and wildwilhelm bring up about it being 8 spaces, because that contradicts [pep-8](https://www.python.org/dev/peps/pep-0008/#indentation) – F. Pareto Jan 19 '17 at 12:38
  • Having a call inside a class definition which is outside any method is a bit weird: it gets executed when the class definition itself is executed, before you create an instance of the class. So in your case, `pygame.quit()` gets called before the stuff in the `if __name__ == "__main__":` is executed, long before `gm = GameMenu(screen, menu_items)` creates an instance of `GameMenu`. – PM 2Ring Jan 19 '17 at 12:52
  • A tab isn't exactly 8 spaces. As my previous docs link says, it's equivalent to anything from 1 to 8 spaces, depending on what's needed to reach the next tab stop. This is orthogonal to PEP-8's recommendation to use 4 spaces for indentation. PEP-8 recommends using spaces for indentation, and to only use tabs "to remain consistent with code that is already indented with tabs". – PM 2Ring Jan 19 '17 at 13:00
  • Of course, it's perfectly fine to use the Tab _key_ for indentation, if you set your editor to translate Tab presses to 4 spaces. For extra safety, it's a Good Idea to configure your editor to make tabs visible. FWIW, my editor lets you use Shift-Tab to de-indent, which is rather handy. (And when a block of text is selected, pressing Tab / Shift-Tab indents / de-indents the whole selected block). – PM 2Ring Jan 19 '17 at 13:02
  • You are right, it is a bit weird. To be honest I don't remember why `pygame.quit()` was put there instead of in a `GameMenu.run()` method. In fact, putting it there fixes the issue as well. I guess that was what caused the error, `pygame.quit()` removing the initialization. And since the tab would be evaluated as 8 spaces (I now understand what you both meant) this caused the `pygame.quit()` to be indented to be called _after_ `pygame.font.SysFont`. If you would post this as an answer I'd be happy to accept it. – F. Pareto Jan 19 '17 at 13:19

2 Answers2

2

If you put pygame.quit() without tab then you have something like this

(it doesn't matter that you have class between init() and quit() - it works the same way)

import pygame

pygame.init()
pygame.quit()

class ...

if __name__ == "__main__":
    screensize = 0
    screen = pygame.display.set_mode((640, 480), screensize, 32)

    menu_items = ('1', '2', '3', '4', '5')

    pygame.display.set_caption('numbers')
    pygame.mouse.set_visible(True)
    gm = GameMenu(screen, menu_items)

So you init pygame and at once you exit pygame - and you get your error when you try to use some elements of pygame (like font).

You should do this inside if __name__ == "__main__": in correct place.

import pygame

class ...

if __name__ == "__main__":

    # starts program
    pygame.init()

    screensize = 0
    screen = pygame.display.set_mode((640, 480), screensize, 32)

    menu_items = ('1', '2', '3', '4', '5')

    pygame.display.set_caption('numbers')
    pygame.mouse.set_visible(True)
    gm = GameMenu(screen, menu_items)

    # ... other code ...

    # ends program
    pygame.quit()

BTW: this can be more usefull (instead of scr_width , scr_height)

self.screen_rect = self.screen.get_rect()

because you can always get self.screen_rect.width, self.screen_rect.height and also self.screen_rect.center (to center element on screen), or others.

furas
  • 134,197
  • 12
  • 106
  • 148
-1

pygame.font.init() is needed to use fonts

Pyrolle
  • 51
  • 1
  • 6