0

I am a complete beginner so if the question seems obvious or stupid I apologize beforehand.

Working on an app in PyGame that reads a random word from a file and then searches it's definition using PyDictionary.

The code I started with is as follows;

WORD = random.choice(WORDS)
dict = PyDictionary()

meaning = dict.meaning(WORD)

the word is printed on screen without issue;

word_text = play_again_font.render(f"{WORD.upper()}", True, "#FFB90F")

but when I try to call the meaning I get;

meaning_text = meaning_font.render(f"{meaning()}", True, "#FFB90F")
TypeError: 'dict' object is not callable

As I found the PyDictionary was sending the output as dict which is indeed not callable.

So I tried a new approach.

My new code is; I have a python file with a WORDS list

WORD = WORDS
WORD_LIST = list(WORD)
word_n = random.choice(WORD_LIST)

I send the random word, defined in the variable word_n, to a txt file:

file = open('test.txt', 'wb')
pickle.dump(word_n,file)
file.close()

As the word has special characters and white spaces I read, clean and send to another file;

def clean_word():
    string = open('test.txt').read().lstrip().strip()
    new_str = ''.join([i for i in string if i.isalpha()]).strip()
    open('mean.txt', 'w').write(new_str)



def get_mean():
    clean = open('mean.txt').readlines()
    dicto = PyDictionary()
    meaning = dicto.meaning(clean)

The join function works in as far as it removes white spaces (NUL) and so, but it leaves this character before the word: œ these characters get removed: €EOT•ENONULNULNULŒSOHo”.

I've tried:

new_str = ''.join([i for i in string if i.isalpha()]).strip().replace('œ','')

This does not work as the œ symbol remains at the beginning of the word.

I've read that it could be encoding so tried:

new_str = ''.join([i for i in string if i.isalpha()]).strip().encode('utf-8')

also tried .encode('cp1252') but neither method works. Tried decode but this doesn't appear to be an option.

Right now I cannot send the word to PyDictionary as it returns "None".

meaning_text = meaning_font.render(f"{clean_word()}", True, "#FFB90F")

I'm assuming this is due to the symbol in front of the word.

How can I strip everything to be able to pass the variable to PyDictionary?

EDIT

This does not appear to be encoding.

I kept trying and have found that the word does get passed to PyDictionary and that it does produce a definition.

I have tested by;

def get_mean():
clean = open('mean.txt').readlines()
dicto = PyDictionary()
meaning = dicto.meaning(clean)
print(meaning)

The meaning is indeed shown on Terminal.

Another test I did was:

def get_mean():
clean = open('mean.txt').readline()
dicto = PyDictionary()
meaning = dicto.meaning(clean)
file = open('meaners.txt', 'wb')
pickle.dump(meaning, file)
file.close()

I can confirm that the file meaners.txt gets created meaning gets sent to it.

Why am I able to pass the variable word_n but not get_mean?

ie.

the below works and renders the word as expected;

play_again_font.render(f"{word_n.upper()}", True, "#FFB90F")

But this does not work:

meaning_text = meaning_font.render(f"{get_mean()}", True, "#FFB90F")

It always returns None even when the definition gets sent to the created file.

If I try to create a variable ie;

my_var = get_mean()

I get error;

meaning_text = meaning_font.render(f"{my_var()}", True, "#FFB90F") TypeError: 'NoneType' object is not callable

if I call the function directly it returns None;

meaning_text = meaning_font.render(f"{get_mean()}", True, "#FFB90F")

Do I need to redirect stdout perhaps?

Thanks in advance.

EDIT;

minimal reproducible example:

I have a words.py file which contains:

WORDS = [ "a", "bunch", "of", "words", "bared" ]

import random import pickle import words from PyDictionary import PyDictionary import pygame import pygame.display

WORD = words.WORDS
WORD_list = list(WORD)
word_n = random.choice(WORD_list)
file = open('mean.txt', 'wb')
pickle.dump(word_n,file)
file.close()
print(word_n)

def get_mean():
    dicto = PyDictionary()
    meaning = dicto.meaning(word_n)
    print(meaning)
    file = open('meaners.txt', 'wb')
    pickle.dump(meaning, file)
    file.close()

get_mean()

test.py" bared {'Verb': ['lay bare', 'make public', 'lay bare'], 'Adjective': ['having the head uncovered']} {'Verb': ['lay bare', 'make public', 'lay bare'], 'Adjective': ['having the head uncovered']}

