Skip to content

Commit

Permalink
Show a warning for 'on' functions that are not valid event handlers.
Browse files Browse the repository at this point in the history
Fixes #181
  • Loading branch information
martindemello authored and lordmauve committed May 6, 2019
1 parent d36bd81 commit cf3d015
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 7 deletions.
5 changes: 3 additions & 2 deletions pgzero/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,9 @@ def _handle_unexpected_kwargs(self, kwargs):
if not unexpected_kwargs:
return

for found, suggested in spellcheck.compare(
unexpected_kwargs, self.EXPECTED_INIT_KWARGS):
typos, _ = spellcheck.compare(
unexpected_kwargs, self.EXPECTED_INIT_KWARGS)
for found, suggested in typos:
raise TypeError(
"Unexpected keyword argument '{}' (did you mean '{}'?)".format(
found, suggested))
Expand Down
36 changes: 32 additions & 4 deletions pgzero/spellcheck.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import re

from operator import itemgetter

from .game import PGZeroGame, positional_parameters
Expand Down Expand Up @@ -60,25 +62,32 @@ def compare(have, want):
This is a greedy algorithm that will take the best answer for each word
in have in turn.
Returns (typos with suggestions, unrecognised functions)
"""
want = set(want)
have = set(have)
matched = want & have
want -= matched
have -= matched
typos = []
for w in have:
suggestions = suggest(w, want)
if suggestions:
s = suggestions[0]
yield w, s
typos.append((w, s))
want.discard(s)
have -= set(w for w, s in typos)
return typos, have


# The list of hooks we support

EVENT_HOOKS = list(PGZeroGame.EVENT_HANDLERS.values())

HOOKS = [
'draw',
'update',
] + list(PGZeroGame.EVENT_HANDLERS.values())
]


# The list of magic module-level constants
Expand Down Expand Up @@ -116,6 +125,18 @@ def warn(self, msg, found, suggestion):
suggestion=suggestion
))

def warn_event_handlers(self, typos, missing):
if not typos or missing:
return
print(
"Warning: Found some 'on' functions that are not "
"valid event handlers.")
for found, suggestion in typos:
print(" {found} (did you mean {suggestion}?)".format(
found=found, suggestion=suggestion))
for f in missing_hooks:
print(" ", f)

def error(self, msg, found, suggestion):
raise InvalidParameter(msg.format(
found=found,
Expand All @@ -138,14 +159,21 @@ def spellcheck(namespace, result=SpellCheckResult()):
elif isinstance(val, (str, int)):
consts.append(name)

for found, suggestion in compare(funcs, HOOKS):
typos, _ = compare(funcs, HOOKS)
for found, suggestion in typos:
result.warn(
"Warning: found function named {found}: "
"did you mean {suggestion}?",
found, suggestion
)

for found, suggestion in compare(consts, CONSTS):
typos, missing = compare(funcs, EVENT_HOOKS)
maybe_hook = re.compile("on[A-Z_]")
missing_hooks = [f for f in missing if re.match(maybe_hook, f)]
result.warn_event_handlers(typos, missing_hooks)

typos, _ = compare(consts, CONSTS)
for found, suggestion in typos:
result.warn(
"Warning: found constant named {found}: "
"did you mean {suggestion}?",
Expand Down
27 changes: 26 additions & 1 deletion test/test_spellcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


class SuggestionTest(TestCase):
HOOKS = spellcheck.HOOKS
HOOKS = spellcheck.HOOKS + spellcheck.EVENT_HOOKS

def assert_suggestions(self, w, candidates, expected):
suggestions = spellcheck.suggest(w, candidates)
Expand Down Expand Up @@ -44,19 +44,27 @@ class LoggingSpellCheckResult:
def __init__(self):
self.warnings = []
self.errors = []
self.bad_handlers = []

def warn(self, msg, found, suggestion):
self.warnings.append((found, suggestion))

def error(self, msg, found, suggestion):
self.errors.append((found, suggestion))

def warn_event_handlers(self, typos, missing):
self.warnings.extend(typos)
self.bad_handlers.extend(missing)

def has_error(self, found, suggestion):
return (found, suggestion) in self.errors

def has_warning(self, found, suggestion):
return (found, suggestion) in self.warnings

def has_bad_handler(self, handler):
return handler in self.bad_handlers

def get_report(self):
lines = []
for type in ('warnings', 'errors'):
Expand Down Expand Up @@ -93,6 +101,15 @@ def assert_has_error(self, found, suggestion):
self.result.get_report()
)

def assert_has_handler_warning(self, handler):
if self.result.has_bad_handler(handler):
return

raise AssertionError(
'Expected warning for hander %s\n' % handler +
self.result.get_report()
)

def spellcheck(self, namespace):
spellcheck.spellcheck(namespace, self.result)

Expand Down Expand Up @@ -125,3 +142,11 @@ def test_misspelled_param(self):
'on_mouse_down': lambda buton: None,
})
self.assert_has_error('buton', 'button')

def test_invalid_event_handler(self):
self.spellcheck({
'on_key_press': lambda: None,
'onKeyPress': lambda: None
})
self.assert_has_handler_warning('on_key_press')
self.assert_has_handler_warning('onKeyPress')

0 comments on commit cf3d015

Please sign in to comment.