PK+0OK{Fhelpmeplease/__init__.py""" Ask your friends to debug for you! """ from .helpme import ask_for_help __author__ = 'Max Liu' __version__ = '0.1'PK0O 0qqhelpmeplease/config.pyMY_EMAIL = 'xxxxxx@xxxx.com' MY_PASSWORD = 'xxxxxx' GOOD_PEOPLE = { 'Max': 'madmax_liuzhehao@163.com' }PK0OuTThelpmeplease/helpme.pyimport smtplib import ssl import functools from email.message import EmailMessage from .config import * from .trackerror import get_code def send_email(msg, address): """ Send msg to Max """ context = ssl.create_default_context() with smtplib.SMTP_SSL("smtp.exmail.qq.com", 465, context=context) as server: server.login(MY_EMAIL, MY_PASSWORD) server.send_message(msg, MY_EMAIL, [address]) server.close() def create_message(code, ex_msg, address): """ Create an error report""" msg = EmailMessage() content = 'Error Message:\n' + ex_msg + '\n\nSource Code:\n' + code msg.set_content(content.replace('\t', ' '*4)) # replace tab with spaces for better formatting msg['Subject'] = '{} needs your help!'.format(MY_EMAIL.split('@')[0]) msg['From'] = MY_EMAIL msg['To'] = address return msg class ask_for_help: def __init__(self, who=None): available = list(GOOD_PEOPLE.keys()) if who and who not in available: raise ValueError('Please add {} to the GOOD_PEOPLE list in the config file.'.format(who)) if who is None: who = available[0] self.who = who self.address = GOOD_PEOPLE[who] def __call__(self, f): f_name = f.__name__ @functools.wraps(f) def wrapped(*args, **kwargs): try: return f(*args, **kwargs) except Exception as e: # generate an error report source_code = get_code(f) ex_msg = str(e) error_report = create_message(source_code, ex_msg, self.address) send_email(error_report, self.address) print('{} will help you!'.format(self.who)) return wrapped PK0OSf 0helpmeplease/trackerror.pyimport inspect import sys import types from warnings import warn from collections import ChainMap, deque def _is_class_obj(obj): """ A dummy way of telling if an object is a Class Object""" return callable(obj) and not hasattr(obj, '__code__') def get_contained_functions(f): """ Given a function object, return a tuple of function names called by f """ return f.__code__.co_names def get_source_code(f, locals=None, globals=None): """ Get the source code of a function :param f: Can be a function type or String, if a string is given, we look into locals and globals to find the definition of f :return The function body along with a tuple of function names that will be called by f """ # In the case we couldn't find the definition of the function if f is None: return '', () if isinstance(f, types.FunctionType): return inspect.getsource(f), get_contained_functions(f) elif isinstance(f, str): var_map = ChainMap(locals or {}, globals or {}) return get_source_code(var_map.get(f, None), locals, globals) elif isinstance(f, types.ModuleType): warn('{} is a Module object. Support for external moduels coming soon.'.format(f)) return '', () elif _is_class_obj(f): warn('Failed to get the code for {}. The support for Class object soon to be added'.format(f)) return '', () else: raise TypeError('{} should either be a function or string.'.format(f)) def get_code(f, newlines=1): _globals = f.__globals__ definitions = list() queue = deque([f]) while queue: f = queue.popleft() code, functions = get_source_code(f, None, _globals) if code: definitions.append(code) queue.extend(functions) delimiter = '\n' * newlines return delimiter.join(definitions) PKO0O=="helpmeplease-0.1.dist-info/LICENSEMIT License Copyright (c) 2019 Max Liu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK!HPO helpmeplease-0.1.dist-info/WHEEL HM K-*ϳR03rOK-J,/RH,szd&Y)r$[)T&UrPK!H)p#helpmeplease-0.1.dist-info/METADATAeS]O1|ƿb)*q)I[ $@+%,;;$תK}ٙ]_Gd2:PLJБ2~m=Ak*ҁ7 1]LMIE}P ԃk\ ONT{s<+vs?ξM%KcKaܙ&5J/MK` 5WJ_%hΆo#B?䒛Yٻc1&YxImO+?`O,89+bM0QX wϰ{vm,ك{^ #\qH<<<4]\loX|1t;Kt[ G.T²44HK)jwuAѲ 0 1Ë a.z#XLAgq`QEdl›N;?'YbǒVJ?CǸZ1޷t4svgJB';7؊a.tVI5, Ś-F;++qԇOR*|JKч}i]αXһ/PK!H?u:r!helpmeplease-0.1.dist-info/RECORD}I@{ s@)RAdG`~LL]U{*ҼJY wQxdkHS奰C^1ںFFH@}d^I>iz}qk]svM4D|E5*1P@ȽjÓPw{mIy ը ܅&W Y ]q5$GbRbW9]}"7t7r,"6t*[ʠo.q/z APi*$Kt?é}W DuTPK+0OK{Fhelpmeplease/__init__.pyPK0O 0qqhelpmeplease/config.pyPK0OuTTZhelpmeplease/helpme.pyPK0OSf 0helpmeplease/trackerror.pyPKO0O=="helpmeplease-0.1.dist-info/LICENSEPK!HPO helpmeplease-0.1.dist-info/WHEELPK!H)p#&helpmeplease-0.1.dist-info/METADATAPK!H?u:r!helpmeplease-0.1.dist-info/RECORDPKT