1__license__ = 'GPL v3' 2__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' 3__docformat__ = 'restructuredtext en' 4 5''' 6Perform various initialization tasks. 7''' 8 9import locale, sys, os 10 11# Default translation is NOOP 12from polyglot.builtins import builtins 13builtins.__dict__['_'] = lambda s: s 14 15# For strings which belong in the translation tables, but which shouldn't be 16# immediately translated to the environment language 17builtins.__dict__['__'] = lambda s: s 18 19# For backwards compat with some third party plugins 20builtins.__dict__['dynamic_property'] = lambda func: func(None) 21 22from calibre.constants import iswindows, ismacos, islinux, DEBUG, isfreebsd 23 24 25def get_debug_executable(): 26 exe_name = 'calibre-debug' + ('.exe' if iswindows else '') 27 if hasattr(sys, 'frameworks_dir'): 28 base = os.path.dirname(sys.frameworks_dir) 29 return [os.path.join(base, 'MacOS', exe_name)] 30 if getattr(sys, 'run_local', None): 31 return [sys.run_local, exe_name] 32 nearby = os.path.join(os.path.dirname(os.path.abspath(sys.executable)), exe_name) 33 if getattr(sys, 'frozen', False): 34 return [nearby] 35 exloc = getattr(sys, 'executables_location', None) 36 if exloc: 37 ans = os.path.join(exloc, exe_name) 38 if os.path.exists(ans): 39 return [ans] 40 if os.path.exists(nearby): 41 return [nearby] 42 return [exe_name] 43 44 45def initialize_calibre(): 46 if hasattr(initialize_calibre, 'initialized'): 47 return 48 initialize_calibre.initialized = True 49 50 # Ensure that all temp files/dirs are created under a calibre tmp dir 51 from calibre.ptempfile import base_dir 52 try: 53 base_dir() 54 except OSError: 55 pass # Ignore this error during startup, so we can show a better error message to the user later. 56 57 # 58 # Ensure that the max number of open files is at least 1024 59 if iswindows: 60 # See https://msdn.microsoft.com/en-us/library/6e3b887c.aspx 61 from calibre_extensions import winutil 62 winutil.setmaxstdio(max(1024, winutil.getmaxstdio())) 63 else: 64 import resource 65 soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE) 66 if soft < 1024: 67 try: 68 resource.setrlimit(resource.RLIMIT_NOFILE, (min(1024, hard), hard)) 69 except Exception: 70 if DEBUG: 71 import traceback 72 traceback.print_exc() 73 74 # 75 # Fix multiprocessing 76 from multiprocessing import spawn, util 77 78 def get_command_line(**kwds): 79 prog = 'from multiprocessing.spawn import spawn_main; spawn_main(%s)' 80 prog %= ', '.join('%s=%r' % item for item in kwds.items()) 81 return get_debug_executable() + ['--fix-multiprocessing', '--', prog] 82 spawn.get_command_line = get_command_line 83 orig_spawn_passfds = util.spawnv_passfds 84 85 def spawnv_passfds(path, args, passfds): 86 try: 87 idx = args.index('-c') 88 except ValueError: 89 return orig_spawn_passfds(args[0], args, passfds) 90 patched_args = get_debug_executable() + ['--fix-multiprocessing', '--'] + args[idx + 1:] 91 return orig_spawn_passfds(patched_args[0], patched_args, passfds) 92 util.spawnv_passfds = spawnv_passfds 93 94 # 95 # Setup resources 96 import calibre.utils.resources as resources 97 resources 98 99 # 100 # Setup translations 101 from calibre.utils.localization import set_translators 102 103 set_translators() 104 105 # 106 # Initialize locale 107 # Import string as we do not want locale specific 108 # string.whitespace/printable, on windows especially, this causes problems. 109 # Before the delay load optimizations, string was loaded before this point 110 # anyway, so we preserve the old behavior explicitly. 111 import string 112 string 113 try: 114 locale.setlocale(locale.LC_ALL, '') # set the locale to the user's default locale 115 except: 116 dl = locale.getdefaultlocale() 117 try: 118 if dl: 119 locale.setlocale(locale.LC_ALL, dl[0]) 120 except: 121 pass 122 123 builtins.__dict__['lopen'] = open # legacy compatibility 124 from calibre.utils.icu import title_case, lower as icu_lower, upper as icu_upper 125 builtins.__dict__['icu_lower'] = icu_lower 126 builtins.__dict__['icu_upper'] = icu_upper 127 builtins.__dict__['icu_title'] = title_case 128 129 def connect_lambda(bound_signal, self, func, **kw): 130 import weakref 131 r = weakref.ref(self) 132 del self 133 num_args = func.__code__.co_argcount - 1 134 if num_args < 0: 135 raise TypeError('lambda must take at least one argument') 136 137 def slot(*args): 138 ctx = r() 139 if ctx is not None: 140 if len(args) != num_args: 141 args = args[:num_args] 142 func(ctx, *args) 143 144 bound_signal.connect(slot, **kw) 145 builtins.__dict__['connect_lambda'] = connect_lambda 146 147 if islinux or ismacos or isfreebsd: 148 # Name all threads at the OS level created using the threading module, see 149 # http://bugs.python.org/issue15500 150 import threading 151 from calibre_extensions import speedup 152 153 orig_start = threading.Thread.start 154 155 def new_start(self): 156 orig_start(self) 157 try: 158 name = self.name 159 if not name or name.startswith('Thread-'): 160 name = self.__class__.__name__ 161 if name == 'Thread': 162 name = self.name 163 if name: 164 if isinstance(name, str): 165 name = name.encode('ascii', 'replace').decode('ascii') 166 speedup.set_thread_name(name[:15]) 167 except Exception: 168 pass # Don't care about failure to set name 169 threading.Thread.start = new_start 170