Skip to content

Commit 80d7c5a

Browse files
committed
Add unit tests (cztomczak#59) and fix Python 3 issue (cztomczak#121,cztomczak#183) among others.
Improve shutting down cleanly with ExceptHook. Fix issue with str/bytes passed to Debug() function (cztomczak#110).
1 parent f515403 commit 80d7c5a

11 files changed

Lines changed: 667 additions & 20 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.idea/
22
build/
3-
*.log
3+
*.log
4+
__pycache__/

api/cefpython.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,10 @@ Global except hook to exit app cleanly on error.
7878

7979
This hook does the following: in case of exception write it to
8080
the "error.log" file, display it to the console, shutdown CEF
81-
and exit application immediately by ignoring "finally" (_exit())
81+
and exit application immediately by ignoring "finally" (_exit()).
82+
83+
If you would like to implement a custom hook take a look at the
84+
source code of ExceptHook in the cefpython/src/helpers.pyx file.
8285

8386

8487
### GetAppSetting

examples/hello_world.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ def main():
1515

1616

1717
class ClientHandler:
18-
"""Client handler."""
18+
1919
def OnBeforeClose(self, browser):
20+
"""Called just before a browser is destroyed."""
2021
if not browser.IsPopup():
22+
# Exit app when main window is closed.
2123
cef.QuitMessageLoop()
2224

2325

src/cefpython.pyx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,31 @@ def Shutdown():
832832
# This one is probably redundant. Additional testing should be done.
833833
Debug("Shutdown: releasing shared request context")
834834
g_sharedRequestContext.Assign(NULL)
835+
836+
if len(g_pyBrowsers):
837+
Error("Shutdown called, but there are still browser references alive,"
838+
" will try to close them and free references.")
839+
# There might be a case when python error occured after creating
840+
# browser, but before any message loop was run. In such case
841+
# the renderer process won't be terminated unless we run some
842+
# message loop work here, try to close browser and free reference,
843+
# and then run some message loop work again.
844+
for i in range(10):
845+
with nogil:
846+
CefDoMessageLoopWork()
847+
time.sleep(0.01)
848+
browsers_list = []
849+
for browserId in g_pyBrowsers:
850+
browser = g_pyBrowsers[browserId]
851+
browser.TryCloseBrowser()
852+
browsers_list.append(browserId)
853+
for browserId in browsers_list:
854+
RemovePyBrowser(browserId)
855+
for i in range(10):
856+
with nogil:
857+
CefDoMessageLoopWork()
858+
time.sleep(0.01)
859+
835860
Debug("Shutdown()")
836861
with nogil:
837862
# Temporary fix for possible errors on shutdown. See this post:

src/helpers.pyx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ cpdef str GetModuleDirectory():
3030

3131
g_GetAppPath_dir = None
3232

33-
cpdef GetAppPath(file=None):
33+
cpdef str GetAppPath(file=None):
3434
"""Get application path."""
3535
# On Windows after downloading file and calling Browser.GoForward(),
3636
# current working directory is set to %UserProfile%.
@@ -58,12 +58,16 @@ cpdef GetAppPath(file=None):
5858
return str(file)
5959

6060

61-
cpdef ExceptHook(excType, excValue, traceObject):
61+
cpdef py_void ExceptHook(excType, excValue, traceObject):
6262
"""Global except hook to exit app cleanly on error."""
6363
# This hook does the following: in case of exception write it to
6464
# the "error.log" file, display it to the console, shutdown CEF
6565
# and exit application immediately by ignoring "finally" (_exit()).
66-
errorMsg = "\n".join(traceback.format_exception(excType, excValue,
66+
print("[CEF Python] ExceptHook: catched exception, will shutdown CEF now")
67+
QuitMessageLoop()
68+
Shutdown()
69+
print("[CEF Python] ExceptHook: see the catched exception below:")
70+
errorMsg = "".join(traceback.format_exception(excType, excValue,
6771
traceObject))
6872
errorFile = GetAppPath("error.log")
6973
try:
@@ -77,16 +81,13 @@ cpdef ExceptHook(excType, excValue, traceObject):
7781
fp.write("\n[%s] %s\n" % (
7882
time.strftime("%Y-%m-%d %H:%M:%S"), errorMsg))
7983
except:
80-
print("[pygtk_.py]: WARNING: failed writing to error file: %s" % (
84+
print("[CEF Python] WARNING: failed writing to error file: %s" % (
8185
errorFile))
8286
# Convert error message to ascii before printing, otherwise
8387
# you may get error like this:
8488
# | UnicodeEncodeError: 'charmap' codec can't encode characters
8589
errorMsg = errorMsg.encode("ascii", errors="replace")
8690
errorMsg = errorMsg.decode("ascii", errors="replace")
87-
print("\n"+errorMsg+"\n")
88-
QuitMessageLoop()
89-
Shutdown()
91+
print("\n"+errorMsg)
9092
# noinspection PyProtectedMember
9193
os._exit(1)
92-

src/linux/setup/cefpython.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/* Generated by Cython 0.24.1 */
22

3-
#ifndef __PYX_HAVE__cefpython_py34
4-
#define __PYX_HAVE__cefpython_py34
3+
#ifndef __PYX_HAVE__cefpython_py35
4+
#define __PYX_HAVE__cefpython_py35
55

66

7-
#ifndef __PYX_HAVE_API__cefpython_py34
7+
#ifndef __PYX_HAVE_API__cefpython_py35
88

99
#ifndef __PYX_EXTERN_C
1010
#ifdef __cplusplus
@@ -89,12 +89,12 @@ __PYX_EXTERN_C DL_IMPORT(bool) ApplicationSettings_GetBoolFromDict(char const *,
8989
__PYX_EXTERN_C DL_IMPORT(std::string) ApplicationSettings_GetString(char const *);
9090
__PYX_EXTERN_C DL_IMPORT(int) CommandLineSwitches_GetInt(char const *);
9191

92-
#endif /* !__PYX_HAVE_API__cefpython_py34 */
92+
#endif /* !__PYX_HAVE_API__cefpython_py35 */
9393

9494
#if PY_MAJOR_VERSION < 3
95-
PyMODINIT_FUNC initcefpython_py34(void);
95+
PyMODINIT_FUNC initcefpython_py35(void);
9696
#else
97-
PyMODINIT_FUNC PyInit_cefpython_py34(void);
97+
PyMODINIT_FUNC PyInit_cefpython_py35(void);
9898
#endif
9999

100-
#endif /* !__PYX_HAVE__cefpython_py34 */
100+
#endif /* !__PYX_HAVE__cefpython_py35 */

src/utils.pyx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,15 @@ cpdef py_bool IsThread(int threadID):
4141
# unicode strings and writing them to file (codecs.open).
4242
# This change is required to work with Cython 0.20.
4343

44-
cpdef object Debug(str msg):
44+
cpdef object Debug(py_string msg):
4545
if not g_debug:
4646
return
47-
msg = "[CEF Python] "+str(msg)
47+
# In Python 3 str or bytes may be passed
48+
if type(msg) != str and type(msg) == bytes:
49+
msg = msg.decode("utf-8", "replace")
50+
# Convert to str in case other kind of object was passed
51+
msg = str(msg)
52+
msg = "[CEF Python] "+msg
4853
print(msg)
4954
if g_debugFile:
5055
try:
@@ -54,6 +59,21 @@ cpdef object Debug(str msg):
5459
print("[CEF Python] WARNING: failed writing to debug file: %s" % (
5560
g_debugFile))
5661

62+
cdef void Error(py_string msg) except *:
63+
# In Python 3 str or bytes may be passed
64+
if type(msg) != str and type(msg) == bytes:
65+
msg = msg.decode("utf-8", "replace")
66+
# Convert to str in case other kind of object was passed
67+
msg = str(msg)
68+
msg = "[CEF Python] ERROR: "+msg
69+
print(msg)
70+
if g_debugFile:
71+
try:
72+
with open(g_debugFile, "a") as file_:
73+
file_.write(msg+"\n")
74+
except:
75+
print("[CEF Python] WARNING: failed writing to debug file: %s" % (
76+
g_debugFile))
5777

5878
cpdef str GetSystemError():
5979
IF UNAME_SYSNAME == "Windows":

0 commit comments

Comments
 (0)