Process finished with exit code 0

The issue I'm facing is when I try to render text with the get_mean() The word_n variable is displayed without problems.

test_text = play_again_font.render(f"{word_n.upper()}", True, "#FFB90F")
test_rect = test_text.get_rect(center=(WIDTH / 2, 650))

The above works and the random word is displayed on screen.

But the below, displaying the get_mean() does not display the definition.

meaning_font = pygame.font.SysFont('segoe-ui-symbol.ttf', 20)
meaning_text = meaning_font.render(f"{get_mean()}", True, "#FFB90F")
meaning_rect = meaning_text.get_rect(center=(WIDTH / 2, 200))
kip
  • 145
  • 7
  • You could encode to `ascii`, see [this answer](https://stackoverflow.com/a/46704307/2280890) – import random Apr 25 '22 at 13:07
  • Thanks for the suggestion. Tried but still no go. – kip Apr 25 '22 at 14:37
  • 2
    Perhaps you could edit your question to include a [mcve] to make it easier to help you. Also `dict` refers to the built-in python dictionary class, so you shouldn't use it as a variable name. – import random Apr 25 '22 at 15:01
  • thanks import random for the tips and for taking the time to reply. I've added a working example to hopefully show better what the issue is. – kip Apr 25 '22 at 21:11

1 Answers1

1

I had some trouble trying to recreate your problem with PyDictionary, it's dependent on a library for translation that no longer installs from PyPI.

Fortunately a fork is available, PyMultiDictionary, that installs for me, so I've created a minimal example. You will likely want to handle the processing of the dictionary.meaning() function call with more care. If you change the dictionary, then the response format will change. One of your issues seems to be that you're not passing strings to the font.render() function.

import random
import pygame

from PyMultiDictionary import MultiDictionary
dictionary = MultiDictionary()

def get_meaning(word):
    """Return the first meaning of a word"""
    # strip non-ascii
    word = word.encode('ascii',errors='ignore').decode()
    print(f"  Searching for {word} … ", end="")
    word_type, word_meaning, word_wikipedia = dictionary.meaning("en", word)
    print(f"found {word_meaning}")
    if word_meaning == "":
        word_meaning = "No definition found"
    return word_meaning

def blit_text(surface, text, pos, font, color=pygame.Color('black')):
    """Multi-line text blit from https://stackoverflow.com/a/42015712/2280890"""
    words = [word.split(' ') for word in text.splitlines()]
    # 2D array where each row is a list of words.
    space = font.size(' ')[0]  # The width of a space.
    max_width, max_height = surface.get_size()
    x, y = pos
    for line in words:
        for word in line:
            word_surface = font.render(word, True, color)
            word_width, word_height = word_surface.get_size()
            if x + word_width >= max_width:
                x = pos[0]  # Reset the x.
                y += word_height  # Start on new row.
            surface.blit(word_surface, (x, y))
            x += word_width + space
        x = pos[0]  # Reset the x.
        y += word_height  # Start on new row.


word_list = ["bunch", "Φof", "wordsΩ", "b✖areδ", "!#@$"]

pygame.init()
# grab the first installed font
sys_font = pygame.font.SysFont(pygame.font.get_fonts()[0], 20)

WIDTH, HEIGHT = 640, 480
window = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Random Meanings")
clock = pygame.time.Clock()
txt_pos = (60,60)

word = random.choice(word_list)
meaning = get_meaning(word)

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                running = False
            elif event.key == pygame.K_SPACE:
                word = random.choice(word_list)
                meaning = get_meaning(word)
    # update state
    txt = f"{word}:\n{meaning}"
    # draw background
    window.fill(pygame.Color("white"))
    # draw text
    blit_text(window, txt, txt_pos, sys_font)
    # update screen
    pygame.display.flip()
    clock.tick(30)
pygame.quit()

This will display a window like:

Meaning of bunch

The simplistic special character removal performed is through conversion to ASCII as suggested in the comment and the multi-line text drawing is from this excellent answer.

import random
  • 3,054
  • 1
  • 17
  • 22
  • 1
    Thank you so much. This made me see where I was going wrong. I was passing the get_mean() without referencing the word_n variable. This def fixed it. Much appreciated. – kip Apr 26 '22 at 11:49