-
Notifications
You must be signed in to change notification settings - Fork 177
/
_internal.py
92 lines (74 loc) · 3.14 KB
/
_internal.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# -*- coding: utf-8 -*-
from __future__ import print_function
import inspect
import traceback
import Foundation
from . import compat
from . import exceptions
def require_string(*objs):
for obj in objs:
if not isinstance(obj, compat.string_types):
raise TypeError(
'a string is required but given {0}, a {1}'.format(obj, type(obj).__name__)
)
def require_string_or_none(*objs):
for obj in objs:
if not(obj is None or isinstance(obj, compat.string_types)):
raise TypeError(
'a string or None is required but given {0}, a {1}'.format(obj, type(obj).__name__)
)
def call_as_function_or_method(func, event):
# The idea here is that when using decorators in a class, the functions passed are not bound so we have to
# determine later if the functions we have (those saved as callbacks) for particular events need to be passed
# 'self'.
#
# This works for an App subclass method or a standalone decorated function. Will attempt to find function as
# a bound method of the App instance. If it is found, use it, otherwise simply call function.
from . import rumps
try:
app = getattr(rumps.App, '*app_instance')
except AttributeError:
pass
else:
for name, method in inspect.getmembers(app, predicate=inspect.ismethod):
if method.__func__ is func:
return method(event)
return func(event)
def guard_unexpected_errors(func):
"""Decorator to be used in PyObjC callbacks where an error bubbling up
would cause a crash. Instead of crashing, print the error to stderr and
prevent passing to PyObjC layer.
For Python 3, print the exception using chaining. Accomplished by setting
the cause of :exc:`rumps.exceptions.InternalRumpsError` to the exception.
For Python 2, emulate exception chaining by printing the original exception
followed by :exc:`rumps.exceptions.InternalRumpsError`.
"""
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
internal_error = exceptions.InternalRumpsError(
'an unexpected error occurred within an internal callback'
)
if compat.PY2:
import sys
traceback.print_exc()
print('\nThe above exception was the direct cause of the following exception:\n', file=sys.stderr)
traceback.print_exception(exceptions.InternalRumpsError, internal_error, None)
else:
internal_error.__cause__ = e
traceback.print_exception(exceptions.InternalRumpsError, internal_error, None)
return wrapper
def string_to_objc(x):
if isinstance(x, compat.binary_type):
return Foundation.NSData.alloc().initWithData_(x)
elif isinstance(x, compat.string_types):
return Foundation.NSString.alloc().initWithString_(x)
else:
raise TypeError(
"expected a string or a bytes-like object but provided %s, "
"having type '%s'" % (
x,
type(x).__name__
)
)