#!/usr/bin/python # CSS Test Suite Manipulation Library Utilities # Initial code by fantasai, joint copyright 2010 W3C and Microsoft # Licensed under BSD 3-Clause: ###### XML Parsing ###### import os import w3ctestlib os.environ['XML_CATALOG_FILES'] = os.path.join(w3ctestlib.__path__[0], 'catalog/catalog.xml') ###### File path manipulation ###### import os.path from os.path import sep, pardir def assetName(path): return intern(os.path.splitext(os.path.basename(path))[0].lower().encode('ascii')) def basepath(path): """ Returns the path part of os.path.split. """ return os.path.dirname(path) def isPathInsideBase(path, base=''): path = os.path.normpath(path) if base: base = os.path.normpath(base) pathlist = path.split(os.path.sep) baselist = base.split(os.path.sep) while baselist: p = pathlist.pop(0) b = baselist.pop(0) if p != b: return False return not pathlist[0].startswith(os.path.pardir) return not path.startswith(os.path.pardir) def relpath(path, start): """Return relative path from start to end. WARNING: this is not the same as a relative URL; see relativeURL().""" try: return os.path.relpath(path, start) except AttributeError: # This function is copied directly from the Python 2.6 source # code, and is therefore under a different license. if not path: raise ValueError("no path specified") start_list = os.path.abspath(start).split(sep) path_list = os.path.abspath(path).split(sep) if start_list[0].lower() != path_list[0].lower(): unc_path, rest = os.path.splitunc(path) unc_start, rest = os.path.splitunc(start) if bool(unc_path) ^ bool(unc_start): raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)" % (path, start)) else: raise ValueError("path is on drive %s, start on drive %s" % (path_list[0], start_list[0])) # Work out how much of the filepath is shared by start and path. for i in range(min(len(start_list), len(path_list))): if start_list[i].lower() != path_list[i].lower(): break else: i += 1 rel_list = [pardir] * (len(start_list)-i) + path_list[i:] if not rel_list: return os.path.curdir return os.path.join(*rel_list) def relativeURL(start, end): """ Returns relative URL from `start` to `end`. """ # if isPathInsideBase(end, start): # return relpath(end, start) # else: return relpath(end, basepath(start)) def listfiles(path, ext = None): """ Returns a list of all files in a directory. Optionally lists only files with a given extension. """ try: _,_,files = os.walk(path).next() if (ext): files = [fileName for fileName in files if fileName.endswith(ext)] except StopIteration: files = [] return files def listdirs(path): """ Returns a list of all subdirectories in a directory. """ try: _,dirs,_ = os.walk(path).next() except StopIteration: dirs = [] return dirs ###### MIME types and file extensions ###### extensionMap = { None : 'application/octet-stream', # default '.xht' : 'application/xhtml+xml', '.xhtml' : 'application/xhtml+xml', '.xml' : 'application/xml', '.htm' : 'text/html', '.html' : 'text/html', '.txt' : 'text/plain', '.jpg' : 'image/jpeg', '.png' : 'image/png', '.svg' : 'image/svg+xml', } def getMimeFromExt(filepath): """Convenience function: equal to extenionMap.get(ext, extensionMap[None]). """ if filepath.endswith('.htaccess'): return 'config/htaccess' ext = os.path.splitext(filepath)[1] return extensionMap.get(ext, extensionMap[None]) ###### Escaping ###### import types from htmlentitydefs import entitydefs entityify = dict([c,e] for e,c in entitydefs.iteritems()) def escapeMarkup(data): """Escape markup characters (&, >, <). Copied from xml.sax.saxutils. """ # must do ampersand first data = data.replace("&", "&") data = data.replace(">", ">") data = data.replace("<", "<") return data def escapeToNamedASCII(text): """Escapes to named entities where possible and numeric-escapes non-ASCII """ return escapeToNamed(text).encode('ascii', 'xmlcharrefreplace') def escapeToNamed(text): """Escape characters with named entities. """ escapable = set() for c in text: if ord(c) > 127: escapable.add(c) if type(text) == types.UnicodeType: for c in escapable: cLatin = c.encode('Latin-1', 'ignore') if (cLatin in entityify): text = text.replace(c, "&%s;" % entityify[cLatin]) else: for c in escapable: text = text.replace(c, "&%s;" % entityify[c]) return text