def load(self, path=None, encoding=None, errors=None, raise_exceptions=False): if not self._isloaded and (path or self.path): self._isloaded = True if not path: path = self.path if path and not os.path.isabs(path): path = get_data_path(path) if path and os.path.isfile(path): self.path = path if encoding: self.encoding = encoding if errors: self.errors = errors else: handle_error(UserWarning("Warning - file not found:\n\n%s" % safe_unicode(path)), tb=False) return try: with codecs.open(path, "rU", self.encoding, self.errors) as f: self.parse(f) except EnvironmentError as exception: if raise_exceptions: raise handle_error(exception) except Exception as exception: if raise_exceptions: raise handle_error(UserWarning("Error parsing file:\n\n%s\n\n%s" % tuple(safe_unicode(s) for s in (path, exception))), tb=False)
def can_update_cal(path): """ Check if cal can be updated by checking for required fields. """ try: calstat = os.stat(path) except Exception as exception: safe_print("Warning - os.stat('%s') failed: %s" % tuple(safe_unicode(s) for s in (path, exception))) return False if not path in cals or cals[path].mtime != calstat.st_mtime: try: cal = CGATS.CGATS(path) except (IOError, CGATS.CGATSInvalidError, CGATS.CGATSInvalidOperationError, CGATS.CGATSKeyError, CGATS.CGATSTypeError, CGATS.CGATSValueError) as exception: if path in cals: del cals[path] safe_print("Warning - couldn't process CGATS file '%s': %s" % tuple(safe_unicode(s) for s in (path, exception))) else: if cal.queryv1("DEVICE_CLASS") == "DISPLAY" and not None in \ (cal.queryv1("TARGET_WHITE_XYZ"), cal.queryv1("TARGET_GAMMA"), cal.queryv1("BLACK_POINT_CORRECTION"), cal.queryv1("QUALITY")): cals[path] = cal return path in cals and cals[path].mtime == calstat.st_mtime
def write(self, *args, **kwargs): pad = kwargs.get("pad", self.pad) padchar = kwargs.get("padchar", self.padchar) sep = kwargs.get("sep", self.sep) end = kwargs.get("end", self.end) file_ = kwargs.get("file_", self.file) fn = kwargs.get("fn", self.fn) encoding = kwargs.get("encoding", self.encoding) strargs = [] if encoding: cls = str else: cls = str for arg in args: if not isinstance(arg, cls): arg = safe_unicode(arg) if isinstance(arg, str) and encoding: arg = arg.encode(encoding, "asciize") strargs.append(arg) line = sep.join(strargs).rstrip(end) if pad is not False: if pad is True: width = _get_console_width() else: width = int(pad) line = line.ljust(width, padchar) if fn: fn(line) else: try: file_.write(line) if end: file_.write(end) except IOError: pass
def writecfg(which="user", worker=None): """ Write configuration file. which: 'user' or 'system' worker: worker instance if which == 'system' """ if which == "user": # user config - stores everything and overrides system-wide config cfgfilename = os.path.join(confighome, appname + ".ini") try: io = StringIO() cfg.write(io) io.seek(0) lines = io.read().strip("\n").split("\n") # Sorting works as long as config has only one section lines = [lines[0]] + sorted(lines[1:]) cfgfile = open(cfgfilename, "wb") cfgfile.write("\n".join(lines)) cfgfile.close() except Exception, exception: from debughelpers import handle_error handle_error(u"Warning - could not write user configuration file " "'%s': %s" % (cfgfilename, safe_unicode(exception))) return False
def get_data_path(relpath, rex=None): """ Search data_dirs for relpath and return the path or a file list. If relpath is a file, return the full path, if relpath is a directory, return a list of files in the intersection of searched directories. """ if (not relpath or relpath.endswith(os.path.sep) or (isinstance(os.path.altsep, basestring) and relpath.endswith(os.path.altsep))): return None intersection = [] paths = [] for dir_ in data_dirs: curpath = os.path.join(dir_, relpath) if os.path.exists(curpath): if os.path.isdir(curpath): try: filelist = listdir_re(curpath, rex) except Exception, exception: from log import safe_print safe_print(u"Error - directory '%s' listing failed: %s" % tuple(safe_unicode(s) for s in (curpath, exception))) else: for filename in filelist: if not filename in intersection: intersection += [filename] paths += [os.path.join(curpath, filename)] else: return curpath
def _schtasks(self, args, elevated=False, echo=False): if elevated: try: p = run_as_admin("schtasks.exe", args, close_process=False, show=False) except pywintypes.error as exception: if exception.args[0] == winerror.ERROR_CANCELLED: self.lastreturncode = winerror.ERROR_CANCELLED else: raise else: self.lastreturncode = int(p["hProcess"].handle == 0) p["hProcess"].Close() finally: self.stdout = "" else: args.insert(0, "schtasks.exe") startupinfo = sp.STARTUPINFO() startupinfo.dwFlags |= sp.STARTF_USESHOWWINDOW startupinfo.wShowWindow = sp.SW_HIDE p = sp.Popen([safe_str(arg) for arg in args], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.STDOUT, startupinfo=startupinfo) self.stdout, stderr = p.communicate() if echo: safe_print(safe_unicode(self.stdout, enc)) self.lastreturncode = p.returncode return self.lastreturncode == 0
def wait(self): self.listening = True if self.logfile: self.logfile.write( lang.getstr("connecting.to", ("Chromecast", " " + self.name)) + "\n") if not hasattr(self, "_cc"): # Find our ChromeCast try: self._cc = next(cc for cc in get_chromecasts() if safe_unicode( cc.device.friendly_name, "UTF-8") == self.name) except StopIteration: self.listening = False raise self._cc.register_handler(self._controller) # Wait for ChromeCast device to be ready while self.listening: self._cc.wait(0.05) if self._cc.status: break if self.listening: # Launch pattern generator app self._controller.launch() # Wait for it while (self.listening and self._cc.app_id != self._controller.supporting_app_id): sleep(0.05) self.conn = True safe_print(lang.getstr("connection.established"))
def init(set_wx_locale=False): """ Populate translation dict with found language strings and set locale. If set_wx_locale is True, set locale also for wxPython. """ langdirs = [] for dir_ in data_dirs: langdirs.append(os.path.join(dir_, "lang")) for langdir in langdirs: if os.path.exists(langdir) and os.path.isdir(langdir): try: langfiles = os.listdir(langdir) except Exception as exception: safe_print("Warning - directory '%s' listing failed: %s" % tuple(safe_unicode(s) for s in (langdir, exception))) else: for filename in langfiles: name, ext = os.path.splitext(filename) if ext.lower() == ".yaml" and name.lower() not in ldict: path = os.path.join(langdir, filename) ldict[name.lower()] = LazyDict_YAML_UltraLite(path) if len(ldict) == 0: handle_error(UserWarning("Warning: No language files found. The " "following places have been searched:\n%s" % "\n".join(langdirs)))
def main(): if "--help" in sys.argv[1:] or (not sys.argv[1:] and not gui): safe_print("Convert VRML file to X3D") safe_print("Author: Florian Hoech, licensed under the GPL version 3") safe_print("Usage: %s [OPTION]... FILE..." % os.path.basename(sys.argv[0])) safe_print("The output is written to FILENAME.x3d(.html)") safe_print("") safe_print(" --embed Embed viewer components in HTML instead of " "referencing them") safe_print(" --force Force fresh download of viewer components") safe_print(" --no-cache Don't use viewer components cache (only " "uses existing cache if") safe_print(" embedding components, can be overridden " "with --force)") if gui: safe_print(" --no-gui Don't use GUI (console mode)") safe_print(" --no-html Don't generate HTML file") safe_print(" --view View the generated file (if no GUI)") if not gui: safe_print(" --batch Don't pause after processing") safe_print(" FILE Filename of VRML file to convert") if gui: return if gui: config.initcfg("VRML-to-X3D-converter") lang.init() lang.update_defaults() cache = not "--no-cache" in sys.argv[1:] embed = "--embed" in sys.argv force = "--force" in sys.argv html = not "--no-html" in sys.argv[1:] if not gui: result = None view = "--view" in sys.argv[1:] for arg in sys.argv[1:]: if not arg.startswith("--"): result = vrmlfile2x3dfile(safe_unicode(arg), html=html, embed=embed, view=view, force=force, cache=cache, gui=gui) if result is None: safe_print("No filename given.") if sys.stdout.isatty() and not "--batch" in sys.argv[1:]: input("Press RETURN to exit") sys.exit(int(not result)) else: view = not "--no-view" in sys.argv[1:] app = BaseApp(0) app.TopWindow = VRML2X3DFrame(html, embed, view, force, cache) if sys.platform == "darwin": app.TopWindow.init_menubar() wx.CallLater(1, _main, app) app.MainLoop()
def makecfgdir(which="user", worker=None): if which == "user": if not os.path.exists(confighome): try: os.makedirs(confighome) except Exception, exception: from debughelpers import handle_error handle_error(u"Warning - could not create configuration directory " "'%s': %s" % (confighome, safe_unicode(exception))) return False
def create(report_path, placeholders2data, pack=True, templatename="report"): """ Create a report with all placeholders substituted by data. """ # read report template templatefilename = "%s.html" % templatename report_html_template_path = get_data_path( os.path.join("report", templatefilename)) if not report_html_template_path: raise IOError(lang.getstr("file.missing", templatefilename)) try: report_html_template = codecs.open(report_html_template_path, "r", "UTF-8") except (IOError, OSError) as exception: raise exception.__class__( lang.getstr("error.file.open", report_html_template_path)) report_html = report_html_template.read() report_html_template.close() # create report for placeholder, data in placeholders2data.items(): report_html = report_html.replace(placeholder, data) for include in ("base.css", "compare.css", "print.css", "jsapi-packages.js", "jsapi-patches.js", "compare.constants.js", "compare.variables.js", "compare.functions.js", "compare.init.js", "uniformity.functions.js"): path = get_data_path(os.path.join("report", include)) if not path: raise IOError(lang.getstr("file.missing", include)) try: f = codecs.open(path, "r", "UTF-8") except (IOError, OSError) as exception: raise exception.__class__(lang.getstr("error.file.open", path)) if include.endswith(".js"): js = f.read() if pack: packer = jspacker.JavaScriptPacker() js = packer.pack(js, 62, True).strip() report_html = report_html.replace( 'src="%s">' % include, ">/*<![CDATA[*/\n" + js + "\n/*]]>*/") else: report_html = report_html.replace('@import "%s";' % include, f.read().strip()) f.close() # write report try: report_html_file = codecs.open(report_path, "w", "UTF-8") except (IOError, OSError) as exception: raise exception.__class__( lang.getstr("error.file.create", report_path) + "\n\n" + safe_unicode(exception)) report_html_file.write(report_html) report_html_file.close()
def add_dispcal_options_to_cal(cal, options_dispcal): # Add dispcal options to cal options_dispcal = quote_nonoption_args(options_dispcal) try: cgats = CGATS.CGATS(cal) cgats[0].add_section( "ARGYLL_DISPCAL_ARGS", " ".join(options_dispcal).encode("UTF-7", "replace")) return cgats except Exception as exception: safe_print(safe_unicode(traceback.format_exc()))
def get_single_response(self): # Buffer received data until EOT (response end marker) and return # single response (additional data will still be in the buffer) while not "\4" in self.recv_buffer: incoming = self.recv(4096) if incoming == "": raise socket.error(lang.getstr("connection.broken")) self.recv_buffer += incoming end = self.recv_buffer.find("\4") single_response = self.recv_buffer[:end] self.recv_buffer = self.recv_buffer[end + 1:] return safe_unicode(single_response, "UTF-8")
def exit(self, raise_exception=True): self.close(raise_exception) if self.temp and os.path.isfile(self.profile_path): os.remove(self.profile_path) if self.tempdir and not os.listdir(self.tempdir): try: shutil.rmtree(self.tempdir, True) except Exception as exception: safe_print("Warning - temporary directory '%s' could " "not be removed: %s" % tuple( safe_unicode(s) for s in (self.tempdir, exception)))
def cal_to_fake_profile(cal): """ Create and return a 'fake' ICCProfile with just a vcgt tag. cal must refer to a valid Argyll CAL file and can be a CGATS instance or a filename. """ vcgt, cal = cal_to_vcgt(cal, True) if not vcgt: return profile = ICCP.ICCProfile() profile.fileName = cal.filename profile._data = "\0" * 128 profile._tags.desc = ICCP.TextDescriptionType("", "desc") profile._tags.desc.ASCII = safe_unicode(os.path.basename( cal.filename)).encode("ascii", "asciize") profile._tags.desc.Unicode = safe_unicode(os.path.basename(cal.filename)) profile._tags.vcgt = vcgt profile.size = len(profile.data) profile.is_loaded = True return profile
def initcfg(): """ Initialize the configuration. Read in settings if the configuration file exists, else create the settings directory if nonexistent. """ # read pre-v0.2.2b configuration if present if sys.platform == "darwin": oldcfg = os.path.join(expanduseru("~"), "Library", "Preferences", appname + " Preferences") else: oldcfg = os.path.join(expanduseru("~"), "." + appname) makecfgdir() if os.path.exists(confighome) and \ not os.path.exists(os.path.join(confighome, appname + ".ini")): try: if os.path.isfile(oldcfg): oldcfg_file = open(oldcfg, "rb") oldcfg_contents = oldcfg_file.read() oldcfg_file.close() cfg_file = open(os.path.join(confighome, appname + ".ini"), "wb") cfg_file.write("[Default]\n" + oldcfg_contents) cfg_file.close() elif sys.platform == "win32": key = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, "Software\\" + appname) numsubkeys, numvalues, mtime = _winreg.QueryInfoKey(key) cfg_file = open(os.path.join(confighome, appname + ".ini"), "wb") cfg_file.write("[Default]\n") for i in range(numvalues): name, value, type_ = _winreg.EnumValue(key, i) if type_ == 1: cfg_file.write((u"%s = %s\n" % (name, value)).encode("UTF-8")) cfg_file.close() except Exception, exception: # WindowsError 2 means registry key does not exist, do not show # warning in that case if sys.platform != "win32" or not hasattr(exception, "errno") or \ exception.errno != 2: from log import safe_print safe_print("Warning - could not process old configuration:", safe_unicode(exception)) # Set a few defaults which have None as possible value and thus cannot # be set in the 'defaults' collection setcfg("gamap_src_viewcond", "mt") setcfg("gamap_out_viewcond", "mt")
def get_file_logger(name, level=logging.DEBUG, when="midnight", backupCount=0): logger = logging.getLogger(name) logger.setLevel(level) logfile = os.path.join(logdir, name + ".log") for handler in logger.handlers: if (isinstance(handler, logging.handlers.TimedRotatingFileHandler) and handler.baseFilename == os.path.abspath(logfile)): return logger if not os.path.exists(logdir): try: os.makedirs(logdir) except Exception, exception: safe_print(u"Warning - log directory '%s' could not be created: %s" % tuple(safe_unicode(s) for s in (logdir, exception)))
def disconnect(self): if self.conn: try: peer = self.conn.getpeername() self.conn.shutdown(socket.SHUT_RDWR) except socket.error as exception: if exception.errno != errno.ENOTCONN: self.add_text(safe_unicode(exception) + "\n") else: self.add_text(lang.getstr("disconnected.from", peer) + "\n") self.conn.close() del self.conn self.conn = None self.commands = [] else: self.add_error_text(lang.getstr("not_connected") + "\n")
def add_options_to_ti3(ti3, options_dispcal=None, options_colprof=None): # Add dispcal and colprof options to ti3 try: cgats = CGATS.CGATS(ti3) if options_colprof: options_colprof = quote_nonoption_args(options_colprof) cgats[0].add_section( "ARGYLL_COLPROF_ARGS", " ".join(options_colprof).encode("UTF-7", "replace")) if options_dispcal and 1 in cgats: options_dispcal = quote_nonoption_args(options_dispcal) cgats[1].add_section( "ARGYLL_DISPCAL_ARGS", " ".join(options_dispcal).encode("UTF-7", "replace")) return cgats except Exception as exception: safe_print(safe_unicode(traceback.format_exc()))
def cal_to_vcgt(cal, return_cgats=False): """ Create a vcgt tag from calibration data. cal must refer to a valid Argyll CAL file and can be a CGATS instance or a filename. """ if not isinstance(cal, CGATS.CGATS): try: cal = CGATS.CGATS(cal) except (IOError, CGATS.CGATSInvalidError, CGATS.CGATSInvalidOperationError, CGATS.CGATSKeyError, CGATS.CGATSTypeError, CGATS.CGATSValueError) as exception: safe_print("Warning - couldn't process CGATS file '%s': %s" % tuple(safe_unicode(s) for s in (cal, exception))) return None required_fields = ("RGB_I", "RGB_R", "RGB_G", "RGB_B") data_format = cal.queryv1("DATA_FORMAT") if data_format: for field in required_fields: if not field in list(data_format.values()): if debug: safe_print("[D] Missing required field:", field) return None for field in list(data_format.values()): if not field in required_fields: if debug: safe_print("[D] Unknown field:", field) return None entries = cal.queryv(required_fields) if len(entries) < 1: if debug: safe_print("[D] No entries found in calibration", cal.filename) return None vcgt = ICCP.VideoCardGammaTableType("", "vcgt") vcgt.update({ "channels": 3, "entryCount": len(entries), "entrySize": 2, "data": [[], [], []] }) for n in entries: for i in range(3): vcgt.data[i].append(entries[n][i + 1] * 65535.0) if return_cgats: return vcgt, cal return vcgt
def main(module=None): mp.freeze_support() if mp.current_process().name != "MainProcess": return if module: name = "%s-%s" % (appbasename, module) else: name = appbasename applockfilename = os.path.join(confighome, "%s.lock" % name) try: _main(module, name, applockfilename) except Exception as exception: if isinstance(exception, ResourceError): error = exception else: error = Error("Fatal error: " + safe_unicode(exception)) handle_error(error) _exit(applockfilename, getattr(sys, "_appsocket_port", ""))
def getstr(id_str, strvars=None, lcode=None, default=None): """ Get a translated string from the dictionary """ if not lcode: lcode = getcode() if not lcode in ldict or not id_str in ldict[lcode]: # fall back to english lcode = "en" if lcode in ldict and id_str in ldict[lcode]: lstr = ldict[lcode][id_str] if debug: if not id_str in usage or not isinstance(usage[id_str], int): usage[id_str] = 1 else: usage[id_str] += 1 if strvars is not None: if not isinstance(strvars, (list, tuple)): strvars = [strvars] fmt = re.findall(r"%\d?(?:\.\d+)?[deEfFgGiorsxX]", lstr) if len(fmt) == len(strvars): if not isinstance(strvars, list): strvars = list(strvars) for i, s in enumerate(strvars): if fmt[i].endswith("s"): s = safe_unicode(s) elif not fmt[i].endswith("r"): try: if fmt[i][-1] in "dioxX": s = int(s) else: s = float(s) except (TypeError, ValueError): s = 0 strvars[i] = s lstr %= tuple(strvars) return lstr else: if (debug and id_str and not isinstance(id_str, str) and not " " in id_str): usage[id_str] = 0 return default or id_str
def check_result(self, delayedResult, get_response=False, additional_commands=None, colorize=True): try: result = delayedResult.get() except Exception as exception: if hasattr(exception, "originalTraceback"): self.add_text(exception.originalTraceback) result = exception if result: if isinstance(result, socket.socket): self.conn = result result = lang.getstr("connection.established") text = "%s\n" % safe_unicode(result) self.add_text(text) if colorize or isinstance(result, Exception): end = self.console.GetLastPosition() start = end - len(text) if isinstance(result, Exception): color = ERRORCOLOR else: color = RESPONSECOLOR self.mark_text(start, end, color) if get_response and not isinstance(result, Exception): delayedresult.startWorker(self.check_result, get_response, cargs=(False, additional_commands)) else: self.add_text("> ") if additional_commands: self.add_text(additional_commands[0].rstrip("\n")) if additional_commands[0].endswith("\n"): self.send_command_handler(additional_commands[0], additional_commands[1:]) return self.console.SetFocus() self.busy = False
def html(self, title="Untitled", xhtml=False, embed=False, force=False, cache=True): """ Convert X3D to HTML This will generate HTML5 by default unless you set xhtml=True. If embed is True, the X3DOM runtime and X3D viewer will be embedded in the HTML (increases filesize considerably) """ # Get children of X3D document x3d_html = re.sub("\s*</?X3D(?:\s+[^>]*)?>\s*", "", self.markup(xhtml, True)) if not xhtml: # Convert uppercase letters at start of tag name to lowercase x3d_html = re.sub("(</?[0-9A-Z]+)", lambda match: match.groups()[0].lower(), x3d_html) # Indent x3d_html = "\n".join( ["\t" * 2 + line for line in x3d_html.splitlines()]).lstrip() # Collect resources def get_resource(url, source=True): baseurl, basename = os.path.split(url) # Strip protocol cache_uri = re.sub("^\w+://", "", baseurl) # Strip www cache_uri = re.sub("^(?:www\.)?", "", cache_uri) # domain.com -> com.domain domain, path = cache_uri.split("/", 1) cache_uri = "/".join([".".join(reversed(domain.split("."))), path]) # com.domain/path -> com.domain.path cache_uri = re.sub("^([^/]+)/", "\\1.", cache_uri) cachedir = os.path.join(cachepath, os.path.join(*cache_uri.split("/"))) if not os.path.isdir(cachedir): _safe_print("Creating cache directory:", cachedir) os.makedirs(cachedir) cachefilename = os.path.join(cachedir, basename) body = "" if not force and os.path.isfile(cachefilename): _safe_print("Using cached file:", cachefilename) with open(cachefilename, "rb") as cachefile: body = cachefile.read() if not body.strip(): for url in (url, url.replace("https://", "http://")): _safe_print("Requesting:", url) try: response = urllib.request.urlopen(url) except (socket.error, urllib.error.URLError, http.client.HTTPException) as exception: _safe_print(exception) else: body = response.read() response.close() break if not body.strip(): # Fallback to local copy url = get_data_path("x3d-viewer/" + basename) if not url: _safe_print("Error: Resource not found:", basename) return with open(url, "rb") as resource_file: body = resource_file.read() if body.strip(): if cache and (force or not os.path.isfile(cachefilename)): with open(cachefilename, "wb") as cachefile: cachefile.write(body) if source and not basename.endswith(".swf"): if basename.endswith(".css"): return "<style>%s</style>" % body elif basename.endswith(".js"): return "<script>%s" % body else: return body else: return "file:///" + safe_unicode(cachefilename).encode( "UTF-8").lstrip("/").replace(os.path.sep, "/") else: _safe_print("Error: Empty document:", url) if os.path.isfile(cachefilename): _safe_print("Removing", cachefilename) os.remove(cachefilename) # Get HTML template from cache or online html = get_resource( "https://%s/x3d-viewer/release/x3d-viewer.html" % domain.lower(), True) if cache or embed: # Update resources in HTML restags = re.findall("<[^>]+\s+data-fallback-\w+=[^>]*>", html) for restag in restags: attrname = re.search(r"\s+data-fallback-(\w+)=", restag).groups()[0] url = re.search(r"\s+%s=([\"'])(.+?)\1" % attrname, restag).groups()[1] if url.endswith(".swf") and not cache: continue resource = get_resource(url, embed) if not resource: continue if embed and not url.endswith(".swf"): html = html.replace(restag, resource) else: updated_restag = re.sub( r"(\s+data-fallback-%s=)([\"']).+?\2" % attrname, create_replace_function(r"\1\2%s\2", resource), restag) html = html.replace(restag, updated_restag) # Update title html = re.sub( "(<title>)[^<]*(</title>)", create_replace_function(r"\1%s\2", safe_unicode(title).encode("UTF-8")), html) # Insert X3D html = html.replace("</x3d>", "\t" + x3d_html + "\n\t\t</x3d>") # Finish if xhtml: html = "<?xml version='1.0' encoding='UTF-8'?>\n" + html html = re.sub("\s*/>", " />", html) else: html = re.sub("\s*/>", ">", html) return html
def get_resource(url, source=True): baseurl, basename = os.path.split(url) # Strip protocol cache_uri = re.sub("^\w+://", "", baseurl) # Strip www cache_uri = re.sub("^(?:www\.)?", "", cache_uri) # domain.com -> com.domain domain, path = cache_uri.split("/", 1) cache_uri = "/".join([".".join(reversed(domain.split("."))), path]) # com.domain/path -> com.domain.path cache_uri = re.sub("^([^/]+)/", "\\1.", cache_uri) cachedir = os.path.join(cachepath, os.path.join(*cache_uri.split("/"))) if not os.path.isdir(cachedir): _safe_print("Creating cache directory:", cachedir) os.makedirs(cachedir) cachefilename = os.path.join(cachedir, basename) body = "" if not force and os.path.isfile(cachefilename): _safe_print("Using cached file:", cachefilename) with open(cachefilename, "rb") as cachefile: body = cachefile.read() if not body.strip(): for url in (url, url.replace("https://", "http://")): _safe_print("Requesting:", url) try: response = urllib.request.urlopen(url) except (socket.error, urllib.error.URLError, http.client.HTTPException) as exception: _safe_print(exception) else: body = response.read() response.close() break if not body.strip(): # Fallback to local copy url = get_data_path("x3d-viewer/" + basename) if not url: _safe_print("Error: Resource not found:", basename) return with open(url, "rb") as resource_file: body = resource_file.read() if body.strip(): if cache and (force or not os.path.isfile(cachefilename)): with open(cachefilename, "wb") as cachefile: cachefile.write(body) if source and not basename.endswith(".swf"): if basename.endswith(".css"): return "<style>%s</style>" % body elif basename.endswith(".js"): return "<script>%s" % body else: return body else: return "file:///" + safe_unicode(cachefilename).encode( "UTF-8").lstrip("/").replace(os.path.sep, "/") else: _safe_print("Error: Empty document:", url) if os.path.isfile(cachefilename): _safe_print("Removing", cachefilename) os.remove(cachefilename)
def __init__(self, profile, intent="r", direction="f", order="n", pcs=None, scale=1, cwd=None, startupinfo=None, use_icclu=False, use_cam_clipping=False, logfile=None, worker=None, show_actual_if_clipped=False, input_encoding=None, output_encoding=None, convert_video_rgb_to_clut65=False, verbose=1): if not profile: raise Error("Xicclu: Profile is %r" % profile) WorkerBase.__init__(self) self.scale = scale self.convert_video_rgb_to_clut65 = convert_video_rgb_to_clut65 self.logfile = logfile self.worker = worker self.temp = False utilname = "icclu" if use_icclu else "xicclu" xicclu = get_argyll_util(utilname) if not xicclu: raise Error(lang.getstr("argyll.util.not_found", utilname)) if not isinstance(profile, (CGATS.CGATS, ICCP.ICCProfile)): if profile.lower().endswith(".cal"): profile = CGATS.CGATS(profile) else: profile = ICCP.ICCProfile(profile) is_profile = isinstance(profile, ICCP.ICCProfile) if (is_profile and profile.version >= 4 and not profile.convert_iccv4_tags_to_iccv2()): raise Error("\n".join([ lang.getstr("profile.iccv4.unsupported"), profile.getDescription() ])) if not profile.fileName or not os.path.isfile(profile.fileName): if profile.fileName: prefix = os.path.basename(profile.fileName) elif is_profile: prefix = make_filename_safe(profile.getDescription(), concat=False) + profile_ext else: # CGATS (.cal) prefix = "cal" prefix += "-" if not cwd: cwd = self.create_tempdir() if isinstance(cwd, Exception): raise cwd fd, profile.fileName = tempfile.mkstemp("", prefix, dir=cwd) stream = os.fdopen(fd, "wb") profile.write(stream) stream.close() self.temp = True elif not cwd: cwd = os.path.dirname(profile.fileName) profile_basename = safe_unicode(os.path.basename(profile.fileName)) profile_path = profile.fileName if sys.platform == "win32": profile_path = win32api.GetShortPathName(profile_path) self.profile_path = safe_str(profile_path) if sys.platform == "win32" and not startupinfo: startupinfo = sp.STARTUPINFO() startupinfo.dwFlags |= sp.STARTF_USESHOWWINDOW startupinfo.wShowWindow = sp.SW_HIDE xicclu = safe_str(xicclu) cwd = safe_str(cwd) self.verbose = verbose args = [xicclu, "-v%i" % verbose, "-s%s" % scale] self.show_actual_if_clipped = False if utilname == "xicclu": if (is_profile and show_actual_if_clipped and "A2B0" in profile.tags and ("B2A0" in profile.tags or direction == "if")): args.append("-a") self.show_actual_if_clipped = True if use_cam_clipping: args.append("-b") if get_argyll_version("xicclu") >= [1, 6]: # Add encoding parameters # Note: Not adding -e -E can cause problems due to unitialized # in_tvenc and out_tvenc variables in xicclu.c for Argyll 1.6.x if not input_encoding: input_encoding = "n" if not output_encoding: output_encoding = "n" args += [ "-e" + safe_str(input_encoding), "-E" + safe_str(output_encoding) ] args.append("-f" + direction) self.output_scale = 1.0 if is_profile: if profile.profileClass not in ("abst", "link"): args.append("-i" + intent) if order != "n": args.append("-o" + order) if profile.profileClass != "link": if (direction in ("f", "ib") and (pcs == "x" or (profile.connectionColorSpace == "XYZ" and not pcs))): # In case of forward lookup with XYZ PCS, use 0..100 scaling # internally so we get extra precision from xicclu for the # decimal part. Scale back to 0..1 later. pcs = "X" self.output_scale = 100.0 if pcs: args.append("-p" + pcs) args.append(self.profile_path) if debug or verbose > 1: self.sessionlogfile = LogFile(profile_basename + ".xicclu", os.path.dirname(profile.fileName)) if is_profile: profile_act = ICCP.ICCProfile(profile.fileName) self.sessionlogfile.write( "Profile ID %s (actual %s)" % (hexlify( profile.ID), hexlify(profile_act.calculateID(False)))) if cwd: self.log(lang.getstr("working_dir")) indent = " " for name in cwd.split(os.path.sep): self.log( textwrap.fill(name + os.path.sep, 80, expand_tabs=False, replace_whitespace=False, initial_indent=indent, subsequent_indent=indent)) indent += " " self.log("") self.log(lang.getstr("commandline")) printcmdline(xicclu, args[1:], fn=self.log, cwd=cwd) self.log("") self.startupinfo = startupinfo self.args = args self.cwd = cwd self.spawn()
for handler in logger.handlers: if (isinstance(handler, logging.handlers.TimedRotatingFileHandler) and handler.baseFilename == os.path.abspath(logfile)): return logger if not os.path.exists(logdir): try: os.makedirs(logdir) except Exception, exception: safe_print(u"Warning - log directory '%s' could not be created: %s" % tuple(safe_unicode(s) for s in (logdir, exception))) elif os.path.exists(logfile): try: logstat = os.stat(logfile) except Exception, exception: safe_print(u"Warning - os.stat('%s') failed: %s" % tuple(safe_unicode(s) for s in (logfile, exception))) else: # rollover needed? try: mtime = localtime(logstat.st_mtime) except ValueError, exception: # This can happen on Windows because localtime() is buggy on # that platform. See: # http://stackoverflow.com/questions/4434629/zipfile-module-in-python-runtime-problems # http://bugs.python.org/issue1760357 # To overcome this problem, we ignore the real modification # date and force a rollover mtime = localtime(time() - 60 * 60 * 24) if localtime()[:3] > mtime[:3]: # do rollover logbackup = logfile + strftime(".%Y-%m-%d", mtime)
def __init__(self, parent, cgats, worker=None): """ Init new CCXPlot window. parent Parent window (only used for error dialogs) cgats A CCMX/CCSS CGATS instance worker Worker instance """ self.is_ccss = cgats[0].type == "CCSS" desc = cgats.get_descriptor() if cgats.filename: fn, ext = os.path.splitext(os.path.basename(cgats.filename)) else: fn = desc if self.is_ccss: ext = ".ccss" else: ext = ".ccmx" desc = lang.getstr(ext[1:] + "." + fn, default=desc) if self.is_ccss: ccxx_type = "spectral" else: ccxx_type = "matrix" title = "%s: %s" % (lang.getstr(ccxx_type), desc) if self.is_ccss: # Convert to TI3 so we can get XYZ from spectra for coloring temp = worker.create_tempdir() if isinstance(temp, Exception): show_result_dialog(temp, parent) else: basename = make_filename_safe(desc) temp_path = os.path.join(temp, basename + ".ti3") cgats[0].type = "CTI3" cgats[0].DEVICE_CLASS = "DISPLAY" cgats.write(temp_path) temp_out_path = os.path.join(temp, basename + ".CIE.ti3") result = worker.exec_cmd(get_argyll_util("spec2cie"), [temp_path, temp_out_path], capture_output=True) if isinstance(result, Exception) or not result: show_result_dialog( UnloggedError(result or "".join(worker.errors)), parent) worker.wrapup(False) else: try: cgats = CGATS.CGATS(temp_out_path) except Exception as exception: show_result_dialog(exception, parent) finally: worker.wrapup(False) data_format = cgats.queryv1("DATA_FORMAT") data = cgats.queryv1("DATA") XYZ_max = 0 self.samples = [] if self.is_ccss: x_min = cgats.queryv1("SPECTRAL_START_NM") x_max = cgats.queryv1("SPECTRAL_END_NM") bands = cgats.queryv1("SPECTRAL_BANDS") lores = bands <= 40 if lores: # Interpolate if lores # 1nm intervals steps = int(x_max - x_min) + 1 safe_print("Up-interpolating", bands, "spectral bands to", steps) step = (x_max - x_min) / (steps - 1.) else: step = (x_max - x_min) / (bands - 1.) y_min = 0 y_max = 1 Y_max = 0 for i, sample in data.items(): # Get nm and spectral power values = [] x = x_min for k in data_format.values(): if k.startswith("SPEC_"): y = sample[k] y_min = min(y, y_min) y_max = max(y, y_max) if lores: values.append(y) else: values.append((x, y)) x += step if lores: # Interpolate if lores. Use Catmull-Rom instead of # PolySpline as we want curves to go through points exactly numvalues = len(values) interp = ICCP.CRInterpolation(values) values = [] for i in range(steps): values.append( (x, interp(i / (steps - 1.) * (numvalues - 1.)))) x += step # Get XYZ for colorization XYZ = [] for component in "XYZ": label = "XYZ_" + component if label in sample: v = sample[label] XYZ_max = max(XYZ_max, v) if label == "XYZ_Y": Y_max = max(Y_max, v) XYZ.append(v) self.samples.append((XYZ, values, {})) Plot = plot.PolyLine Plot._attributes["width"] = 1 else: # CCMX cube_size = 2 x_min = 0 y_min = 0 mtx = colormath.Matrix3x3( [[sample[k] for k in data_format.values()] for sample in data.values()]) imtx = mtx.inverted() # Get XYZ that colorimeter would measure without matrix (sRGB ref, # so not accurate, but useful for visual representation which is all # we care about here) if cube_size == 2: scale = 1 x_max = 100 * scale y_max = x_max * (74.6 / 67.4) if sys.platform != "win32": x_center = x_max / 2. else: x_center = x_max / 2. - 2.5 y_center = y_max / 2. x_center *= scale y_center *= scale pos2rgb = [((x_center - 23.7, y_center - 13.7), (0, 0, 1)), ((x_center, y_center + 27.3), (0, 1, 0)), ((x_center + 23.7, y_center - 13.7), (1, 0, 0)), ((x_center - 23.7, y_center + 13.7), (0, 1, 1)), ((x_center, y_center - 27.3), (1, 0, 1)), ((x_center + 23.7, y_center + 13.7), (1, 1, 0)), ((x_center, y_center), (1, 1, 1))] attrs_c = {'size': 10} attrs_r = {'size': 5} else: x_max = 100 y_max = 100 y = -5 pos2rgb = [] for R in range(cube_size): for G in range(cube_size): x = -5 y += 10 for B in range(cube_size): x += 10 pos2rgb.append(((x, y), (v / (cube_size - 1.0) for v in (R, G, B)))) attrs_c = {'marker': 'square', 'size': 10} attrs_r = {'marker': 'square', 'size': 5} Y_max = (imtx * colormath.get_whitepoint("D65"))[1] for i, ((x, y), (R, G, B)) in enumerate(pos2rgb): XYZ = list(colormath.RGB2XYZ(R, G, B)) X, Y, Z = imtx * XYZ XYZ_max = max(XYZ_max, X, Y, Z) self.samples.append(([X, Y, Z], [(x, y)], attrs_c)) self.samples.append((XYZ, [(x, y)], attrs_r)) Plot = plot.PolyMarker if self.is_ccss: # Protect against division by zero when range is zero if not x_max - x_min: x_min = 350.0 x_max = 750.0 if not y_max - y_min: y_min = 0.0 y_max = 10.0 y_zero = 0 self.ccxx_axis_x = (math.floor(x_min / 50.) * 50, math.ceil(x_max / 50.) * 50) self.spec_x = (self.ccxx_axis_x[1] - self.ccxx_axis_x[0]) / 50. graph_range = nicenum(y_max - y_zero, False) d = nicenum(graph_range / (NTICK - 1.0), True) self.spec_y = math.ceil(y_max / d) self.ccxx_axis_y = (math.floor(y_zero / d) * d, self.spec_y * d) else: self.ccxx_axis_x = (math.floor(x_min / 20.) * 20, math.ceil(x_max / 20.) * 20) self.ccxx_axis_y = (math.floor(y_min), math.ceil(y_max)) self.gfx = [] for XYZ, values, attrs in self.samples: if len(XYZ) == 3: # Got XYZ if attrs.get("size") > 11.25: # Colorimeter XYZ if Y_max > 1: # Colorimeter brighter than ref XYZ[:] = [v / Y_max for v in XYZ] else: # Colorimeter dimmer than ref XYZ[:] = [v * Y_max for v in XYZ] else: # Ref XYZ if Y_max > 1: # Colorimeter brighter than ref XYZ[:] = [v / Y_max for v in XYZ] RGB = tuple( int(v) for v in colormath.XYZ2RGB(*XYZ, scale=255, round_=True)) else: RGB = (153, 153, 153) self.gfx.append(Plot(values, colour=wx.Colour(*RGB), **attrs)) if self.is_ccss: # Add a few points at the extremes to define a bounding box self.gfx.append( plot.PolyLine( [(self.ccxx_axis_x[0], self.ccxx_axis_y[0]), (self.ccxx_axis_x[1], self.ccxx_axis_y[1] - y_min)], colour=wx.Colour(0, 0, 0, 0))) ref = cgats.queryv1("REFERENCE") if ref: ref = get_canonical_instrument_name(safe_unicode(ref, "UTF-8")) if not self.is_ccss: observers_ab = {} for observer in config.valid_values["observer"]: observers_ab[observer] = lang.getstr("observer." + observer) x_label = [lang.getstr("matrix")] x_label.extend(["%9.6f %9.6f %9.6f" % tuple(row) for row in mtx]) if ref: ref_observer = cgats.queryv1("REFERENCE_OBSERVER") if ref_observer: ref += ", " + observers_ab.get(ref_observer, ref_observer) x_label.append("") x_label.append(ref) fit_method = cgats.queryv1("FIT_METHOD") if fit_method == "xy": fit_method = lang.getstr("ccmx.use_four_color_matrix_method") elif fit_method: fit_method = lang.getstr("perceptual") fit_de00_avg = cgats.queryv1("FIT_AVG_DE00") if not isinstance(fit_de00_avg, float): fit_de00_avg = None fit_de00_max = cgats.queryv1("FIT_MAX_DE00") if not isinstance(fit_de00_max, float): fit_de00_max = None if fit_method: x_label.append(fit_method) fit_de00 = [] if fit_de00_avg: fit_de00.append( "ΔE*00 %s %.4f" % (lang.getstr("profile.self_check.avg"), fit_de00_avg)) if fit_de00_max: fit_de00.append( "ΔE*00 %s %.4f" % (lang.getstr("profile.self_check.max"), fit_de00_max)) if fit_de00: x_label.append("\n".join(fit_de00)) x_label = "\n".join(x_label) else: x_label = "" if ref: x_label += ref + ", " x_label += "%.1fnm, %i-%inm" % ((x_max - x_min) / (bands - 1.0), x_min, x_max) scale = max(getcfg("app.dpi") / config.get_default_dpi(), 1) style = wx.DEFAULT_FRAME_STYLE wx.Frame.__init__(self, None, -1, title, style=style) self.SetIcons(config.get_icon_bundle([256, 48, 32, 16], appname)) self.SetBackgroundColour(BGCOLOUR) self.Sizer = wx.GridSizer(1, 1, 0, 0) bg = wx.Panel(self) bg.SetBackgroundColour(BGCOLOUR) bg.Sizer = wx.BoxSizer(wx.VERTICAL) self.canvas = canvas = LUTCanvas(bg) if self.is_ccss: bg.MinSize = (513 * scale, 557 * scale) btnsizer = wx.BoxSizer(wx.HORIZONTAL) bg.Sizer.Add(btnsizer, flag=wx.EXPAND | wx.TOP | wx.RIGHT | wx.LEFT, border=16) self.toggle_btn = FlatShadedButton(bg, -1, label=lang.getstr("spectral")) btnsizer.Add(self.toggle_btn, 1) self.Sizer.Add(bg, 1, flag=wx.EXPAND) bg.Sizer.Add(canvas, 1, flag=wx.EXPAND) else: self.Sizer.Add(bg, flag=wx.ALIGN_CENTER) canvas_w = 240 * scale canvas.MinSize = (canvas_w, canvas_w * (74.6 / 67.4)) bg.Sizer.Add(canvas, flag=wx.ALIGN_CENTER) label = wx.StaticText(bg, -1, x_label.replace("&", "&&"), style=wx.ALIGN_CENTRE_HORIZONTAL) label.SetForegroundColour(FGCOLOUR) label.SetMaxFontSize(11) bg.Sizer.Add(label, flag=wx.ALIGN_CENTER | wx.ALL & ~wx.TOP, border=16 * scale) canvas.SetBackgroundColour(BGCOLOUR) canvas.SetEnableCenterLines(False) canvas.SetEnableDiagonals(False) canvas.SetEnableGrid(True) canvas.enableTicks = (True, True) canvas.tickPen = wx.Pen(GRIDCOLOUR, canvas._pointSize[0]) canvas.SetEnablePointLabel(False) canvas.SetEnableTitle(True) canvas.SetForegroundColour(FGCOLOUR) canvas.SetGridColour(GRIDCOLOUR) canvas.canvas.BackgroundColour = BGCOLOUR if self.is_ccss: canvas.HandCursor = wx.StockCursor(wx.CURSOR_SIZING) canvas.SetCursor(canvas.HandCursor) else: canvas.canvas.Unbind(wx.EVT_LEFT_DCLICK) canvas.SetEnableDrag(False) canvas.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) canvas.SetXSpec('none') canvas.SetYSpec('none') # CallAfter is needed under GTK as usual wx.CallAfter(self.draw_ccxx) if self.is_ccss: self.Bind(wx.EVT_KEY_DOWN, self.key_handler) for child in self.GetAllChildren(): child.Bind(wx.EVT_KEY_DOWN, self.key_handler) child.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel) self.toggle_btn.Bind(wx.EVT_BUTTON, self.toggle_draw) self.Bind(wx.EVT_SIZE, self.OnSize) else: bg.Sizer.Add((0, 16)) self.Sizer.SetSizeHints(self) self.Sizer.Layout()
def __init__(self): SimpleTerminal.__init__( self, None, wx.ID_ANY, lang.getstr("scripting-client"), start_timer=False, pos=(getcfg("position.scripting.x"), getcfg("position.scripting.y")), size=(getcfg("size.scripting.w"), getcfg("size.scripting.h")), consolestyle=wx.TE_CHARWRAP | wx.TE_MULTILINE | wx.TE_PROCESS_ENTER | wx.TE_RICH | wx.VSCROLL | wx.NO_BORDER, show=False, name="scriptingframe") self.SetIcons( config.get_icon_bundle([256, 48, 32, 16], appname + "-scripting-client")) self.console.SetForegroundColour("#EEEEEE") self.console.SetDefaultStyle(wx.TextAttr("#EEEEEE")) self.busy = False self.commands = [] self.history = [] self.historyfilename = os.path.join( confighome, config.appbasename + "-scripting-client.history") if os.path.isfile(self.historyfilename): try: with open(self.historyfilename) as historyfile: for line in historyfile: self.history.append( safe_unicode(line, "UTF-8").rstrip("\r\n")) except EnvironmentError as exception: safe_print("Warning - couldn't read history file:", exception) # Always have empty selection at bottom self.history.append("") self.historypos = len(self.history) - 1 self.overwrite = False # Determine which application we should connect to by default (if any) self.conn = None scripting_hosts = self.get_scripting_hosts() self.sizer.Layout() if sys.platform != "darwin": # Under Mac OS X, the transparency messes up the window shadow if # there is another window's border behind self.SetTransparent(240) self.Bind(wx.EVT_ACTIVATE, self.OnActivate) self.Bind(wx.EVT_SIZE, self.OnSize) self.Unbind(wx.EVT_CHAR_HOOK) self.console.Unbind(wx.EVT_KEY_DOWN, self.console) self.console.Bind(wx.EVT_KEY_DOWN, self.key_handler) self.console.Bind(wx.EVT_TEXT_COPY, self.copy_text_handler) self.console.Bind(wx.EVT_TEXT_PASTE, self.paste_text_handler) if sys.platform == "darwin": # Under Mac OS X, pasting text via the context menu isn't catched # by EVT_TEXT_PASTE. TODO: Implement custom context menu. self.console.Bind(wx.EVT_CONTEXT_MENU, lambda event: None) if scripting_hosts: self.add_text("> getscriptinghosts" + "\n") for host in scripting_hosts: self.add_text(host + "\n") ip_port = scripting_hosts[0].split()[0] self.add_text("> connect " + ip_port + "\n") self.connect_handler(ip_port)
def init(lib=None, samplerate=22050, channels=2, buffersize=2048, reinit=False): """ (Re-)Initialize sound subsystem """ # Note on buffer size: Too high values cause crackling during fade, too low # values cause choppy playback of ogg files when using pyo (good value for # pyo is >= 2048) global _initialized, _lib, _lib_version, _server, pyglet, pyo, sdl, wx if _initialized and not reinit: # To re-initialize, explicitly set reinit to True return # Select the audio library we're going to use. # User choice or SDL > pyglet > pyo > wx if not lib: if sys.platform in ("darwin", "win32"): # Mac OS X, Windows libs = ("pyglet", "SDL", "pyo", "wx") else: # Linux libs = ("SDL", "pyglet", "pyo", "wx") for lib in libs: try: return init(lib, samplerate, channels, buffersize, reinit) except Exception as exception: pass raise exception elif lib == "pyglet": if not getattr(sys, "frozen", False): # Use included pyglet lib_dir = os.path.join(os.path.dirname(__file__), "lib") if not lib_dir in sys.path: sys.path.insert(0, lib_dir) try: import pyglet version = [] for item in pyglet.version.split("."): try: version.append(int(item)) except ValueError: version.append(item) if version < [1, 2, 2]: raise ImportError("pyglet version %s is too old" % pyglet.version) _lib = "pyglet" except ImportError: _lib = None else: # Work around localization preventing fallback to RIFFSourceLoader pyglet.lib.LibraryLoader.darwin_not_found_error = "" pyglet.lib.LibraryLoader.linux_not_found_error = "" # Set audio driver preference pyglet.options["audio"] = ("pulse", "openal", "directsound", "silent") _server = pyglet.media _lib_version = pyglet.version elif lib == "pyo": try: import pyo _lib = "pyo" except ImportError: _lib = None else: if isinstance(_server, pyo.Server): _server.reinit(sr=samplerate, nchnls=channels, buffersize=buffersize, duplex=0) else: _server = pyo.Server(sr=samplerate, nchnls=channels, buffersize=buffersize, duplex=0, winhost="asio").boot() _server.start() _lib_version = ".".join(str(v) for v in pyo.getVersion()) elif lib == "SDL": SDL_INIT_AUDIO = 16 AUDIO_S16LSB = 0x8010 AUDIO_S16MSB = 0x9010 if sys.byteorder == "little": MIX_DEFAULT_FORMAT = AUDIO_S16LSB else: MIX_DEFAULT_FORMAT = AUDIO_S16MSB if sys.platform == "win32": pth = getenvu("PATH") libpth = os.path.join(pydir, "lib") if not pth.startswith(libpth + os.pathsep): pth = libpth + os.pathsep + pth os.environ["PATH"] = safe_str(pth) elif sys.platform == "darwin": x_framework_pth = os.getenv("X_DYLD_FALLBACK_FRAMEWORK_PATH") if x_framework_pth: framework_pth = os.getenv("DYLD_FALLBACK_FRAMEWORK_PATH") if framework_pth: x_framework_pth = os.pathsep.join( [x_framework_pth, framework_pth]) os.environ["DYLD_FALLBACK_FRAMEWORK_PATH"] = x_framework_pth for libname in ("SDL2", "SDL2_mixer", "SDL", "SDL_mixer"): handle = None if sys.platform in ("darwin", "win32"): libfn = ctypes.util.find_library(libname) if sys.platform == "win32": if libfn and win32api: # Support for unicode paths libfn = safe_unicode(libfn) try: handle = win32api.LoadLibrary(libfn) except pywintypes.error: pass elif sys.platform != "darwin": # Hard-code lib names for Linux libfn = "lib" + libname if libname.startswith("SDL2"): # SDL 2.0 libfn += "-2.0.so.0" else: # SDL 1.2 libfn += "-1.2.so.0" dll = dlopen(libfn, handle=handle) if dll: safe_print("%s:" % libname, libfn) if libname.endswith("_mixer"): if not dll: continue if not sdl: raise RuntimeError("SDL library not loaded") sdl.SDL_RWFromFile.restype = POINTER(SDL_RWops) _server = dll _server.Mix_OpenAudio.argtypes = [ c_int, c_uint16, c_int, c_int ] _server.Mix_LoadWAV_RW.argtypes = [POINTER(SDL_RWops), c_int] _server.Mix_LoadWAV_RW.restype = POINTER(Mix_Chunk) _server.Mix_PlayChannelTimed.argtypes = [ c_int, POINTER(Mix_Chunk), c_int, c_int ] _server.Mix_VolumeChunk.argtypes = [POINTER(Mix_Chunk), c_int] if _initialized: _server.Mix_Quit() sdl.SDL_Quit() sdl.SDL_Init(SDL_INIT_AUDIO) _server.Mix_OpenAudio(samplerate, MIX_DEFAULT_FORMAT, channels, buffersize) _lib = "SDL" if libname.startswith("SDL2"): _lib_version = "2.0" else: _lib_version = "1.2" break else: sdl = dll _server = None elif lib == "wx": try: import wx _lib = "wx" except ImportError: _lib = None else: _server = wx _lib_version = wx.__version__ if not _lib: raise RuntimeError("No audio library available") _initialized = True return _server
def get_default_size(): """ Get and return the default size for the window in pixels. The default size is always equivalent to 100 x 100 mm according to the display's size as returned by the RealDisplaySizeMM function, which uses the same code as Argyll to determine that size. This function is used internally. """ display_sizes = [] display_sizes_mm = [] for display_no in range(len(getcfg("displays"))): display_no = get_display_number(display_no) display_size = wx.Display(display_no).Geometry[2:] display_size_mm = [] if RDSMM: try: display_size_mm = RDSMM.RealDisplaySizeMM(display_no) except Exception as exception: handle_error("Error - RealDisplaySizeMM() failed: " + safe_unicode(exception), silent=True) else: display_size_mm = floatlist(display_size_mm) if debug: safe_print("[D] display_size_mm:", display_size_mm) if not len(display_size_mm) or 0 in display_size_mm: ppi_def = get_default_dpi() method = 1 if method == 0: # use configurable screen diagonal inch = 20.0 mm = inch * 25.4 f = mm / math.sqrt(math.pow(display_size[0], 2) + \ math.pow(display_size[1], 2)) w_mm = math.sqrt(math.pow(mm, 2) - \ math.pow(display_size[1] * f, 2)) h_mm = math.sqrt(math.pow(mm, 2) - \ math.pow(display_size[0] * f, 2)) display_size_mm = w_mm, h_mm elif method == 1: # use the first display display_size_1st = wx.DisplaySize() display_size_mm = floatlist(wx.DisplaySizeMM()) if 0 in display_size_mm: # bogus display_size_mm = [ display_size_1st[0] / ppi_def * 25.4, display_size_1st[1] / ppi_def * 25.4 ] if display_no > 0: display_size_mm[0] = display_size[0] / ( display_size_1st[0] / display_size_mm[0]) display_size_mm[1] = display_size[1] / ( display_size_1st[1] / display_size_mm[1]) else: # use assumed ppi display_size_mm = (display_size[0] / ppi_def * 25.4, display_size[1] / ppi_def * 25.4) display_sizes.append(display_size) display_sizes_mm.append(display_size_mm) if sum(mm[0] for mm in display_sizes_mm) / \ len(display_sizes_mm) == display_sizes_mm[0][0] and \ sum(mm[1] for mm in display_sizes_mm) / \ len(display_sizes_mm) == display_sizes_mm[0][1]: # display_size_mm is the same for all screens, use the 1st one display_size = display_sizes[0] display_size_mm = display_sizes_mm[0] else: if getcfg("display_lut.link"): display_no = getcfg("display.number") - 1 else: display_no = getcfg("display_lut.number") - 1 display_size = display_sizes[display_no] display_size_mm = display_sizes_mm[display_no] px_per_mm = (display_size[0] / display_size_mm[0], display_size[1] / display_size_mm[1]) if debug: safe_print("[D] H px_per_mm:", px_per_mm[0]) safe_print("[D] V px_per_mm:", px_per_mm[1]) return round(100.0 * max(px_per_mm))
def handle_error(error, parent=None, silent=False, tb=True): """ Log an error string and show an error dialog. """ if isinstance(error, tuple): # We got a tuple. Assume (etype, value, tb) tbstr = "".join(traceback.format_exception(*error)) error = error[1] else: tbstr = traceback.format_exc() if (tb and tbstr.strip() != "None" and isinstance(error, Exception) and (debug or not isinstance(error, EnvironmentError) or not getattr(error, "filename", None))): # Print a traceback if in debug mode, for non environment errors, and # for environment errors not related to files errstr, tbstr = (safe_unicode(v) for v in (error, tbstr)) msg = "\n\n".join((errstr, tbstr)) if msg.startswith(errstr): safe_print(box(tbstr)) else: safe_print(box(msg)) else: msg = safe_unicode(error) safe_print(box(msg)) if not silent: try: from wxaddons import wx if wx.VERSION < wx_recversion: msg += ( "\n\nWARNING: Your version of wxPython (%s) is outdated " "and no longer supported. You should consider updating " "to wxPython %s or newer." % (wx.__version__, ".".join(str(n) for n in wx_recversion))) app = wx.GetApp() if app is None and parent is None: app = wx.App(redirect=False) # wxPython 3 bugfix: We also need a toplevel window frame = wx.Frame(None) parent = False else: frame = None if parent is None: parent = wx.GetActiveWindow() if parent: try: parent.IsShownOnScreen() except: # If the parent is still being constructed, we can't use it parent = None icon = wx.ICON_INFORMATION if not isinstance(error, Info): if isinstance(error, Warning): icon = wx.ICON_WARNING elif isinstance(error, Exception): icon = wx.ICON_ERROR dlg = wx.MessageDialog( parent if parent not in (False, None) and parent.IsShownOnScreen() else None, msg, app.AppName, wx.OK | icon) if frame: # wxPython 3 bugfix: We need to use CallLater and MainLoop wx.CallLater(1, dlg.ShowModal) wx.CallLater(1, frame.Close) app.MainLoop() else: dlg.ShowModal() dlg.Destroy() except Exception as exception: safe_print("Warning: handle_error():", safe_unicode(exception))
if sys.platform == "win32": os.makedirs(config_sys) else: result = worker.exec_cmd("mkdir", ["-p", config_sys], capture_output=True, low_contrast=False, skip_scripts=True, silent=True, asroot=True) if isinstance(result, Exception): raise result except Exception, exception: from debughelpers import handle_error handle_error(u"Warning - could not create configuration directory " "'%s': %s" % (config_sys, safe_unicode(exception))) return False return True def initcfg(): """ Initialize the configuration. Read in settings if the configuration file exists, else create the settings directory if nonexistent. """ # read pre-v0.2.2b configuration if present if sys.platform == "darwin": oldcfg = os.path.join(expanduseru("~"), "Library", "Preferences",
def vrmlfile2x3dfile(vrmlpath=None, x3dpath=None, html=True, embed=False, view=False, force=False, cache=True, worker=None, gui=True): """ Convert VRML to HTML. Output is written to <vrmlfilename>.x3d.html unless you set x3dpath to desired output path, or False to be prompted for an output path. """ while not vrmlpath or not os.path.isfile(vrmlpath): if not gui: if not vrmlpath or vrmlpath.startswith("--"): safe_print("No filename given.") else: safe_print("%r is not a file." % vrmlpath) return False if not wx.GetApp(): app = BaseApp(0) defaultDir, defaultFile = config.get_verified_path("last_vrml_path") dlg = wx.FileDialog(None, lang.getstr("file.select"), defaultDir=defaultDir, defaultFile=defaultFile, wildcard=lang.getstr("filetype.vrml") + "|*.vrml;*.vrml.gz;*.wrl.gz;*.wrl;*.wrz", style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) dlg.Center(wx.BOTH) result = dlg.ShowModal() vrmlpath = dlg.GetPath() dlg.Destroy() if result != wx.ID_OK: return config.setcfg("last_vrml_path", vrmlpath) config.writecfg(module="VRML-to-X3D-converter", options=("last_vrml_path", )) filename, ext = os.path.splitext(vrmlpath) if x3dpath is None: x3dpath = filename + ".x3d" if x3dpath: dirname = os.path.dirname(x3dpath) while not x3dpath or not waccess(dirname, os.W_OK): if not gui: if not x3dpath: safe_print("No HTML output filename given.") else: safe_print("%r is not writable." % dirname) return False if not wx.GetApp(): app = BaseApp(0) if x3dpath: defaultDir, defaultFile = os.path.split(x3dpath) else: defaultFile = os.path.basename(filename) + ".x3d" dlg = wx.FileDialog(None, lang.getstr("error.access_denied.write", dirname), defaultDir=defaultDir, defaultFile=defaultFile, wildcard=lang.getstr("filetype.x3d") + "|*.x3d", style=wx.SAVE | wx.FD_OVERWRITE_PROMPT) dlg.Center(wx.BOTH) result = dlg.ShowModal() dlg.Destroy() if result != wx.ID_OK: return x3dpath = dlg.GetPath() dirname = os.path.dirname(x3dpath) vrmlpath, x3dpath = [safe_unicode(path) for path in (vrmlpath, x3dpath)] if sys.platform == "win32": vrmlpath = make_win32_compatible_long_path(vrmlpath) x3dpath = make_win32_compatible_long_path(x3dpath) if html: finalpath = x3dpath + ".html" if sys.platform == "win32": finalpath = make_win32_compatible_long_path(finalpath) x3dpath = finalpath[:-5] else: finalpath = x3dpath if worker: worker.clear_cmd_output() worker.start( lambda result: show_result_dialog(result, wx.GetApp().GetTopWindow()) if isinstance(result, Exception ) else result and view and launch_file(finalpath), x3dom.vrmlfile2x3dfile, wargs=(vrmlpath, x3dpath, html, embed, force, cache, worker), progress_title=lang.getstr("vrml_to_x3d_converter"), progress_start=1, resume=worker.progress_wnd and worker.progress_wnd.IsShownOnScreen(), fancy=False) else: result = x3dom.vrmlfile2x3dfile(vrmlpath, x3dpath, html, embed, force, cache, None) if not isinstance(result, Exception) and result: if view: launch_file(finalpath) else: return False return True
def _main(module, name, applockfilename, probe_ports=True): # Allow multiple instances only for curve viewer, profile info, # scripting client, synthetic profile creator and testchart editor multi_instance = ("curve-viewer", "profile-info", "scripting-client", "synthprofile", "testchart-editor") lock = AppLock(applockfilename, "a+", True, module in multi_instance) if not lock: # If a race condition occurs, do not start another instance safe_print("Not starting another instance.") return log("=" * 80) if verbose >= 1: version = VERSION_STRING if VERSION > VERSION_BASE: version += " Beta" safe_print(pyname + runtype, version, build) if sys.platform == "darwin": # Python's platform.platform output is useless under Mac OS X # (e.g. 'Darwin-15.0.0-x86_64-i386-64bit' for Mac OS X 10.11 El Capitan) safe_print("Mac OS X %s %s" % (mac_ver()[0], mac_ver()[-1])) elif sys.platform == "win32": machine = platform.machine() safe_print(*[v for v in win_ver() if v] + ({ "AMD64": "x86_64" }.get(machine, machine), )) else: # Linux safe_print(' '.join(platform.dist()), platform.machine()) safe_print("Python " + sys.version) cafile = os.getenv("SSL_CERT_FILE") if cafile: safe_print("CA file", cafile) # Enable faulthandler try: import faulthandler except Exception as exception: safe_print(exception) else: try: faulthandler.enable( open(os.path.join(logdir, pyname + "-fault.log"), "w")) except Exception as exception: safe_print(exception) else: safe_print("Faulthandler", getattr(faulthandler, "__version__", "")) from wxaddons import wx if "phoenix" in wx.PlatformInfo: # py2exe helper so wx.xml gets picked up from wx import xml safe_print("wxPython " + wx.version()) safe_print("Encoding: " + enc) safe_print("File system encoding: " + fs_enc) if sys.platform == "win32" and sys.getwindowsversion() >= (6, 2): # HighDPI support try: shcore = ctypes.windll.shcore except Exception as exception: safe_print("Warning - could not load shcore:", exception) else: if hasattr(shcore, "SetProcessDpiAwareness"): try: # 1 = System DPI aware (wxWpython currently does not # support per-monitor DPI) shcore.SetProcessDpiAwareness(1) except Exception as exception: safe_print("Warning - SetProcessDpiAwareness() failed:", exception) else: safe_print( "Warning - SetProcessDpiAwareness not found in shcore") initcfg(module) host = "127.0.0.1" defaultport = getcfg("app.port") lock2pids_ports = {} opid = os.getpid() if probe_ports: # Check for currently used ports lockfilenames = glob.glob(os.path.join(confighome, "*.lock")) for lockfilename in lockfilenames: safe_print("Lockfile", lockfilename) try: if lock and lockfilename == applockfilename: lockfile = lock lock.seek(0) else: lockfile = AppLock(lockfilename, "r", True, True) if lockfile: if not lockfilename in lock2pids_ports: lock2pids_ports[lockfilename] = [] for ln, line in enumerate(lockfile.read().splitlines(), 1): if ":" in line: # DisplayCAL >= 3.8.8.2 with localhost blocked pid, port = line.split(":", 1) if pid: try: pid = int(pid) except ValueError as exception: # This shouldn't happen safe_print("Warning - couldn't parse PID " "as int: %r (%s line %i)" % (pid, lockfilename, ln)) pid = None else: safe_print("Existing client using PID", pid) else: # DisplayCAL <= 3.8.8.1 or localhost ok pid = None port = line if port: try: port = int(port) except ValueError as exception: # This shouldn't happen safe_print( "Warning - couldn't parse port as int: %r " "(%s line %i)" % (port, lockfilename, ln)) port = None else: safe_print("Existing client using port", port) if pid or port: lock2pids_ports[lockfilename].append((pid, port)) if not lock or lockfilename != applockfilename: lockfile.unlock() except EnvironmentError as exception: # This shouldn't happen safe_print( "Warning - could not read lockfile %s:" % lockfilename, exception) if module not in multi_instance: # Check lockfile(s) and probe port(s) for lockfilename in [applockfilename]: incoming = None pids_ports = lock2pids_ports.get(lockfilename) if pids_ports: pid, port = pids_ports[0] appsocket = AppSocket() if appsocket and port: safe_print("Connecting to %s..." % port) if appsocket.connect(host, port): safe_print("Connected to", port) # Other instance already running? # Get appname to check if expected app is actually # running under that port safe_print("Getting instance name") if appsocket.send("getappname"): safe_print( "Sent scripting request, awaiting response..." ) incoming = appsocket.read().rstrip("\4") safe_print("Got response: %r" % incoming) if incoming: if incoming != pyname: incoming = None else: incoming = False while incoming: # Send args as UTF-8 if module == "apply-profiles": # Always try to close currently running instance safe_print("Closing existing instance") cmd = "exit" if incoming == pyname else "close" data = [cmd] lock.unlock() else: # Send module/appname to notify running app safe_print("Notifying existing instance") data = [module or appname] if module != "3DLUT-maker": for arg in sys.argv[1:]: data.append( safe_str(safe_unicode(arg), "UTF-8")) data = sp.list2cmdline(data) if appsocket.send(data): safe_print( "Sent scripting request, awaiting response..." ) incoming = appsocket.read().rstrip("\4") safe_print("Got response: %r" % incoming) if module == "apply-profiles": if incoming == "": # Successfully sent our close request. incoming = "ok" elif incoming == "invalid" and cmd == "exit": # < 3.8.8.1 didn't have exit command continue break appsocket.close() else: pid = None if not incoming: if sys.platform == "win32": import pywintypes import win32ts try: osid = win32ts.ProcessIdToSessionId(opid) except pywintypes.error as exception: safe_print("Enumerating processes failed:", exception) osid = None try: processes = win32ts.WTSEnumerateProcesses() except pywintypes.error as exception: safe_print("Enumerating processes failed:", exception) else: appname_lower = appname.lower() exename_lower = exename.lower() if module: pyexe_lower = appname_lower + "-" + module + exe_ext else: pyexe_lower = appname_lower + exe_ext incoming = None for (sid, pid2, basename, usid) in processes: basename_lower = basename.lower() if ((pid and pid2 == pid and basename_lower == exename_lower) or ((osid is None or sid == osid) and basename_lower == pyexe_lower)) and pid2 != opid: # Other instance running incoming = False if module == "apply-profiles": if not os.path.isfile(lockfilename): # Create dummy lockfile try: with open(lockfilename, "w"): pass except EnvironmentError as exception: safe_print( "Warning - could " "not create dummy " "lockfile %s: %r" % (lockfilename, exception)) else: safe_print( "Warning - had to " "create dummy " "lockfile", lockfilename) safe_print( "Closing existing instance " "with PID", pid2) startupinfo = sp.STARTUPINFO() startupinfo.dwFlags |= sp.STARTF_USESHOWWINDOW startupinfo.wShowWindow = sp.SW_HIDE lock.unlock() try: p = sp.Popen( [ "taskkill", "/PID", "%s" % pid2 ], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.STDOUT, startupinfo=startupinfo) stdout, stderr = p.communicate() except Exception as exception: safe_print(exception) else: safe_print(stdout) if not p.returncode: # Successfully sent our close # request. incoming = "ok" if incoming == "ok": # Successfully sent our request if module == "apply-profiles": # Wait for lockfile to be removed, in which case # we know the running instance has successfully # closed. safe_print( "Waiting for existing instance to exit and " "delete lockfile", lockfilename) while os.path.isfile(lockfilename): sleep(.05) lock.lock() safe_print("Existing instance exited.") incoming = None if lockfilename in lock2pids_ports: del lock2pids_ports[lockfilename] break if incoming is not None: # Other instance running? import localization as lang lang.init() if incoming == "ok": # Successfully sent our request safe_print(lang.getstr("app.otherinstance.notified")) elif module == "apply-profiles": safe_print("Not starting another instance.") else: # Other instance busy? handle_error(lang.getstr("app.otherinstance", name)) # Exit return # Use exclusive lock during app startup with lock: # Create listening socket appsocket = AppSocket() if appsocket: if sys.platform != "win32": # https://docs.microsoft.com/de-de/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse#using-so_reuseaddr # From the above link: "The SO_REUSEADDR socket option allows # a socket to forcibly bind to a port in use by another socket". # Note that this is different from the behavior under Linux/BSD, # where a socket can only be (re-)bound if no active listening # socket is already bound to the address. # Consequently, we don't use SO_REUSEADDR under Windows. appsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sys._appsocket = appsocket.socket if getcfg("app.allow_network_clients"): host = "" used_ports = [ pid_port[1] for pids_ports in list(lock2pids_ports.values()) for pid_port in pids_ports ] candidate_ports = [0] if not defaultport in used_ports: candidate_ports.insert(0, defaultport) for port in candidate_ports: try: sys._appsocket.bind((host, port)) except socket.error as exception: if port == 0: safe_print( "Warning - could not bind to %s:%s:" % (host, port), exception) del sys._appsocket break else: try: sys._appsocket.settimeout(.2) except socket.error as exception: safe_print( "Warning - could not set socket " "timeout:", exception) del sys._appsocket break try: sys._appsocket.listen(1) except socket.error as exception: safe_print("Warning - could not listen on " "socket:", exception) del sys._appsocket break try: port = sys._appsocket.getsockname()[1] except socket.error as exception: safe_print( "Warning - could not get socket " "address:", exception) del sys._appsocket break sys._appsocket_port = port break if not hasattr(sys, "_appsocket_port"): port = "" lock.seek(0) if module not in multi_instance: lock.truncate(0) if not port: lock.write("%s:%s" % (opid, port)) else: lock.write(port) atexit.register(lambda: safe_print("Ran application exit handlers")) from wxwindows import BaseApp BaseApp.register_exitfunc(_exit, applockfilename, port) # Check for required resource files mod2res = { "3DLUT-maker": ["xrc/3dlut.xrc"], "curve-viewer": [], "profile-info": [], "scripting-client": [], "synthprofile": ["xrc/synthicc.xrc"], "testchart-editor": [], "VRML-to-X3D-converter": [] } for filename in mod2res.get(module, resfiles): path = get_data_path(os.path.sep.join(filename.split("/"))) if not path or not os.path.isfile(path): import localization as lang lang.init() raise ResourceError( lang.getstr("resources.notfound.error") + "\n" + filename) # Create main data dir if it does not exist if not os.path.exists(datahome): try: os.makedirs(datahome) except Exception as exception: handle_error( UserWarning("Warning - could not create " "directory '%s'" % datahome)) elif sys.platform == "darwin": # Check & fix permissions if necessary import getpass user = getpass.getuser().decode(fs_enc) script = [] for directory in (confighome, datahome, logdir): if (os.path.isdir(directory) and not os.access(directory, os.W_OK)): script.append("chown -R '%s' '%s'" % (user, directory)) if script: sp.call([ 'osascript', '-e', 'do shell script "%s" with administrator privileges' % ";".join(script).encode(fs_enc) ]) # Initialize & run if module == "3DLUT-maker": from wxLUT3DFrame import main elif module == "curve-viewer": from wxLUTViewer import main elif module == "profile-info": from wxProfileInfo import main elif module == "scripting-client": from wxScriptingClient import main elif module == "synthprofile": from wxSynthICCFrame import main elif module == "testchart-editor": from wxTestchartEditor import main elif module == "VRML-to-X3D-converter": from wxVRML2X3D import main elif module == "apply-profiles": from profile_loader import main else: from DisplayCAL import main # Run main after releasing lock main()
def get_file_logger(name, level=loglevel, when="midnight", backupCount=5, logdir=None, filename=None, confighome=None): """ Return logger object. A TimedRotatingFileHandler or FileHandler (if when == "never") will be used. """ global _logdir if logdir is None: logdir = _logdir logger = logging.getLogger(name) if not filename: filename = name mode = "a" if confighome: # Use different logfile name (append number) for each additional # instance is_main_process = mp.current_process().name == "MainProcess" if os.path.basename(confighome).lower() == "dispcalgui": lockbasename = filename.replace(appname, "dispcalGUI") else: lockbasename = filename lockfilepath = os.path.join(confighome, lockbasename + ".lock") if os.path.isfile(lockfilepath): try: with open(lockfilepath, "r") as lockfile: instances = len(lockfile.read().splitlines()) except: pass else: if not is_main_process: # Running as child from multiprocessing under Windows instances -= 1 if instances: filenames = [filename] filename += ".%i" % instances filenames.append(filename) if filenames[0].endswith("-apply-profiles"): # Running the profile loader always sends a close # request to an already running instance, so there # will be at most two logfiles, and we want to use # the one not currently in use. mtimes = {} for filename in filenames: logfile = os.path.join(logdir, filename + ".log") if not os.path.isfile(logfile): mtimes[0] = filename continue try: logstat = os.stat(logfile) except Exception as exception: safe_print( "Warning - os.stat('%s') failed: %s" % tuple( safe_unicode(s) for s in (logfile, exception))) else: mtimes[logstat.st_mtime] = filename if mtimes: filename = mtimes[sorted(mtimes.keys())[0]] if is_main_process: for lockfilepath in safe_glob( os.path.join(confighome, lockbasename + ".mp-worker-*.lock")): try: os.remove(lockfilepath) except: pass else: # Running as child from multiprocessing under Windows lockbasename += ".mp-worker-" process_num = 1 while os.path.isfile( os.path.join(confighome, lockbasename + "%i.lock" % process_num)): process_num += 1 lockfilepath = os.path.join(confighome, lockbasename + "%i.lock" % process_num) try: with open(lockfilepath, "w") as lockfile: pass except: pass else: atexit.register(os.remove, lockfilepath) when = "never" filename += ".mp-worker-%i" % process_num mode = "w" logfile = os.path.join(logdir, filename + ".log") for handler in logger.handlers: if (isinstance(handler, logging.FileHandler) and handler.baseFilename == os.path.abspath(logfile)): return logger logger.propagate = 0 logger.setLevel(level) if not os.path.exists(logdir): try: os.makedirs(logdir) except Exception as exception: safe_print( "Warning - log directory '%s' could not be created: %s" % tuple(safe_unicode(s) for s in (logdir, exception))) elif when != "never" and os.path.exists(logfile): try: logstat = os.stat(logfile) except Exception as exception: safe_print("Warning - os.stat('%s') failed: %s" % tuple(safe_unicode(s) for s in (logfile, exception))) else: # rollover needed? t = logstat.st_mtime try: mtime = localtime(t) except ValueError as exception: # This can happen on Windows because localtime() is buggy on # that platform. See: # http://stackoverflow.com/questions/4434629/zipfile-module-in-python-runtime-problems # http://bugs.python.org/issue1760357 # To overcome this problem, we ignore the real modification # date and force a rollover t = time() - 60 * 60 * 24 mtime = localtime(t) # Deal with DST now = localtime() dstNow = now[-1] dstThen = mtime[-1] if dstNow != dstThen: if dstNow: addend = 3600 else: addend = -3600 mtime = localtime(t + addend) if now[:3] > mtime[:3]: # do rollover logbackup = logfile + strftime(".%Y-%m-%d", mtime) if os.path.exists(logbackup): try: os.remove(logbackup) except Exception as exception: safe_print("Warning - logfile backup '%s' could not " "be removed during rollover: %s" % tuple( safe_unicode(s) for s in (logbackup, exception))) try: os.rename(logfile, logbackup) except Exception as exception: safe_print( "Warning - logfile '%s' could not be renamed " "to '%s' during rollover: %s" % tuple( safe_unicode(s) for s in (logfile, os.path.basename(logbackup), exception))) # Adapted from Python 2.6's # logging.handlers.TimedRotatingFileHandler.getFilesToDelete extMatch = re.compile(r"^\d{4}-\d{2}-\d{2}$") baseName = os.path.basename(logfile) try: fileNames = os.listdir(logdir) except Exception as exception: safe_print( "Warning - log directory '%s' listing failed " "during rollover: %s" % tuple(safe_unicode(s) for s in (logdir, exception))) else: result = [] prefix = baseName + "." plen = len(prefix) for fileName in fileNames: if fileName[:plen] == prefix: suffix = fileName[plen:] if extMatch.match(suffix): result.append(os.path.join(logdir, fileName)) result.sort() if len(result) > backupCount: for logbackup in result[:len(result) - backupCount]: try: os.remove(logbackup) except Exception as exception: safe_print( "Warning - logfile backup '%s' " "could not be removed during " "rollover: %s" % tuple( safe_unicode(s) for s in (logbackup, exception))) if os.path.exists(logdir): try: if when != "never": filehandler = logging.handlers.TimedRotatingFileHandler( logfile, when=when, backupCount=backupCount) else: filehandler = logging.FileHandler(logfile, mode) fileformatter = logging.Formatter("%(asctime)s %(message)s") filehandler.setFormatter(fileformatter) logger.addHandler(filehandler) except Exception as exception: safe_print("Warning - logging to file '%s' not possible: %s" % tuple(safe_unicode(s) for s in (logfile, exception))) return logger