def safe_format(self, fmt, kwargs, error_value, book, column_name=None, template_cache=None, strip_results=True, template_functions=None, global_vars=None, break_reporter=None): self.strip_results = strip_results self.column_name = column_name self.template_cache = template_cache self.kwargs = kwargs self.book = book self.global_vars = global_vars if isinstance(global_vars, dict) else {} if template_functions: self.funcs = template_functions else: self.funcs = formatter_functions().get_functions() self.composite_values = {} self.locals = {} try: ans = self.evaluate(fmt, [], kwargs, self.global_vars, break_reporter=break_reporter) except StopException as e: ans = error_message(e) except Exception as e: if DEBUG: # and getattr(e, 'is_locking_error', False): traceback.print_exc() if column_name: prints('Error evaluating column named:', column_name) ans = error_value + ' ' + error_message(e) return ans
def main(args=sys.argv): import argparse ver = compiler().g.exports.rs_version parser = argparse.ArgumentParser(prog='pyj', description='RapydScript compiler and REPL. If passed input on stdin, it is compiled and written to stdout. Otherwise a REPL is started.') parser.add_argument('--version', action='version', version='Using RapydScript compiler version: '+ver) parser.add_argument('--show-js', action='store_true', help='Have the REPL output the compiled javascript before executing it') parser.add_argument('--libdir', help='Where to look for imported modules') parser.add_argument('--omit-baselib', action='store_true', default=False, help='Omit the RapydScript base library') parser.add_argument('--no-private-scope', action='store_true', default=False, help='Do not wrap the output in its own private scope') args = parser.parse_args(args) libdir = os.path.expanduser(args.libdir) if args.libdir else None if sys.stdin.isatty(): Repl(show_js=args.show_js, libdir=libdir)() else: try: enc = getattr(sys.stdin, 'encoding', 'utf-8') or 'utf-8' data = compile_pyj(sys.stdin.read().decode(enc), libdir=libdir, private_scope=not args.no_private_scope, omit_baselib=args.omit_baselib) print(data.encode(enc)) except JSError as e: raise SystemExit(error_message(e)) except CompileFailure as e: raise SystemExit(error_message(e))
def parse_request_line(self, buf, event, first=False): # {{{ line = self.readline(buf) if line is None: return self.request_line = line.rstrip() if line == b'\r\n': # Ignore a single leading empty line, as per RFC 2616 sec 4.1 if first: return self.set_state(READ, self.parse_request_line, Accumulator()) return self.simple_response(http_client.BAD_REQUEST, 'Multiple leading empty lines not allowed') try: method, uri, req_protocol = line.strip().split(b' ', 2) req_protocol = req_protocol.decode('ascii') rp = int(req_protocol[5]), int(req_protocol[7]) self.method = method.decode('ascii').upper() except Exception: return self.simple_response(http_client.BAD_REQUEST, "Malformed Request-Line") if self.method not in HTTP_METHODS: return self.simple_response(http_client.BAD_REQUEST, "Unknown HTTP method") try: self.request_protocol = protocol_map[rp] except KeyError: return self.simple_response(http_client.HTTP_VERSION_NOT_SUPPORTED) self.response_protocol = protocol_map[min((1, 1), rp)] try: self.scheme, self.path, self.query = parse_uri(uri) except HTTPSimpleResponse as e: return self.simple_response(e.http_code, error_message(e), close_after_response=False) self.header_line_too_long_error_code = http_client.REQUEST_ENTITY_TOO_LARGE self.set_state(READ, self.parse_header_line, HTTPHeaderParser(), Accumulator())
def run_text_search(search, current_editor, current_editor_name, searchable_names, gui_parent, show_editor, edit_file): try: pat = get_search_regex(search) except InvalidRegex as e: return error_dialog(gui_parent, _('Invalid regex'), '<p>' + _( 'The regular expression you entered is invalid: <pre>{0}</pre>With error: {1}').format( prepare_string_for_xml(e.regex), error_message(e)), show=True) editor, where, files, do_all, marked = initialize_search_request(search, 'count', current_editor, current_editor_name, searchable_names) with BusyCursor(): if editor is not None: if editor.find_text(pat): return True if not files and editor.find_text(pat, wrap=True): return True for fname, syntax in iteritems(files): ed = editors.get(fname, None) if ed is not None: if ed.find_text(pat, complete=True): show_editor(fname) return True else: root = current_container().parsed(fname) if hasattr(root, 'xpath'): raw = tostring(root, method='text', encoding='unicode', with_tail=True) else: raw = current_container().raw_data(fname) if pat.search(raw) is not None: edit_file(fname, syntax) if editors[fname].find_text(pat, complete=True): return True msg = '<p>' + _('No matches were found for %s') % ('<pre style="font-style:italic">' + prepare_string_for_xml(search['find']) + '</pre>') return error_dialog(gui_parent, _('Not found'), msg, show=True)
def run_importer(): export_dir = input_unicode( 'Enter path to folder containing previously exported data: ').rstrip( '\r') if not os.path.isdir(export_dir): raise SystemExit('%s is not a folder' % export_dir) try: importer = Importer(export_dir) except ValueError as err: raise SystemExit(error_message(err)) import_dir = input_unicode( 'Enter path to an empty folder (all libraries will be created inside this folder): ' ).rstrip('\r') if not os.path.exists(import_dir): os.makedirs(import_dir) if not os.path.isdir(import_dir): raise SystemExit('%s is not a folder' % import_dir) if os.listdir(import_dir): raise SystemExit('%s is not empty' % import_dir) import_data(importer, { k: os.path.join(import_dir, os.path.basename(k)) for k in importer.metadata['libraries'] }, progress1=cli_report, progress2=cli_report)
def restart(self, forced=False): from calibre.utils.rapydscript import CompileFailure, compile_srv self.clean_kill() if forced: self.retry_count += 1 else: self.retry_count = 0 try: compile_srv() except OSError as e: # Happens if the editor deletes and replaces a file being edited if e.errno != errno.ENOENT or not getattr(e, 'filename', False): raise st = monotonic() while not os.path.exists(e.filename) and monotonic() - st < 3: time.sleep(0.01) compile_srv() except CompileFailure as e: self.log.error(error_message(e)) time.sleep(0.1 * self.retry_count) if self.retry_count < MAX_RETRIES and self.wakeup is not None: self.wakeup() # Force a restart return self.retry_count = 0 self.p = subprocess.Popen(self.cmd, creationflags=getattr( subprocess, 'CREATE_NEW_PROCESS_GROUP', 0)) self.wait_for_listen() self.server.notify_reload()
def restart(self, forced=False): from calibre.utils.rapydscript import compile_srv, CompileFailure self.clean_kill() if forced: self.retry_count += 1 else: self.retry_count = 0 try: compile_srv() except EnvironmentError as e: # Happens if the editor deletes and replaces a file being edited if e.errno != errno.ENOENT or not getattr(e, 'filename', False): raise st = monotonic() while not os.path.exists(e.filename) and monotonic() - st < 3: time.sleep(0.01) compile_srv() except CompileFailure as e: self.log.error(error_message(e)) time.sleep(0.1 * self.retry_count) if self.retry_count < MAX_RETRIES and self.wakeup is not None: self.wakeup() # Force a restart return self.retry_count = 0 self.p = subprocess.Popen(self.cmd, creationflags=getattr(subprocess, 'CREATE_NEW_PROCESS_GROUP', 0)) self.wait_for_listen() self.server.notify_reload()
def parse_request_line(self, buf, event, first=False): # {{{ line = self.readline(buf) if line is None: return self.request_line = line.rstrip() if line == b'\r\n': # Ignore a single leading empty line, as per RFC 2616 sec 4.1 if first: return self.set_state(READ, self.parse_request_line, Accumulator()) return self.simple_response(http_client.BAD_REQUEST, 'Multiple leading empty lines not allowed') try: method, uri, req_protocol = line.strip().split(b' ', 2) req_protocol = req_protocol.decode('ascii') rp = int(req_protocol[5]), int(req_protocol[7]) self.method = method.decode('ascii').upper() except Exception: return self.simple_response(http_client.BAD_REQUEST, "Malformed Request-Line") if self.method not in HTTP_METHODS: return self.simple_response(http_client.BAD_REQUEST, "Unknown HTTP method") try: self.request_protocol = protocol_map[rp] except KeyError: return self.simple_response(http_client.HTTP_VERSION_NOT_SUPPORTED) self.response_protocol = protocol_map[min((1, 1), rp)] self.request_original_uri = uri try: self.scheme, self.path, self.query = parse_uri(uri) except HTTPSimpleResponse as e: return self.simple_response(e.http_code, error_message(e), close_after_response=False) self.header_line_too_long_error_code = http_client.REQUEST_ENTITY_TOO_LARGE self.set_state(READ, self.parse_header_line, HTTPHeaderParser(), Accumulator())
def main(args=sys.argv): opts, args = create_option_parser().parse_args(args) if opts.auto_reload: if getattr(opts, 'daemonize', False): raise SystemExit( 'Cannot specify --auto-reload and --daemonize at the same time') from calibre.srv.auto_reload import auto_reload, NoAutoReload try: from calibre.utils.logging import default_log return auto_reload(default_log, listen_on=opts.listen_on) except NoAutoReload as e: raise SystemExit(error_message(e)) ensure_single_instance() if opts.userdb: opts.userdb = os.path.abspath(os.path.expandvars(os.path.expanduser(opts.userdb))) connect(opts.userdb, exc_class=SystemExit).close() if opts.manage_users: try: manage_users_cli(opts.userdb) except (KeyboardInterrupt, EOFError): raise SystemExit(_('Interrupted by user')) raise SystemExit(0) libraries = args[1:] for lib in libraries: if not lib or not LibraryDatabase.exists_at(lib): raise SystemExit(_('There is no calibre library at: %s') % lib) libraries = libraries or load_gui_libraries() if not libraries: if not prefs['library_path']: raise SystemExit(_('You must specify at least one calibre library')) libraries = [prefs['library_path']] opts.auto_reload_port = int(os.environ.get('CALIBRE_AUTORELOAD_PORT', 0)) opts.allow_console_print = 'CALIBRE_ALLOW_CONSOLE_PRINT' in os.environ if opts.log and os.path.isdir(opts.log): raise SystemExit('The --log option must point to a file, not a directory') if opts.access_log and os.path.isdir(opts.access_log): raise SystemExit('The --access-log option must point to a file, not a directory') server = Server(libraries, opts) if getattr(opts, 'daemonize', False): if not opts.log and not iswindows: raise SystemExit( 'In order to daemonize you must specify a log file, you can use /dev/stdout to log to screen even as a daemon' ) daemonize() if opts.pidfile: with lopen(opts.pidfile, 'wb') as f: f.write(unicode_type(os.getpid()).encode('ascii')) signal.signal(signal.SIGTERM, lambda s, f: server.stop()) if not getattr(opts, 'daemonize', False) and not iswindows: signal.signal(signal.SIGHUP, lambda s, f: server.stop()) # Needed for dynamic cover generation, which uses Qt for drawing from calibre.gui2 import ensure_app, load_builtin_fonts ensure_app(), load_builtin_fonts() try: server.serve_forever() finally: shutdown_delete_service()
def as_dict(self): return { 'name': self.name or undefined, 'message': self.js_message or error_message(self), 'fileName': self.fileName or undefined, 'lineNumber': self.lineNumber or undefined, 'stack': self.stack or undefined }
def as_dict(self): return { 'name':self.name or undefined, 'message': self.js_message or error_message(self), 'fileName': self.fileName or undefined, 'lineNumber': self.lineNumber or undefined, 'stack': self.stack or undefined }
def run(self): self.init_ctx() rl = None def set_prompt(p): self.prompt = p def prompt(lw): self.from_repl.put(to_python(lw)) self.ctx.g.set_prompt = set_prompt self.ctx.g.prompt = prompt self.ctx.eval(''' listeners = {}; rl = { setPrompt:set_prompt, write:Duktape.write, clearLine: function() {}, on: function(ev, cb) { listeners[ev] = cb; return rl; }, prompt: prompt, sync_prompt: true, send_line: function(line) { listeners['line'](line); }, send_interrupt: function() { listeners['SIGINT'](); }, close: function() {listeners['close'](); }, }; repl_options.readline = { createInterface: function(options) { rl.completer = options.completer; return rl; }}; exports.init_repl(repl_options) ''', fname='<init repl>') rl = self.ctx.g.rl completer = to_python(rl.completer) send_interrupt = to_python(rl.send_interrupt) send_line = to_python(rl.send_line) while True: ev, line = self.to_repl.get() try: if ev == 'SIGINT': self.output.write('\n') send_interrupt() elif ev == 'line': send_line(line) else: val = completer(line) val = to_python(val) self.from_repl.put(val[0]) except Exception as e: if isinstance(e, JSError): print(e.stack or error_message(e), file=sys.stderr) else: import traceback traceback.print_exc() for i in range(100): # Do this many times to ensure we dont deadlock self.from_repl.put(None)
def compile_coffeescript(raw, filename=None): from duktape import JSError jc = compiler() jc.g.src = raw try: ans = compiler().eval('CoffeeScript.compile(src)') except JSError as e: return u'', (error_message(e),) return ans, ()
def job_done(self, ok, result): if not ok: etype, e, tb = result if isinstance(e, HTTPSimpleResponse): eh = {} if e.location: eh['Location'] = e.location if e.authenticate: eh['WWW-Authenticate'] = e.authenticate if e.log: self.log.warn(e.log) return self.simple_response(e.http_code, msg=error_message(e) or '', close_after_response=e.close_connection, extra_headers=eh) reraise(etype, e, tb) data, output = result output = self.finalize_output(output, data, self.method is HTTP1) if output is None: return outheaders = data.outheaders outheaders.set('Date', http_date(), replace_all=True) outheaders.set('Server', 'calibre %s' % __version__, replace_all=True) keep_alive = not self.close_after_response and self.opts.timeout > 0 if keep_alive: outheaders.set('Keep-Alive', 'timeout=%d' % int(self.opts.timeout)) if 'Connection' not in outheaders: if self.response_protocol is HTTP11: if self.close_after_response: outheaders.set('Connection', 'close') else: if not self.close_after_response: outheaders.set('Connection', 'Keep-Alive') ct = outheaders.get('Content-Type', '') if ct.startswith('text/') and 'charset=' not in ct: outheaders.set('Content-Type', ct + '; charset=UTF-8', replace_all=True) buf = [HTTP11 + (' %d ' % data.status_code) + http_client.responses[data.status_code]] for header, value in sorted(iteritems(outheaders), key=itemgetter(0)): buf.append('%s: %s' % (header, value)) for morsel in itervalues(data.outcookie): morsel['version'] = '1' x = morsel.output() if isinstance(x, bytes): x = x.decode('ascii') buf.append(x) buf.append('') response_data = ReadOnlyFileBuffer(b''.join((x + '\r\n').encode('ascii') for x in buf)) if self.access_log is not None: sz = outheaders.get('Content-Length') if sz is not None: sz = int(sz) + response_data.sz self.log_access(status_code=data.status_code, response_size=sz, username=data.username) self.response_ready(response_data, output=output)
def check_raster_images(name, mt, raw): if not raw: return [EmptyFile(name)] errors = [] try: i = Image.open(BytesIO(raw)) except Exception as e: errors.append(InvalidImage(as_unicode(error_message(e)), name)) else: if i.mode == 'CMYK': errors.append(CMYKImage(_('Image is in the CMYK colorspace'), name)) return errors
def readfile(path, enc='utf-8'): try: with open(path, 'rb') as f: return [f.read().decode(enc or 'utf-8'), None, None] except UnicodeDecodeError as e: return None, '', 'Failed to decode the file: %s with specified encoding: %s' % ( path, enc) except EnvironmentError as e: return [ None, errno.errorcode[e.errno], 'Failed to read from file: %s with error: %s' % (path, error_message(e) or e) ]
def check_xml_parsing(name, mt, raw): if not raw: return [EmptyFile(name)] if check_for_private_entities(name, raw): return [PrivateEntities(_('Private entities found'), name)] raw = raw.replace(b'\r\n', b'\n').replace(b'\r', b'\n') # Get rid of entities as named entities trip up the XML parser eproc = EntitityProcessor(mt) eraw = entity_pat.sub(eproc, raw) parser = XMLParser(recover=False) errcls = HTMLParseError if mt in OEB_DOCS else XMLParseError errors = [] if eproc.ok_named_entities: errors.append(NamedEntities(name)) if eproc.bad_entities: position = PositionFinder(raw) for offset, ent in eproc.bad_entities: lnum, col = position(offset) errors.append(BadEntity(ent, name, lnum, col)) try: root = fromstring(eraw, parser=parser) except UnicodeDecodeError: return errors + [DecodeError(name)] except XMLSyntaxError as err: try: line, col = err.position except: line = col = None return errors + [errcls(error_message(err), name, line, col)] except Exception as err: return errors + [errcls(error_message(err), name)] if mt in OEB_DOCS: if root.nsmap.get(root.prefix, None) != XHTML_NS: errors.append(BadNamespace(name, root.nsmap.get(root.prefix, None))) return errors
def run_importer(): export_dir = input_unicode('Enter path to folder containing previously exported data: ').rstrip('\r') if not os.path.isdir(export_dir): raise SystemExit('%s is not a folder' % export_dir) try: importer = Importer(export_dir) except ValueError as err: raise SystemExit(error_message(err)) import_dir = input_unicode('Enter path to an empty folder (all libraries will be created inside this folder): ').rstrip('\r') if not os.path.exists(import_dir): os.makedirs(import_dir) if not os.path.isdir(import_dir): raise SystemExit('%s is not a folder' % import_dir) if os.listdir(import_dir): raise SystemExit('%s is not empty' % import_dir) import_data(importer, { k:os.path.join(import_dir, os.path.basename(k)) for k in importer.metadata['libraries']}, progress1=cli_report, progress2=cli_report)
def __call__(self, f, outfile, filters=()): w = outfile.write c = self.crc def write(raw): if filters: raw = bytearray(raw) for flt in filters: raw = flt(raw) raw = bytes(raw) w(raw), c(raw) try: lzma.decompress2(f.read, f.seek, write, self.props, self.bufsize) except lzma.error as e: raise InvalidXZ( 'Failed to decode LZMA2 block with error code: %s' % error_message(e)) self.crc.finish()
def __call__(self, f, outfile, filters=()): w = outfile.write c = self.crc def write(raw): if filters: raw = bytearray(raw) for flt in filters: raw = flt(raw) raw = bytes(raw) w(raw), c(raw) try: lzma.decompress2(f.read, f.seek, write, self.props, self.bufsize) except lzma.error as e: raise InvalidXZ( 'Failed to decode LZMA2 block with error code: %s' % error_message(e) ) self.crc.finish()
def writefile(path, data, enc='utf-8'): if enc == undefined: enc = 'utf-8' try: if isinstance(data, unicode_type): data = data.encode(enc or 'utf-8') atomic_write(path, data) except UnicodeEncodeError as e: return [ '', 'Failed to encode the data for file: %s with specified encoding: %s' % (path, enc) ] except EnvironmentError as e: return [ errno.errorcode[e.errno], 'Failed to write to file: %s with error: %s' % (path, error_message(e) or e) ] return [None, None]
def safe_format(self, fmt, kwargs, error_value, book, column_name=None, template_cache=None, strip_results=True, template_functions=None): self.strip_results = strip_results self.column_name = column_name self.template_cache = template_cache self.kwargs = kwargs self.book = book if template_functions: self.funcs = template_functions else: self.funcs = formatter_functions().get_functions() self.composite_values = {} self.locals = {} try: ans = self.evaluate(fmt, [], kwargs) except Exception as e: if DEBUG: # and getattr(e, 'is_locking_error', False): traceback.print_exc() if column_name: prints('Error evaluating column named:', column_name) ans = error_value + ' ' + error_message(e) return ans
def job_done(self, ok, result): if not ok: etype, e, tb = result if isinstance(e, HTTPSimpleResponse): eh = {} if e.location: eh['Location'] = e.location if e.authenticate: eh['WWW-Authenticate'] = e.authenticate if e.log: self.log.warn(e.log) return self.simple_response( e.http_code, msg=error_message(e) or '', close_after_response=e.close_connection, extra_headers=eh) reraise(etype, e, tb) data, output = result output = self.finalize_output(output, data, self.method is HTTP1) if output is None: return outheaders = data.outheaders outheaders.set('Date', http_date(), replace_all=True) outheaders.set('Server', 'calibre %s' % __version__, replace_all=True) keep_alive = not self.close_after_response and self.opts.timeout > 0 if keep_alive: outheaders.set('Keep-Alive', 'timeout=%d' % int(self.opts.timeout)) if 'Connection' not in outheaders: if self.response_protocol is HTTP11: if self.close_after_response: outheaders.set('Connection', 'close') else: if not self.close_after_response: outheaders.set('Connection', 'Keep-Alive') ct = outheaders.get('Content-Type', '') if ct.startswith('text/') and 'charset=' not in ct: outheaders.set('Content-Type', ct + '; charset=UTF-8', replace_all=True) buf = [ HTTP11 + (' %d ' % data.status_code) + http_client.responses[data.status_code] ] for header, value in sorted(iteritems(outheaders), key=itemgetter(0)): buf.append('%s: %s' % (header, value)) for morsel in itervalues(data.outcookie): morsel['version'] = '1' x = morsel.output() if isinstance(x, bytes): x = x.decode('ascii') buf.append(x) buf.append('') response_data = ReadOnlyFileBuffer(b''.join( (x + '\r\n').encode('ascii') for x in buf)) if self.access_log is not None: sz = outheaders.get('Content-Length') if sz is not None: sz = int(sz) + response_data.sz self.log_access(status_code=data.status_code, response_size=sz, username=data.username) self.response_ready(response_data, output=output)
def main(args=sys.argv): opts, args = create_option_parser().parse_args(args) if opts.auto_reload and not opts.manage_users: if getattr(opts, 'daemonize', False): raise SystemExit( 'Cannot specify --auto-reload and --daemonize at the same time') from calibre.srv.auto_reload import NoAutoReload, auto_reload try: from calibre.utils.logging import default_log return auto_reload(default_log, listen_on=opts.listen_on) except NoAutoReload as e: raise SystemExit(error_message(e)) ensure_single_instance() if opts.userdb: opts.userdb = os.path.abspath(os.path.expandvars(os.path.expanduser(opts.userdb))) connect(opts.userdb, exc_class=SystemExit).close() if opts.manage_users: try: manage_users_cli(opts.userdb, args[1:]) except (KeyboardInterrupt, EOFError): raise SystemExit(_('Interrupted by user')) raise SystemExit(0) libraries = args[1:] for lib in libraries: if not lib or not LibraryDatabase.exists_at(lib): raise SystemExit(_('There is no calibre library at: %s') % lib) libraries = libraries or load_gui_libraries() if not libraries: if not prefs['library_path']: raise SystemExit(_('You must specify at least one calibre library')) libraries = [prefs['library_path']] opts.auto_reload_port = int(os.environ.get('CALIBRE_AUTORELOAD_PORT', 0)) opts.allow_console_print = 'CALIBRE_ALLOW_CONSOLE_PRINT' in os.environ if opts.log and os.path.isdir(opts.log): raise SystemExit('The --log option must point to a file, not a directory') if opts.access_log and os.path.isdir(opts.access_log): raise SystemExit('The --access-log option must point to a file, not a directory') try: server = Server(libraries, opts) except BadIPSpec as e: raise SystemExit('{}'.format(e)) if getattr(opts, 'daemonize', False): if not opts.log and not iswindows: raise SystemExit( 'In order to daemonize you must specify a log file, you can use /dev/stdout to log to screen even as a daemon' ) daemonize() if opts.pidfile: with lopen(opts.pidfile, 'wb') as f: f.write(str(os.getpid()).encode('ascii')) signal.signal(signal.SIGTERM, lambda s, f: server.stop()) if not getattr(opts, 'daemonize', False) and not iswindows: signal.signal(signal.SIGHUP, lambda s, f: server.stop()) # Needed for dynamic cover generation, which uses Qt for drawing from calibre.gui2 import ensure_app, load_builtin_fonts ensure_app(), load_builtin_fonts() with HandleInterrupt(server.stop): try: server.serve_forever() finally: shutdown_delete_service()
def parse_media(self, tokens, errors): if not tokens: return [MediaQuery('all')] queries = [] for part in split_on_comma(remove_whitespace(tokens)): negated = False media_type = None expressions = [] try: for i, tok in enumerate(part): if i == 0 and tok.type == 'IDENT': val = tok.value.lower() if val == 'only': continue # ignore leading ONLY if val == 'not': negated = True continue if media_type is None and tok.type == 'IDENT': media_type = tok.value continue elif media_type is None: media_type = 'all' if tok.type == 'IDENT' and tok.value.lower() == 'and': continue if not tok.is_container: raise MalformedExpression( tok, 'expected a media expression not a %s' % tok.type) if tok.type != '(': raise MalformedExpression( tok, 'media expressions must be in parentheses not %s' % tok.type) content = remove_whitespace(tok.content) if len(content) == 0: raise MalformedExpression( tok, 'media expressions cannot be empty') if content[0].type != 'IDENT': raise MalformedExpression( content[0], 'expected a media feature not a %s' % tok.type) media_feature, expr = content[0].value, None if len(content) > 1: if len(content) < 3: raise MalformedExpression( content[1], 'malformed media feature definition') if content[1].type != ':': raise MalformedExpression(content[1], 'expected a :') expr = content[2:] if len(expr) == 1: expr = expr[0] elif len(expr) == 3 and ( expr[0].type, expr[1].type, expr[1].value, expr[2].type) == ('INTEGER', 'DELIM', '/', 'INTEGER'): # This should really be moved into token_data, but # since RATIO is not part of CSS 2.1 and does not # occur anywhere else, we special case it here. r = expr[0] r.value = (expr[0].value, expr[2].value) r.type = 'RATIO' r._as_css = expr[0]._as_css + expr[ 1]._as_css + expr[2]._as_css expr = r else: raise MalformedExpression( expr[0], 'malformed media feature definition') expressions.append((media_feature, expr)) except MalformedExpression as err: errors.append(ParseError(err.tok, error_message(err))) media_type, negated, expressions = 'all', True, () queries.append( MediaQuery(media_type or 'all', expressions=tuple(expressions), negated=negated)) return queries
def readfile(path, enc='utf-8'): try: with open(path, 'rb') as f: return [f.read().decode(enc or 'utf-8'), None, None] except UnicodeDecodeError as e: return None, '', 'Failed to decode the file: %s with specified encoding: %s' % (path, enc) except EnvironmentError as e: return [None, errno.errorcode[e.errno], 'Failed to read from file: %s with error: %s' % (path, error_message(e) or e)]
def writefile(path, data, enc='utf-8'): if enc == undefined: enc = 'utf-8' try: if isinstance(data, type('')): data = data.encode(enc or 'utf-8') atomic_write(path, data) except UnicodeEncodeError as e: return ['', 'Failed to encode the data for file: %s with specified encoding: %s' % (path, enc)] except EnvironmentError as e: return [errno.errorcode[e.errno], 'Failed to write to file: %s with error: %s' % (path, error_message(e) or e)] return [None, None]