mirror of
https://github.com/bendtherules/pyFun.git
synced 2026-08-18 13:52:46 +00:00
summer update
This commit is contained in:
+247
@@ -0,0 +1,247 @@
|
||||
# Utility functions
|
||||
# ToDo: Put everything in a class as staticmethods when imported, if
|
||||
# name=__main__, keep them local
|
||||
from pygame import locals as pygame_consts
|
||||
from functools import partial
|
||||
import inspect
|
||||
import logging
|
||||
import types
|
||||
|
||||
|
||||
def register(list_to_register=None):
|
||||
''' Used as decorator: Adds the function (or anything else) to list_to_register '''
|
||||
def temp_func(what_to_register):
|
||||
list_to_register.append(what_to_register)
|
||||
return what_to_register
|
||||
return temp_func
|
||||
|
||||
KW_EVENTS = {
|
||||
"QUIT": pygame_consts.QUIT,
|
||||
"ACTIVE_EVENT": pygame_consts.ACTIVEEVENT,
|
||||
"KEY_DOWN": pygame_consts.KEYDOWN,
|
||||
"KEY_UP": pygame_consts.KEYUP,
|
||||
"MOUSE_MOTION": pygame_consts.MOUSEMOTION,
|
||||
"MOUSE_BUTTON_UP": pygame_consts.MOUSEBUTTONUP,
|
||||
"MOUSE_BUTTON_DOWN": pygame_consts.MOUSEBUTTONDOWN,
|
||||
"JOY_AXIS_MOTION": pygame_consts.JOYAXISMOTION,
|
||||
"JOY_BALL_MOTION": pygame_consts.JOYBALLMOTION,
|
||||
"JOY_HAT_MOTION": pygame_consts.JOYHATMOTION,
|
||||
"JOY_BUTTON_UP": pygame_consts.JOYBUTTONUP,
|
||||
"JOY_BUTTOND_OWN": pygame_consts.JOYBUTTONDOWN,
|
||||
"VIDEO_RESIZE": pygame_consts.VIDEORESIZE,
|
||||
"VIDEO_EXPOSE": pygame_consts.VIDEOEXPOSE,
|
||||
"USER_EVENT": pygame_consts.USEREVENT,
|
||||
# think of begin_step, step and end_step
|
||||
"BEGIN_STEP": pygame_consts.USEREVENT + 1,
|
||||
"STEP": pygame_consts.USEREVENT + 2,
|
||||
"END_STEP": pygame_consts.USEREVENT + 3
|
||||
}
|
||||
|
||||
|
||||
def fuzzy_match_event_name(string):
|
||||
# print(string)
|
||||
str_normalized = string.upper()
|
||||
for tmp_event in KW_EVENTS:
|
||||
# tmp event is the event_name, keys of KW_EVENTS
|
||||
tmp_event_normalized = tmp_event.replace("_", "")
|
||||
if (tmp_event in str_normalized) or (tmp_event_normalized in str_normalized):
|
||||
return tmp_event
|
||||
|
||||
|
||||
class Action(object):
|
||||
|
||||
""" pygame.event.Action(type, dict): return Action
|
||||
pygame.Action.Action(type, **attributes): return Action
|
||||
"""
|
||||
|
||||
def __init__(self, type, *args, **kwargs):
|
||||
super(Action, self).__init__()
|
||||
self.type = type
|
||||
_dict = {}
|
||||
if len(args) == 1:
|
||||
_dict.update(args[0])
|
||||
elif len(args) > 1:
|
||||
raise TypeError(
|
||||
"Max one non-keyword argument allowed (which is set to dict)")
|
||||
if kwargs:
|
||||
_dict.update(kwargs)
|
||||
if _dict:
|
||||
self.dict = _dict
|
||||
|
||||
|
||||
def copy_func(f, name=None):
|
||||
return types.FunctionType(f.func_code, f.func_globals, name or f.func_name,
|
||||
f.func_defaults, f.func_closure)
|
||||
|
||||
|
||||
def selfie_depreceated(f):
|
||||
"""Decorate function `f` to pass a reference to the function
|
||||
as the first argument"""
|
||||
return partial(f, f)
|
||||
|
||||
|
||||
def selfie(f):
|
||||
"""Decorate function `f` to pass a reference to the function
|
||||
as the first argument"""
|
||||
return f.__get__(f, type(f))
|
||||
|
||||
|
||||
def sync_func(func1, func2):
|
||||
'''Makes the 1st param (func) equivalent to 2nd param (func).'''
|
||||
func1.func_code = func2.func_code
|
||||
func1.func_defaults = func2.func_defaults
|
||||
func1.func_dict = func2.func_dict
|
||||
func1.func_doc = func2.func_doc
|
||||
func1.func_name = func2.func_name
|
||||
|
||||
|
||||
class meta_accessor_class(type):
|
||||
|
||||
''' This metaclass allows class access to any function (or as extended use, to metaclasses)'''
|
||||
# Using metaclass and decorator to allow class access during class creation time
|
||||
# No method defined within the class should have "_process_meta" as arg
|
||||
# Potential problems: Using closures, function.func_globals is read-only
|
||||
# Doesnt get appropiate globals, maybe pass it (or the reqd global vars)
|
||||
# as param on func defn
|
||||
def __new__(cls, name, base, clsdict):
|
||||
temp_cls = type.__new__(cls, name, base, clsdict)
|
||||
methods = inspect.getmembers(temp_cls, inspect.ismethod)
|
||||
for (method_name, method_obj) in methods:
|
||||
has_im_func = hasattr(method_obj, "im_func")
|
||||
has_func = hasattr(method_obj, "func")
|
||||
while has_im_func or has_func:
|
||||
if has_im_func:
|
||||
method_obj = method_obj.im_func
|
||||
if has_func:
|
||||
# cater for partials
|
||||
method_obj = method_obj.func
|
||||
has_im_func = hasattr(method_obj, "im_func")
|
||||
has_func = hasattr(method_obj, "func")
|
||||
|
||||
if hasattr(method_obj, "_process_meta"):
|
||||
method_obj._process_meta = True
|
||||
# method_obj should return itself after setting main_func
|
||||
if hasattr(method_obj,"selfie"):
|
||||
method_obj = method_obj(method_obj)
|
||||
else:
|
||||
method_obj = method_obj()
|
||||
what_to_do, main_func = method_obj.what_to_do, method_obj.main_func
|
||||
# as we have resolved all im_funcs in
|
||||
# partial,classmethod,boundmethods
|
||||
f = method_obj
|
||||
sync_func(f, main_func)
|
||||
# func_to_register hardcoded
|
||||
mod_func = what_to_do(f, cls=temp_cls)
|
||||
sync_func(f, mod_func)
|
||||
|
||||
return temp_cls
|
||||
|
||||
|
||||
@selfie
|
||||
def run_dec_on_meta(self, what_to_do):
|
||||
'''Runs decorator (what_to_do) passed to it during meta with args, cls=>class and func=>function which this is used on'''
|
||||
# must be deepcopied bcoz multiple versions will edit main func
|
||||
# syntax error to grab attention
|
||||
# make copies of this func and instead of params use .vars. Should accept
|
||||
# *args,*kwargs to main_func. Next step: multiple funcs, think.
|
||||
|
||||
def inter_run_dec_on_meta(*args,**kwargs):
|
||||
# this intermediate func is used to produce func_process_meta for each time
|
||||
def func_process_meta(self, *args, **kwargs):
|
||||
if not hasattr(self, "_process_meta"):
|
||||
# changing own's state, should be restored at last step before
|
||||
# meta-return
|
||||
self._process_meta = False
|
||||
#(below) unneccesary here
|
||||
if not hasattr(self,"__old_args") and not hasattr(self,"__old_kwargs"):
|
||||
self.__old_args = None
|
||||
self.__old_kwargs = None
|
||||
if not self._process_meta:
|
||||
# as long as not being meta-processed
|
||||
# its not really main_func, really its just what_to_do's param
|
||||
if (self.__old_args or self.__old_kwargs):
|
||||
self.what_to_do = partial(self.what_to_do, *(self.__old_args), **(self.__old_kwargs))
|
||||
self.__old_args = args
|
||||
self.__old_kwargs = kwargs
|
||||
return selfie(self)
|
||||
else:
|
||||
self.main_func = self.__old_args[0]
|
||||
return self
|
||||
|
||||
func_process_meta.__old_args = args
|
||||
func_process_meta.__old_kwargs = kwargs
|
||||
func_process_meta.what_to_do = what_to_do
|
||||
func_process_meta.selfie=True
|
||||
func_process_meta = selfie(func_process_meta)
|
||||
return func_process_meta
|
||||
return inter_run_dec_on_meta
|
||||
|
||||
def run_func_on_meta(run_func):
|
||||
'''Runs func (run_func) passed to it during meta with arg, cls.
|
||||
run_func remains a method of the class.'''
|
||||
def what_to_do(func, cls):
|
||||
func(cls=cls)
|
||||
return func
|
||||
return run_dec_on_meta(what_to_do=what_to_do, main_func=run_func)
|
||||
|
||||
|
||||
def register_event(event_name=None, func_to_register=None, cls=None):
|
||||
'''
|
||||
@fun_Class.register_event() # @fun_Class.register_event === @fun_Class.register_event()
|
||||
def event_key_down(ev):
|
||||
pass
|
||||
OR
|
||||
# event_name=KEYDOWN (or "key_down")
|
||||
@fun_Class.register_event(event_name)
|
||||
def whatever(ev):
|
||||
pass
|
||||
OR
|
||||
fun_Class.register_event(event_name,func)
|
||||
'''
|
||||
if (event_name is None) and (func_to_register is None):
|
||||
# i.e No param passed, used as decorator (1st step of ex. 1)
|
||||
logging.info("Nothing passed")
|
||||
return register_event
|
||||
elif (not(event_name is None)) and (func_to_register is None):
|
||||
# i.e. one param is passed, maybe func or (str or int)
|
||||
logging.info("Event Name only passed")
|
||||
if isinstance(event_name, int) or isinstance(event_name, str):
|
||||
# i.e. 1st parm-> str or int, is event name, acts as decorator
|
||||
# (2nd ex.)
|
||||
# dont hardcode func name- use metaclass
|
||||
logging.info("Event Name is event_name")
|
||||
return partial(cls.register_event, event_name)
|
||||
elif hasattr(event_name, "__call__"):
|
||||
# first param is func, actually func_to_register.
|
||||
# So get event_name from func_name (2nd step of 1st ex.)
|
||||
logging.info("Event Name is actually func")
|
||||
func_to_register = event_name
|
||||
event_name = fuzzy_match_event_name(func_to_register.func_name)
|
||||
return register_event(event_name=event_name, func_to_register=func_to_register, cls=cls)
|
||||
else:
|
||||
raise TypeError("event_name must be (str or int) or func")
|
||||
else:
|
||||
# Both params present
|
||||
logging.info("Both param passed")
|
||||
|
||||
if isinstance(event_name, str):
|
||||
event_name = fuzzy_match_event_name(event_name)
|
||||
event_numb = KW_EVENTS[event_name]
|
||||
elif isinstance(event_name, int):
|
||||
event_numb = event_name
|
||||
else:
|
||||
raise TypeError("event_name should be str or int")
|
||||
|
||||
logging.info("Registering func")
|
||||
if not (event_numb in cls.dict_action_func):
|
||||
cls.dict_action_func[event_numb] = []
|
||||
cls.dict_action_func[event_numb].append(func_to_register)
|
||||
|
||||
return func_to_register
|
||||
|
||||
|
||||
|
||||
##_register_event_ = register_event
|
||||
##del register_event
|
||||
# so that register event is actually delegated register
|
||||
##register_event = run_dec_on_meta(_register_event_)
|
||||
Reference in New Issue
Block a user