Version 1.8
parent
4d96f79d78
commit
299d105b22
|
@ -1,2 +1,2 @@
|
|||
# PortalAuth
|
||||
Captive portal cloner and payload distributor for the WiFi Pineapple NANO and TETRA
|
||||
# PortalAuth
|
||||
Captive portal cloner and payload distributor for the WiFi Pineapple NANO and TETRA
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
July 26, 2018
|
||||
<br /><br />
|
||||
- Fixed tinycss lib reference<br />
|
File diff suppressed because it is too large
Load Diff
|
@ -1,310 +1,310 @@
|
|||
# Copyright 2001-2005 by Vinay Sajip. All Rights Reserved.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose and without fee is hereby granted,
|
||||
# provided that the above copyright notice appear in all copies and that
|
||||
# both that copyright notice and this permission notice appear in
|
||||
# supporting documentation, and that the name of Vinay Sajip
|
||||
# not be used in advertising or publicity pertaining to distribution
|
||||
# of the software without specific, written prior permission.
|
||||
# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
||||
# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
|
||||
# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""
|
||||
Configuration functions for the logging package for Python. The core package
|
||||
is based on PEP 282 and comments thereto in comp.lang.python, and influenced
|
||||
by Apache's log4j system.
|
||||
|
||||
Should work under Python versions >= 1.5.2, except that source line
|
||||
information is not available unless 'sys._getframe()' is.
|
||||
|
||||
Copyright (C) 2001-2004 Vinay Sajip. All Rights Reserved.
|
||||
|
||||
To use, simply 'import logging' and log away!
|
||||
"""
|
||||
|
||||
import sys, logging, logging.handlers, string, socket, struct, os
|
||||
|
||||
try:
|
||||
import thread
|
||||
import threading
|
||||
except ImportError:
|
||||
thread = None
|
||||
|
||||
from SocketServer import ThreadingTCPServer, StreamRequestHandler
|
||||
|
||||
|
||||
DEFAULT_LOGGING_CONFIG_PORT = 9030
|
||||
|
||||
if sys.platform == "win32":
|
||||
RESET_ERROR = 10054 #WSAECONNRESET
|
||||
else:
|
||||
RESET_ERROR = 104 #ECONNRESET
|
||||
|
||||
#
|
||||
# The following code implements a socket listener for on-the-fly
|
||||
# reconfiguration of logging.
|
||||
#
|
||||
# _listener holds the server object doing the listening
|
||||
_listener = None
|
||||
|
||||
def fileConfig(fname, defaults=None):
|
||||
"""
|
||||
Read the logging configuration from a ConfigParser-format file.
|
||||
|
||||
This can be called several times from an application, allowing an end user
|
||||
the ability to select from various pre-canned configurations (if the
|
||||
developer provides a mechanism to present the choices and load the chosen
|
||||
configuration).
|
||||
In versions of ConfigParser which have the readfp method [typically
|
||||
shipped in 2.x versions of Python], you can pass in a file-like object
|
||||
rather than a filename, in which case the file-like object will be read
|
||||
using readfp.
|
||||
"""
|
||||
import ConfigParser
|
||||
|
||||
cp = ConfigParser.ConfigParser(defaults)
|
||||
if hasattr(cp, 'readfp') and hasattr(fname, 'readline'):
|
||||
cp.readfp(fname)
|
||||
else:
|
||||
cp.read(fname)
|
||||
#first, do the formatters...
|
||||
flist = cp.get("formatters", "keys")
|
||||
if len(flist):
|
||||
flist = string.split(flist, ",")
|
||||
formatters = {}
|
||||
for form in flist:
|
||||
sectname = "formatter_%s" % form
|
||||
opts = cp.options(sectname)
|
||||
if "format" in opts:
|
||||
fs = cp.get(sectname, "format", 1)
|
||||
else:
|
||||
fs = None
|
||||
if "datefmt" in opts:
|
||||
dfs = cp.get(sectname, "datefmt", 1)
|
||||
else:
|
||||
dfs = None
|
||||
f = logging.Formatter(fs, dfs)
|
||||
formatters[form] = f
|
||||
#next, do the handlers...
|
||||
#critical section...
|
||||
logging._acquireLock()
|
||||
try:
|
||||
try:
|
||||
#first, lose the existing handlers...
|
||||
logging._handlers.clear()
|
||||
#now set up the new ones...
|
||||
hlist = cp.get("handlers", "keys")
|
||||
if len(hlist):
|
||||
hlist = string.split(hlist, ",")
|
||||
handlers = {}
|
||||
fixups = [] #for inter-handler references
|
||||
for hand in hlist:
|
||||
try:
|
||||
sectname = "handler_%s" % hand
|
||||
klass = cp.get(sectname, "class")
|
||||
opts = cp.options(sectname)
|
||||
if "formatter" in opts:
|
||||
fmt = cp.get(sectname, "formatter")
|
||||
else:
|
||||
fmt = ""
|
||||
klass = eval(klass, vars(logging))
|
||||
args = cp.get(sectname, "args")
|
||||
args = eval(args, vars(logging))
|
||||
h = apply(klass, args)
|
||||
if "level" in opts:
|
||||
level = cp.get(sectname, "level")
|
||||
h.setLevel(logging._levelNames[level])
|
||||
if len(fmt):
|
||||
h.setFormatter(formatters[fmt])
|
||||
#temporary hack for FileHandler and MemoryHandler.
|
||||
if klass == logging.handlers.MemoryHandler:
|
||||
if "target" in opts:
|
||||
target = cp.get(sectname,"target")
|
||||
else:
|
||||
target = ""
|
||||
if len(target): #the target handler may not be loaded yet, so keep for later...
|
||||
fixups.append((h, target))
|
||||
handlers[hand] = h
|
||||
except: #if an error occurs when instantiating a handler, too bad
|
||||
pass #this could happen e.g. because of lack of privileges
|
||||
#now all handlers are loaded, fixup inter-handler references...
|
||||
for fixup in fixups:
|
||||
h = fixup[0]
|
||||
t = fixup[1]
|
||||
h.setTarget(handlers[t])
|
||||
#at last, the loggers...first the root...
|
||||
llist = cp.get("loggers", "keys")
|
||||
llist = string.split(llist, ",")
|
||||
llist.remove("root")
|
||||
sectname = "logger_root"
|
||||
root = logging.root
|
||||
log = root
|
||||
opts = cp.options(sectname)
|
||||
if "level" in opts:
|
||||
level = cp.get(sectname, "level")
|
||||
log.setLevel(logging._levelNames[level])
|
||||
for h in root.handlers[:]:
|
||||
root.removeHandler(h)
|
||||
hlist = cp.get(sectname, "handlers")
|
||||
if len(hlist):
|
||||
hlist = string.split(hlist, ",")
|
||||
for hand in hlist:
|
||||
log.addHandler(handlers[hand])
|
||||
#and now the others...
|
||||
#we don't want to lose the existing loggers,
|
||||
#since other threads may have pointers to them.
|
||||
#existing is set to contain all existing loggers,
|
||||
#and as we go through the new configuration we
|
||||
#remove any which are configured. At the end,
|
||||
#what's left in existing is the set of loggers
|
||||
#which were in the previous configuration but
|
||||
#which are not in the new configuration.
|
||||
existing = root.manager.loggerDict.keys()
|
||||
#now set up the new ones...
|
||||
for log in llist:
|
||||
sectname = "logger_%s" % log
|
||||
qn = cp.get(sectname, "qualname")
|
||||
opts = cp.options(sectname)
|
||||
if "propagate" in opts:
|
||||
propagate = cp.getint(sectname, "propagate")
|
||||
else:
|
||||
propagate = 1
|
||||
logger = logging.getLogger(qn)
|
||||
if qn in existing:
|
||||
existing.remove(qn)
|
||||
if "level" in opts:
|
||||
level = cp.get(sectname, "level")
|
||||
logger.setLevel(logging._levelNames[level])
|
||||
for h in logger.handlers[:]:
|
||||
logger.removeHandler(h)
|
||||
logger.propagate = propagate
|
||||
logger.disabled = 0
|
||||
hlist = cp.get(sectname, "handlers")
|
||||
if len(hlist):
|
||||
hlist = string.split(hlist, ",")
|
||||
for hand in hlist:
|
||||
logger.addHandler(handlers[hand])
|
||||
#Disable any old loggers. There's no point deleting
|
||||
#them as other threads may continue to hold references
|
||||
#and by disabling them, you stop them doing any logging.
|
||||
for log in existing:
|
||||
root.manager.loggerDict[log].disabled = 1
|
||||
except:
|
||||
import traceback
|
||||
ei = sys.exc_info()
|
||||
traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr)
|
||||
del ei
|
||||
finally:
|
||||
logging._releaseLock()
|
||||
|
||||
def listen(port=DEFAULT_LOGGING_CONFIG_PORT):
|
||||
"""
|
||||
Start up a socket server on the specified port, and listen for new
|
||||
configurations.
|
||||
|
||||
These will be sent as a file suitable for processing by fileConfig().
|
||||
Returns a Thread object on which you can call start() to start the server,
|
||||
and which you can join() when appropriate. To stop the server, call
|
||||
stopListening().
|
||||
"""
|
||||
if not thread:
|
||||
raise NotImplementedError, "listen() needs threading to work"
|
||||
|
||||
class ConfigStreamHandler(StreamRequestHandler):
|
||||
"""
|
||||
Handler for a logging configuration request.
|
||||
|
||||
It expects a completely new logging configuration and uses fileConfig
|
||||
to install it.
|
||||
"""
|
||||
def handle(self):
|
||||
"""
|
||||
Handle a request.
|
||||
|
||||
Each request is expected to be a 4-byte length,
|
||||
followed by the config file. Uses fileConfig() to do the
|
||||
grunt work.
|
||||
"""
|
||||
import tempfile
|
||||
try:
|
||||
conn = self.connection
|
||||
chunk = conn.recv(4)
|
||||
if len(chunk) == 4:
|
||||
slen = struct.unpack(">L", chunk)[0]
|
||||
chunk = self.connection.recv(slen)
|
||||
while len(chunk) < slen:
|
||||
chunk = chunk + conn.recv(slen - len(chunk))
|
||||
#Apply new configuration. We'd like to be able to
|
||||
#create a StringIO and pass that in, but unfortunately
|
||||
#1.5.2 ConfigParser does not support reading file
|
||||
#objects, only actual files. So we create a temporary
|
||||
#file and remove it later.
|
||||
file = tempfile.mktemp(".ini")
|
||||
f = open(file, "w")
|
||||
f.write(chunk)
|
||||
f.close()
|
||||
fileConfig(file)
|
||||
os.remove(file)
|
||||
except socket.error, e:
|
||||
if type(e.args) != types.TupleType:
|
||||
raise
|
||||
else:
|
||||
errcode = e.args[0]
|
||||
if errcode != RESET_ERROR:
|
||||
raise
|
||||
|
||||
class ConfigSocketReceiver(ThreadingTCPServer):
|
||||
"""
|
||||
A simple TCP socket-based logging config receiver.
|
||||
"""
|
||||
|
||||
allow_reuse_address = 1
|
||||
|
||||
def __init__(self, host='localhost', port=DEFAULT_LOGGING_CONFIG_PORT,
|
||||
handler=None):
|
||||
ThreadingTCPServer.__init__(self, (host, port), handler)
|
||||
logging._acquireLock()
|
||||
self.abort = 0
|
||||
logging._releaseLock()
|
||||
self.timeout = 1
|
||||
|
||||
def serve_until_stopped(self):
|
||||
import select
|
||||
abort = 0
|
||||
while not abort:
|
||||
rd, wr, ex = select.select([self.socket.fileno()],
|
||||
[], [],
|
||||
self.timeout)
|
||||
if rd:
|
||||
self.handle_request()
|
||||
logging._acquireLock()
|
||||
abort = self.abort
|
||||
logging._releaseLock()
|
||||
|
||||
def serve(rcvr, hdlr, port):
|
||||
server = rcvr(port=port, handler=hdlr)
|
||||
global _listener
|
||||
logging._acquireLock()
|
||||
_listener = server
|
||||
logging._releaseLock()
|
||||
server.serve_until_stopped()
|
||||
|
||||
return threading.Thread(target=serve,
|
||||
args=(ConfigSocketReceiver,
|
||||
ConfigStreamHandler, port))
|
||||
|
||||
def stopListening():
|
||||
"""
|
||||
Stop the listening server which was created with a call to listen().
|
||||
"""
|
||||
global _listener
|
||||
if _listener:
|
||||
logging._acquireLock()
|
||||
_listener.abort = 1
|
||||
_listener = None
|
||||
logging._releaseLock()
|
||||
# Copyright 2001-2005 by Vinay Sajip. All Rights Reserved.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose and without fee is hereby granted,
|
||||
# provided that the above copyright notice appear in all copies and that
|
||||
# both that copyright notice and this permission notice appear in
|
||||
# supporting documentation, and that the name of Vinay Sajip
|
||||
# not be used in advertising or publicity pertaining to distribution
|
||||
# of the software without specific, written prior permission.
|
||||
# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
||||
# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
|
||||
# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
"""
|
||||
Configuration functions for the logging package for Python. The core package
|
||||
is based on PEP 282 and comments thereto in comp.lang.python, and influenced
|
||||
by Apache's log4j system.
|
||||
|
||||
Should work under Python versions >= 1.5.2, except that source line
|
||||
information is not available unless 'sys._getframe()' is.
|
||||
|
||||
Copyright (C) 2001-2004 Vinay Sajip. All Rights Reserved.
|
||||
|
||||
To use, simply 'import logging' and log away!
|
||||
"""
|
||||
|
||||
import sys, logging, logging.handlers, string, socket, struct, os
|
||||
|
||||
try:
|
||||
import thread
|
||||
import threading
|
||||
except ImportError:
|
||||
thread = None
|
||||
|
||||
from SocketServer import ThreadingTCPServer, StreamRequestHandler
|
||||
|
||||
|
||||
DEFAULT_LOGGING_CONFIG_PORT = 9030
|
||||
|
||||
if sys.platform == "win32":
|
||||
RESET_ERROR = 10054 #WSAECONNRESET
|
||||
else:
|
||||
RESET_ERROR = 104 #ECONNRESET
|
||||
|
||||
#
|
||||
# The following code implements a socket listener for on-the-fly
|
||||
# reconfiguration of logging.
|
||||
#
|
||||
# _listener holds the server object doing the listening
|
||||
_listener = None
|
||||
|
||||
def fileConfig(fname, defaults=None):
|
||||
"""
|
||||
Read the logging configuration from a ConfigParser-format file.
|
||||
|
||||
This can be called several times from an application, allowing an end user
|
||||
the ability to select from various pre-canned configurations (if the
|
||||
developer provides a mechanism to present the choices and load the chosen
|
||||
configuration).
|
||||
In versions of ConfigParser which have the readfp method [typically
|
||||
shipped in 2.x versions of Python], you can pass in a file-like object
|
||||
rather than a filename, in which case the file-like object will be read
|
||||
using readfp.
|
||||
"""
|
||||
import ConfigParser
|
||||
|
||||
cp = ConfigParser.ConfigParser(defaults)
|
||||
if hasattr(cp, 'readfp') and hasattr(fname, 'readline'):
|
||||
cp.readfp(fname)
|
||||
else:
|
||||
cp.read(fname)
|
||||
#first, do the formatters...
|
||||
flist = cp.get("formatters", "keys")
|
||||
if len(flist):
|
||||
flist = string.split(flist, ",")
|
||||
formatters = {}
|
||||
for form in flist:
|
||||
sectname = "formatter_%s" % form
|
||||
opts = cp.options(sectname)
|
||||
if "format" in opts:
|
||||
fs = cp.get(sectname, "format", 1)
|
||||
else:
|
||||
fs = None
|
||||
if "datefmt" in opts:
|
||||
dfs = cp.get(sectname, "datefmt", 1)
|
||||
else:
|
||||
dfs = None
|
||||
f = logging.Formatter(fs, dfs)
|
||||
formatters[form] = f
|
||||
#next, do the handlers...
|
||||
#critical section...
|
||||
logging._acquireLock()
|
||||
try:
|
||||
try:
|
||||
#first, lose the existing handlers...
|
||||
logging._handlers.clear()
|
||||
#now set up the new ones...
|
||||
hlist = cp.get("handlers", "keys")
|
||||
if len(hlist):
|
||||
hlist = string.split(hlist, ",")
|
||||
handlers = {}
|
||||
fixups = [] #for inter-handler references
|
||||
for hand in hlist:
|
||||
try:
|
||||
sectname = "handler_%s" % hand
|
||||
klass = cp.get(sectname, "class")
|
||||
opts = cp.options(sectname)
|
||||
if "formatter" in opts:
|
||||
fmt = cp.get(sectname, "formatter")
|
||||
else:
|
||||
fmt = ""
|
||||
klass = eval(klass, vars(logging))
|
||||
args = cp.get(sectname, "args")
|
||||
args = eval(args, vars(logging))
|
||||
h = apply(klass, args)
|
||||
if "level" in opts:
|
||||
level = cp.get(sectname, "level")
|
||||
h.setLevel(logging._levelNames[level])
|
||||
if len(fmt):
|
||||
h.setFormatter(formatters[fmt])
|
||||
#temporary hack for FileHandler and MemoryHandler.
|
||||
if klass == logging.handlers.MemoryHandler:
|
||||
if "target" in opts:
|
||||
target = cp.get(sectname,"target")
|
||||
else:
|
||||
target = ""
|
||||
if len(target): #the target handler may not be loaded yet, so keep for later...
|
||||
fixups.append((h, target))
|
||||
handlers[hand] = h
|
||||
except: #if an error occurs when instantiating a handler, too bad
|
||||
pass #this could happen e.g. because of lack of privileges
|
||||
#now all handlers are loaded, fixup inter-handler references...
|
||||
for fixup in fixups:
|
||||
h = fixup[0]
|
||||
t = fixup[1]
|
||||
h.setTarget(handlers[t])
|
||||
#at last, the loggers...first the root...
|
||||
llist = cp.get("loggers", "keys")
|
||||
llist = string.split(llist, ",")
|
||||
llist.remove("root")
|
||||
sectname = "logger_root"
|
||||
root = logging.root
|
||||
log = root
|
||||
opts = cp.options(sectname)
|
||||
if "level" in opts:
|
||||
level = cp.get(sectname, "level")
|
||||
log.setLevel(logging._levelNames[level])
|
||||
for h in root.handlers[:]:
|
||||
root.removeHandler(h)
|
||||
hlist = cp.get(sectname, "handlers")
|
||||
if len(hlist):
|
||||
hlist = string.split(hlist, ",")
|
||||
for hand in hlist:
|
||||
log.addHandler(handlers[hand])
|
||||
#and now the others...
|
||||
#we don't want to lose the existing loggers,
|
||||
#since other threads may have pointers to them.
|
||||
#existing is set to contain all existing loggers,
|
||||
#and as we go through the new configuration we
|
||||
#remove any which are configured. At the end,
|
||||
#what's left in existing is the set of loggers
|
||||
#which were in the previous configuration but
|
||||
#which are not in the new configuration.
|
||||
existing = root.manager.loggerDict.keys()
|
||||
#now set up the new ones...
|
||||
for log in llist:
|
||||
sectname = "logger_%s" % log
|
||||
qn = cp.get(sectname, "qualname")
|
||||
opts = cp.options(sectname)
|
||||
if "propagate" in opts:
|
||||
propagate = cp.getint(sectname, "propagate")
|
||||
else:
|
||||
propagate = 1
|
||||
logger = logging.getLogger(qn)
|
||||
if qn in existing:
|
||||
existing.remove(qn)
|
||||
if "level" in opts:
|
||||
level = cp.get(sectname, "level")
|
||||
logger.setLevel(logging._levelNames[level])
|
||||
for h in logger.handlers[:]:
|
||||
logger.removeHandler(h)
|
||||
logger.propagate = propagate
|
||||
logger.disabled = 0
|
||||
hlist = cp.get(sectname, "handlers")
|
||||
if len(hlist):
|
||||
hlist = string.split(hlist, ",")
|
||||
for hand in hlist:
|
||||
logger.addHandler(handlers[hand])
|
||||
#Disable any old loggers. There's no point deleting
|
||||
#them as other threads may continue to hold references
|
||||
#and by disabling them, you stop them doing any logging.
|
||||
for log in existing:
|
||||
root.manager.loggerDict[log].disabled = 1
|
||||
except:
|
||||
import traceback
|
||||
ei = sys.exc_info()
|
||||
traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr)
|
||||
del ei
|
||||
finally:
|
||||
logging._releaseLock()
|
||||
|
||||
def listen(port=DEFAULT_LOGGING_CONFIG_PORT):
|
||||
"""
|
||||
Start up a socket server on the specified port, and listen for new
|
||||
configurations.
|
||||
|
||||
These will be sent as a file suitable for processing by fileConfig().
|
||||
Returns a Thread object on which you can call start() to start the server,
|
||||
and which you can join() when appropriate. To stop the server, call
|
||||
stopListening().
|
||||
"""
|
||||
if not thread:
|
||||
raise NotImplementedError, "listen() needs threading to work"
|
||||
|
||||
class ConfigStreamHandler(StreamRequestHandler):
|
||||
"""
|
||||
Handler for a logging configuration request.
|
||||
|
||||
It expects a completely new logging configuration and uses fileConfig
|
||||
to install it.
|
||||
"""
|
||||
def handle(self):
|
||||
"""
|
||||
Handle a request.
|
||||
|
||||
Each request is expected to be a 4-byte length,
|
||||
followed by the config file. Uses fileConfig() to do the
|
||||
grunt work.
|
||||
"""
|
||||
import tempfile
|
||||
try:
|
||||
conn = self.connection
|
||||
chunk = conn.recv(4)
|
||||
if len(chunk) == 4:
|
||||
slen = struct.unpack(">L", chunk)[0]
|
||||
chunk = self.connection.recv(slen)
|
||||
while len(chunk) < slen:
|
||||
chunk = chunk + conn.recv(slen - len(chunk))
|
||||
#Apply new configuration. We'd like to be able to
|
||||
#create a StringIO and pass that in, but unfortunately
|
||||
#1.5.2 ConfigParser does not support reading file
|
||||
#objects, only actual files. So we create a temporary
|
||||
#file and remove it later.
|
||||
file = tempfile.mktemp(".ini")
|
||||
f = open(file, "w")
|
||||
f.write(chunk)
|
||||
f.close()
|
||||
fileConfig(file)
|
||||
os.remove(file)
|
||||
except socket.error, e:
|
||||
if type(e.args) != types.TupleType:
|
||||
raise
|
||||
else:
|
||||
errcode = e.args[0]
|
||||
if errcode != RESET_ERROR:
|
||||
raise
|
||||
|
||||
class ConfigSocketReceiver(ThreadingTCPServer):
|
||||
"""
|
||||
A simple TCP socket-based logging config receiver.
|
||||
"""
|
||||
|
||||
allow_reuse_address = 1
|
||||
|
||||
def __init__(self, host='localhost', port=DEFAULT_LOGGING_CONFIG_PORT,
|
||||
handler=None):
|
||||
ThreadingTCPServer.__init__(self, (host, port), handler)
|
||||
logging._acquireLock()
|
||||
self.abort = 0
|
||||
logging._releaseLock()
|
||||
self.timeout = 1
|
||||
|
||||
def serve_until_stopped(self):
|
||||
import select
|
||||
abort = 0
|
||||
while not abort:
|
||||
rd, wr, ex = select.select([self.socket.fileno()],
|
||||
[], [],
|
||||
self.timeout)
|
||||
if rd:
|
||||
self.handle_request()
|
||||
logging._acquireLock()
|
||||
abort = self.abort
|
||||
logging._releaseLock()
|
||||
|
||||
def serve(rcvr, hdlr, port):
|
||||
server = rcvr(port=port, handler=hdlr)
|
||||
global _listener
|
||||
logging._acquireLock()
|
||||
_listener = server
|
||||
logging._releaseLock()
|
||||
server.serve_until_stopped()
|
||||
|
||||
return threading.Thread(target=serve,
|
||||
args=(ConfigSocketReceiver,
|
||||
ConfigStreamHandler, port))
|
||||
|
||||
def stopListening():
|
||||
"""
|
||||
Stop the listening server which was created with a call to listen().
|
||||
"""
|
||||
global _listener
|
||||
if _listener:
|
||||
logging._acquireLock()
|
||||
_listener.abort = 1
|
||||
_listener = None
|
||||
logging._releaseLock()
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
[run]
|
||||
branch = True
|
||||
|
||||
[report]
|
||||
exclude_lines =
|
||||
pragma: no cover
|
||||
def __repr__
|
||||
except ImportError
|
||||
omit =
|
||||
tinycss/tests/speed.py
|
|
@ -1,12 +0,0 @@
|
|||
*.pyc
|
||||
*.c
|
||||
*.so
|
||||
*.egg-info
|
||||
/.coverage
|
||||
/htmlcov
|
||||
/build
|
||||
/dist
|
||||
/.tox
|
||||
/MANIFEST
|
||||
/docs/_build
|
||||
/env
|
|
@ -1,16 +0,0 @@
|
|||
language: python
|
||||
|
||||
python:
|
||||
- "2.7"
|
||||
- "3.3"
|
||||
- "3.4"
|
||||
- "3.5"
|
||||
- "pypy"
|
||||
- "pypy3"
|
||||
|
||||
install:
|
||||
- pip install Cython
|
||||
- pip install --upgrade -e .[test]
|
||||
|
||||
script:
|
||||
- python setup.py test
|
|
@ -1,53 +0,0 @@
|
|||
tinycss changelog
|
||||
=================
|
||||
|
||||
|
||||
Version 0.4
|
||||
-----------
|
||||
|
||||
Released on 2016-09-23.
|
||||
|
||||
* Add an __eq__ operator to Token object.
|
||||
* Support Fonts 3.
|
||||
|
||||
|
||||
|
||||
Version 0.3
|
||||
-----------
|
||||
|
||||
Released on 2012-09-18.
|
||||
|
||||
* Fix a bug when parsing \5c (an escaped antislash.)
|
||||
|
||||
|
||||
|
||||
Version 0.2
|
||||
-----------
|
||||
|
||||
Released on 2012-04-27.
|
||||
|
||||
**Breaking changes:**
|
||||
|
||||
* Remove the ``selectors3`` module. The functionality has moved to the
|
||||
`cssselect <http://packages.python.org/cssselect/>`_ project.
|
||||
* Simplify the API for :func:`~tinycss.make_parser`.
|
||||
|
||||
|
||||
Version 0.1.1
|
||||
-------------
|
||||
|
||||
Released on 2012-04-06.
|
||||
|
||||
Bug fixes:
|
||||
|
||||
* Error handling on exepected end of stylesheet in an at-rule head
|
||||
* Fix the installation on ASCII-only locales
|
||||
|
||||
|
||||
Version 0.1
|
||||
-----------
|
||||
|
||||
Released on 2012-04-05.
|
||||
|
||||
First release. Parser support for CSS 2.1, Seloctors 3, Color 3 and
|
||||
Paged Media 3.
|
|
@ -1,31 +0,0 @@
|
|||
Copyright (c) 2012 by Simon Sapin.
|
||||
|
||||
Some rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* The names of the contributors may not be used to endorse or
|
||||
promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,3 +0,0 @@
|
|||
include README.rst CHANGES LICENSE tox.ini .coveragerc tinycss/speedups.c
|
||||
recursive-include docs *
|
||||
prune docs/_build
|
|
@ -1,47 +0,0 @@
|
|||
Metadata-Version: 1.1
|
||||
Name: tinycss
|
||||
Version: 0.4
|
||||
Summary: tinycss is a complete yet simple CSS parser for Python.
|
||||
Home-page: http://tinycss.readthedocs.io/
|
||||
Author: Simon Sapin
|
||||
Author-email: simon.sapin@exyr.org
|
||||
License: BSD
|
||||
Description: tinycss: CSS parser for Python
|
||||
==============================
|
||||
|
||||
*tinycss* is a complete yet simple CSS parser for Python. It supports the full
|
||||
syntax and error handling for CSS 2.1 as well as some CSS 3 modules:
|
||||
|
||||
* CSS Color 3
|
||||
* CSS Fonts 3
|
||||
* CSS Paged Media 3
|
||||
|
||||
It is designed to be easy to extend for new CSS modules and syntax,
|
||||
and integrates well with cssselect_ for Selectors 3 support.
|
||||
|
||||
Quick facts:
|
||||
|
||||
* Free software: BSD licensed
|
||||
* Compatible with Python 2.7 and 3.x
|
||||
* Latest documentation `on python.org`_
|
||||
* Source, issues and pull requests `on Github`_
|
||||
* Releases `on PyPI`_
|
||||
* Install with ``pip install tinycss``
|
||||
|
||||
.. _cssselect: http://packages.python.org/cssselect/
|
||||
.. _on python.org: http://packages.python.org/tinycss/
|
||||
.. _on Github: https://github.com/SimonSapin/tinycss/
|
||||
.. _on PyPI: http://pypi.python.org/pypi/tinycss
|
||||
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 4 - Beta
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.3
|
||||
Classifier: Programming Language :: Python :: 3.4
|
||||
Classifier: Programming Language :: Python :: 3.5
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
@ -1,26 +0,0 @@
|
|||
tinycss: CSS parser for Python
|
||||
==============================
|
||||
|
||||
*tinycss* is a complete yet simple CSS parser for Python. It supports the full
|
||||
syntax and error handling for CSS 2.1 as well as some CSS 3 modules:
|
||||
|
||||
* CSS Color 3
|
||||
* CSS Fonts 3
|
||||
* CSS Paged Media 3
|
||||
|
||||
It is designed to be easy to extend for new CSS modules and syntax,
|
||||
and integrates well with cssselect_ for Selectors 3 support.
|
||||
|
||||
Quick facts:
|
||||
|
||||
* Free software: BSD licensed
|
||||
* Compatible with Python 2.7 and 3.x
|
||||
* Latest documentation `on python.org`_
|
||||
* Source, issues and pull requests `on Github`_
|
||||
* Releases `on PyPI`_
|
||||
* Install with ``pip install tinycss``
|
||||
|
||||
.. _cssselect: http://packages.python.org/cssselect/
|
||||
.. _on python.org: http://packages.python.org/tinycss/
|
||||
.. _on Github: https://github.com/SimonSapin/tinycss/
|
||||
.. _on PyPI: http://pypi.python.org/pypi/tinycss
|
|
@ -1,24 +0,0 @@
|
|||
div.body {
|
||||
text-align: left;
|
||||
}
|
||||
div.document p, div.document ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
div.document ul ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
.field-name {
|
||||
padding-right: .5em;
|
||||
}
|
||||
table.field-list p, table.field-list ul {
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
table.docutils td, table.docutils th {
|
||||
padding: .2em .5em;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
{% extends "!layout.html" %}
|
||||
{% block extrahead %}
|
||||
<link rel="stylesheet" href="{{ pathto('_static/custom.css', 1) }}" />
|
||||
{% endblock %}
|
|
@ -1 +0,0 @@
|
|||
.. include:: ../CHANGES
|
|
@ -1,252 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# tinycss documentation build configuration file, created by
|
||||
# sphinx-quickstart on Tue Mar 27 14:20:34 2012.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.viewcode', 'sphinx.ext.doctest']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'tinycss'
|
||||
copyright = '2012, Simon Sapin'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
#release = '0.1dev'
|
||||
import re
|
||||
with open(os.path.join(os.path.dirname(__file__), '..',
|
||||
'tinycss', 'version.py')) as init_py:
|
||||
release = re.search("VERSION = '([^']+)'", init_py.read()).group(1)
|
||||
# The short X.Y version.
|
||||
version = release.rstrip('dev')
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#html_theme = 'agogo'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'tinycssdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'tinycss.tex', 'tinycss Documentation',
|
||||
'Simon Sapin', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'tinycss', 'tinycss Documentation',
|
||||
['Simon Sapin'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output ------------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'tinycss', 'tinycss Documentation',
|
||||
'Simon Sapin', 'tinycss', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'http://docs.python.org/': None}
|
|
@ -1,116 +0,0 @@
|
|||
CSS 3 Modules
|
||||
=============
|
||||
|
||||
.. _selectors3:
|
||||
|
||||
Selectors 3
|
||||
-----------
|
||||
|
||||
.. currentmodule:: tinycss.css21
|
||||
|
||||
On :attr:`RuleSet.selector`, the :meth:`~.token_data.TokenList.as_css` method
|
||||
can be used to serialize a selector back to an Unicode string.
|
||||
|
||||
>>> import tinycss
|
||||
>>> stylesheet = tinycss.make_parser().parse_stylesheet(
|
||||
... 'div.error, #root > section:first-letter { color: red }')
|
||||
>>> selector_string = stylesheet.rules[0].selector.as_css()
|
||||
>>> selector_string
|
||||
'div.error, #root > section:first-letter'
|
||||
|
||||
This string can be parsed by cssselect_. The parsed objects have information
|
||||
about pseudo-elements and selector specificity.
|
||||
|
||||
.. _cssselect: http://packages.python.org/cssselect/
|
||||
|
||||
>>> import cssselect
|
||||
>>> selectors = cssselect.parse(selector_string)
|
||||
>>> [s.specificity() for s in selectors]
|
||||
[(0, 1, 1), (1, 0, 2)]
|
||||
>>> [s.pseudo_element for s in selectors]
|
||||
[None, 'first-letter']
|
||||
|
||||
These objects can in turn be translated to XPath expressions. Note that
|
||||
the translation ignores pseudo-elements, you have to account for them
|
||||
somehow or reject selectors with pseudo-elements.
|
||||
|
||||
>>> xpath = cssselect.HTMLTranslator().selector_to_xpath(selectors[1])
|
||||
>>> xpath
|
||||
"descendant-or-self::*[@id = 'root']/section"
|
||||
|
||||
Finally, the XPath expressions can be used with lxml_ to find the matching
|
||||
elements.
|
||||
|
||||
>>> from lxml import etree
|
||||
>>> compiled_selector = etree.XPath(xpath)
|
||||
>>> document = etree.fromstring('''<section id="root">
|
||||
... <section id="head">Title</section>
|
||||
... <section id="content">
|
||||
... Lorem <section id="sub-section">ipsum</section>
|
||||
... </section>
|
||||
... </section>''')
|
||||
>>> [el.get('id') for el in compiled_selector(document)]
|
||||
['head', 'content']
|
||||
|
||||
.. _lxml: http://lxml.de/xpathxslt.html#xpath
|
||||
|
||||
Find more details in the `cssselect documentation`_.
|
||||
|
||||
.. _cssselect documentation: http://packages.python.org/cssselect/
|
||||
|
||||
|
||||
.. module:: tinycss.color3
|
||||
|
||||
Color 3
|
||||
-------
|
||||
|
||||
This module implements parsing for the *<color>* values, as defined in
|
||||
`CSS 3 Color <http://www.w3.org/TR/css3-color/>`_.
|
||||
|
||||
The (deprecated) CSS2 system colors are not supported, but you can
|
||||
easily test for them if you want as they are simple ``IDENT`` tokens.
|
||||
For example::
|
||||
|
||||
if token.type == 'IDENT' and token.value == 'ButtonText':
|
||||
return ...
|
||||
|
||||
All other values types *are* supported:
|
||||
|
||||
* Basic, extended (X11) and transparent color keywords;
|
||||
* 3-digit and 6-digit hexadecimal notations;
|
||||
* ``rgb()``, ``rgba()``, ``hsl()`` and ``hsla()`` functional notations.
|
||||
* ``currentColor``
|
||||
|
||||
This module does not integrate with a parser class. Instead, it provides
|
||||
a function that can parse tokens as found in :attr:`.css21.Declaration.value`,
|
||||
for example.
|
||||
|
||||
.. autofunction:: parse_color
|
||||
.. autofunction:: parse_color_string
|
||||
.. autoclass:: RGBA
|
||||
|
||||
|
||||
.. module:: tinycss.page3
|
||||
|
||||
Paged Media 3
|
||||
-------------
|
||||
|
||||
.. autoclass:: CSSPage3Parser
|
||||
.. autoclass:: MarginRule
|
||||
|
||||
|
||||
.. module:: tinycss.fonts3
|
||||
|
||||
Fonts 3
|
||||
-------
|
||||
|
||||
.. autoclass:: CSSFonts3Parser
|
||||
.. autoclass:: FontFaceRule
|
||||
.. autoclass:: FontFeatureValuesRule
|
||||
.. autoclass:: FontFeatureRule
|
||||
|
||||
|
||||
Other CSS modules
|
||||
-----------------
|
||||
|
||||
To add support for new CSS syntax, see :ref:`extending`.
|
|
@ -1,97 +0,0 @@
|
|||
.. _extending:
|
||||
|
||||
Extending the parser
|
||||
====================
|
||||
|
||||
Modules such as :mod:`.page3` extend the CSS 2.1 parser to add support for
|
||||
CSS 3 syntax.
|
||||
They do so by sub-classing :class:`.css21.CSS21Parser` and overriding/extending
|
||||
some of its methods. If fact, the parser is made of methods in a class
|
||||
(rather than a set of functions) solely to enable this kind of sub-classing.
|
||||
|
||||
tinycss is designed to enable you to have parser subclasses outside of
|
||||
tinycss, without monkey-patching. If however the syntax you added is for a
|
||||
W3C specification, consider including your subclass in a new tinycss module
|
||||
and send a pull request: see :ref:`hacking`.
|
||||
|
||||
|
||||
.. currentmodule:: tinycss.css21
|
||||
|
||||
Example: star hack
|
||||
------------------
|
||||
|
||||
.. _star hack: https://en.wikipedia.org/wiki/CSS_filter#Star_hack
|
||||
|
||||
The `star hack`_ uses invalid declarations that are only parsed by some
|
||||
versions of Internet Explorer. By default, tinycss ignores invalid
|
||||
declarations and logs an error.
|
||||
|
||||
>>> from tinycss.css21 import CSS21Parser
|
||||
>>> css = '#elem { width: [W3C Model Width]; *width: [BorderBox Model]; }'
|
||||
>>> stylesheet = CSS21Parser().parse_stylesheet(css)
|
||||
>>> stylesheet.errors
|
||||
[ParseError('Parse error at 1:35, expected a property name, got DELIM',)]
|
||||
>>> [decl.name for decl in stylesheet.rules[0].declarations]
|
||||
['width']
|
||||
|
||||
If for example a minifier based on tinycss wants to support the star hack,
|
||||
it can by extending the parser::
|
||||
|
||||
>>> class CSSStarHackParser(CSS21Parser):
|
||||
... def parse_declaration(self, tokens):
|
||||
... has_star_hack = (tokens[0].type == 'DELIM' and tokens[0].value == '*')
|
||||
... if has_star_hack:
|
||||
... tokens = tokens[1:]
|
||||
... declaration = super(CSSStarHackParser, self).parse_declaration(tokens)
|
||||
... declaration.has_star_hack = has_star_hack
|
||||
... return declaration
|
||||
...
|
||||
>>> stylesheet = CSSStarHackParser().parse_stylesheet(css)
|
||||
>>> stylesheet.errors
|
||||
[]
|
||||
>>> [(d.name, d.has_star_hack) for d in stylesheet.rules[0].declarations]
|
||||
[('width', False), ('width', True)]
|
||||
|
||||
This class extends the :meth:`~CSS21Parser.parse_declaration` method.
|
||||
It removes any ``*`` delimeter :class:`~.token_data.Token` at the start of
|
||||
a declaration, and adds a ``has_star_hack`` boolean attribute on parsed
|
||||
:class:`Declaration` objects: ``True`` if a ``*`` was removed, ``False`` for
|
||||
“normal” declarations.
|
||||
|
||||
|
||||
Parser methods
|
||||
--------------
|
||||
|
||||
In addition to methods of the user API (see :ref:`parsing`), here
|
||||
are the methods of the CSS 2.1 parser that can be overriden or extended:
|
||||
|
||||
.. automethod:: CSS21Parser.parse_rules
|
||||
.. automethod:: CSS21Parser.read_at_rule
|
||||
.. automethod:: CSS21Parser.parse_at_rule
|
||||
.. automethod:: CSS21Parser.parse_media
|
||||
.. automethod:: CSS21Parser.parse_page_selector
|
||||
.. automethod:: CSS21Parser.parse_declarations_and_at_rules
|
||||
.. automethod:: CSS21Parser.parse_ruleset
|
||||
.. automethod:: CSS21Parser.parse_declaration_list
|
||||
.. automethod:: CSS21Parser.parse_declaration
|
||||
.. automethod:: CSS21Parser.parse_value_priority
|
||||
|
||||
Unparsed at-rules
|
||||
-----------------
|
||||
|
||||
.. autoclass:: AtRule
|
||||
|
||||
|
||||
.. module:: tinycss.parsing
|
||||
|
||||
Parsing helper functions
|
||||
------------------------
|
||||
|
||||
The :mod:`tinycss.parsing` module contains helper functions for parsing
|
||||
tokens into a more structured form:
|
||||
|
||||
.. autofunction:: strip_whitespace
|
||||
.. autofunction:: split_on_comma
|
||||
.. autofunction:: validate_value
|
||||
.. autofunction:: validate_block
|
||||
.. autofunction:: validate_any
|
|
@ -1,117 +0,0 @@
|
|||
.. _hacking:
|
||||
|
||||
Hacking tinycss
|
||||
===============
|
||||
|
||||
.. highlight:: sh
|
||||
|
||||
Bugs and feature requests
|
||||
-------------------------
|
||||
|
||||
Bug reports, feature requests and other issues should got to the
|
||||
`tinycss issue tracker`_ on Github. Any suggestion or feedback is welcome.
|
||||
Please include in full any error message, trackback or other detail that
|
||||
could be helpful.
|
||||
|
||||
.. _tinycss issue tracker: https://github.com/SimonSapin/tinycss/issues
|
||||
|
||||
|
||||
Installing the development version
|
||||
----------------------------------
|
||||
|
||||
First, get the latest git version::
|
||||
|
||||
git clone https://github.com/SimonSapin/tinycss.git
|
||||
cd tinycss
|
||||
|
||||
You will need Cython_ and pytest_. Installing in a virtualenv_ is recommended::
|
||||
|
||||
virtualenv env
|
||||
. env/bin/activate
|
||||
pip install Cython pytest
|
||||
|
||||
.. _Cython: http://cython.org/
|
||||
.. _pytest: http://pytest.org/
|
||||
.. _virtualenv: http://www.virtualenv.org/
|
||||
|
||||
Then, install tinycss in-place with pip’s *editable mode*. This will also
|
||||
build the accelerators::
|
||||
|
||||
pip install -e .
|
||||
|
||||
|
||||
Running the test suite
|
||||
----------------------
|
||||
|
||||
Once you have everything installed (see above), just run pytest from the
|
||||
*tinycss* directory::
|
||||
|
||||
py.test
|
||||
|
||||
If the accelerators are not available for some reason, use the
|
||||
``TINYCSS_SKIP_SPEEDUPS_TESTS`` environment variable::
|
||||
|
||||
TINYCSS_SKIP_SPEEDUPS_TESTS=1 py.test
|
||||
|
||||
If you get test failures on a fresh git clone, something may have gone wrong
|
||||
during the installation. Otherwise, you probably found a bug. Please
|
||||
`report it <#bugs-and-feature-requests>`_.
|
||||
|
||||
|
||||
Test in multiple Python versions with tox
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
tox_ automatically creates virtualenvs for various Python versions and
|
||||
runs the test suite there::
|
||||
|
||||
pip install tox
|
||||
|
||||
Change to the project’s root directory and just run::
|
||||
|
||||
tox
|
||||
|
||||
.. _tox: http://tox.testrun.org/
|
||||
|
||||
tinycss comes with a pre-configured ``tox.ini`` file to test in CPython
|
||||
2.6, 2.7, 3.1 and 3.2 as well as PyPy. You can change that with the ``-e``
|
||||
parameter::
|
||||
|
||||
tox -e py27,py32
|
||||
|
||||
If you use ``--`` in the arguments passed to tox, further arguments
|
||||
are passed to the underlying ``py.test`` command::
|
||||
|
||||
tox -- -x --pdb
|
||||
|
||||
|
||||
Building the documentation
|
||||
--------------------------
|
||||
|
||||
This documentation is made with Sphinx_::
|
||||
|
||||
pip install Sphinx
|
||||
|
||||
.. _Sphinx: http://sphinx.pocoo.org/
|
||||
|
||||
To build the HTML version of the documentation, change to the project’s root
|
||||
directory and run::
|
||||
|
||||
python setup.py build_sphinx
|
||||
|
||||
The built HTML files are in ``docs/_build/html``.
|
||||
|
||||
|
||||
Making a patch and a pull request
|
||||
---------------------------------
|
||||
|
||||
If you would like to see something included in tinycss, please fork
|
||||
`the repository <https://github.com/SimonSapin/tinycss/>`_ on Github
|
||||
and make a pull request. Make sure to include tests for your change.
|
||||
|
||||
|
||||
Mailing-list
|
||||
------------
|
||||
|
||||
tinycss does not have a mailing-list of its own for now, but the
|
||||
`WeasyPrint mailing-list <http://weasyprint.org/community/>`_
|
||||
is appropriate to discuss it.
|
|
@ -1,50 +0,0 @@
|
|||
.. include:: ../README.rst
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
`tinycss is tested <https://travis-ci.org/Kozea/tinycss>`_ on CPython 2.7, 3.3,
|
||||
3.4 and 3.5 as well as PyPy 5.3 and PyPy3 2.4; it should work on any
|
||||
implementation of **Python 2.7 or later version (including 3.x)** of the
|
||||
language.
|
||||
|
||||
Cython_ is used for optional accelerators but is only required for
|
||||
development versions on tinycss.
|
||||
|
||||
.. _Cython: http://cython.org/
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Installing with `pip <http://www.pip-installer.org/>`_ should Just Work:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
pip install tinycss
|
||||
|
||||
The release tarballs contain pre-*cythoned* C files for the accelerators:
|
||||
you will not need Cython to install like this.
|
||||
If the accelerators fail to build for some reason, tinycss will
|
||||
print a warning and fall back to a pure-Python installation.
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
.. Have this page in the sidebar, but do not show a link to itself here:
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
self
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
parsing
|
||||
css3
|
||||
extending
|
||||
hacking
|
||||
changelog
|
|
@ -1,97 +0,0 @@
|
|||
Parsing with tinycss
|
||||
====================
|
||||
|
||||
.. highlight:: python
|
||||
|
||||
Quickstart
|
||||
----------
|
||||
|
||||
Import *tinycss*, make a parser object with the features you want,
|
||||
and parse a stylesheet:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> import tinycss
|
||||
>>> parser = tinycss.make_parser('page3')
|
||||
>>> stylesheet = parser.parse_stylesheet_bytes(b'''@import "foo.css";
|
||||
... p.error { color: red } @lorem-ipsum;
|
||||
... @page tables { size: landscape }''')
|
||||
>>> stylesheet.rules
|
||||
[<ImportRule 1:1 foo.css>, <RuleSet at 2:5 p.error>, <PageRule 3:5 ('tables', None)>]
|
||||
>>> stylesheet.errors
|
||||
[ParseError('Parse error at 2:29, unknown at-rule in stylesheet context: @lorem-ipsum',)]
|
||||
|
||||
You’ll get a :class:`~tinycss.css21.Stylesheet` object which contains
|
||||
all the parsed content as well as a list of encountered errors.
|
||||
|
||||
|
||||
Parsers
|
||||
-------
|
||||
|
||||
Parsers are subclasses of :class:`tinycss.css21.CSS21Parser`. Various
|
||||
subclasses add support for more syntax. You can choose which features to
|
||||
enable by making a new parser class with multiple inheritance, but there
|
||||
is also a convenience function to do that:
|
||||
|
||||
.. module:: tinycss
|
||||
|
||||
.. autofunction:: make_parser
|
||||
|
||||
|
||||
.. module:: tinycss.css21
|
||||
.. _parsing:
|
||||
|
||||
Parsing a stylesheet
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Parser classes have three different methods to parse CSS stylesheet,
|
||||
depending on whether you have a file, a byte string, or an Unicode string.
|
||||
|
||||
.. autoclass:: CSS21Parser
|
||||
:members: parse_stylesheet_file, parse_stylesheet_bytes, parse_stylesheet
|
||||
|
||||
|
||||
Parsing a ``style`` attribute
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. automethod:: CSS21Parser.parse_style_attr
|
||||
|
||||
|
||||
Parsed objects
|
||||
--------------
|
||||
|
||||
These data structures make up the results of the various parsing methods.
|
||||
|
||||
.. autoclass:: tinycss.parsing.ParseError()
|
||||
.. autoclass:: Stylesheet()
|
||||
|
||||
.. note::
|
||||
All subsequent objects have :obj:`line` and :obj:`column` attributes (not
|
||||
repeated every time fore brevity) that indicate where in the CSS source
|
||||
this object was read.
|
||||
|
||||
.. autoclass:: RuleSet()
|
||||
.. autoclass:: ImportRule()
|
||||
.. autoclass:: MediaRule()
|
||||
.. autoclass:: PageRule()
|
||||
.. autoclass:: Declaration()
|
||||
|
||||
|
||||
Tokens
|
||||
------
|
||||
|
||||
Some parts of a stylesheet (such as selectors in CSS 2.1 or property values)
|
||||
are not parsed by tinycss. They appear as tokens instead.
|
||||
|
||||
.. module:: tinycss.token_data
|
||||
|
||||
.. autoclass:: TokenList()
|
||||
:member-order: bysource
|
||||
:members:
|
||||
.. autoclass:: Token()
|
||||
:members:
|
||||
.. autoclass:: tinycss.speedups.CToken()
|
||||
.. autoclass:: ContainerToken()
|
||||
:members:
|
||||
|
||||
.. autoclass:: FunctionToken()
|
|
@ -1,23 +0,0 @@
|
|||
[build_sphinx]
|
||||
source-dir = docs
|
||||
build-dir = docs/_build
|
||||
|
||||
[upload_sphinx]
|
||||
upload-dir = docs/_build/html
|
||||
|
||||
[aliases]
|
||||
test = pytest
|
||||
|
||||
[tool:pytest]
|
||||
addopts = --flake8 --isort --cov --ignore=test/cairosvg_reference
|
||||
norecursedirs = dist .cache .git build *.egg-info .eggs venv cairosvg_reference
|
||||
flake8-ignore = docs/conf.py ALL
|
||||
isort_ignore =
|
||||
docs/conf.py
|
||||
setup.py
|
||||
|
||||
[egg_info]
|
||||
tag_build =
|
||||
tag_date = 0
|
||||
tag_svn_revision = 0
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
import os.path
|
||||
import re
|
||||
import sys
|
||||
from distutils.errors import (
|
||||
CCompilerError, DistutilsExecError, DistutilsPlatformError)
|
||||
from setuptools import Extension, setup
|
||||
|
||||
try:
|
||||
from Cython.Distutils import build_ext
|
||||
import Cython.Compiler.Version
|
||||
CYTHON_INSTALLED = True
|
||||
except ImportError:
|
||||
from distutils.command.build_ext import build_ext
|
||||
CYTHON_INSTALLED = False
|
||||
|
||||
|
||||
ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError)
|
||||
if sys.platform == 'win32' and sys.version_info > (2, 6):
|
||||
# 2.6's distutils.msvc9compiler can raise an IOError when failing to
|
||||
# find the compiler
|
||||
ext_errors += (IOError,)
|
||||
|
||||
|
||||
class BuildFailed(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ve_build_ext(build_ext):
|
||||
# This class allows C extension building to fail.
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
build_ext.run(self)
|
||||
except DistutilsPlatformError:
|
||||
raise BuildFailed
|
||||
|
||||
def build_extension(self, ext):
|
||||
try:
|
||||
build_ext.build_extension(self, ext)
|
||||
except ext_errors:
|
||||
raise BuildFailed
|
||||
|
||||
|
||||
ROOT = os.path.dirname(__file__)
|
||||
with open(os.path.join(ROOT, 'tinycss', 'version.py')) as fd:
|
||||
VERSION = re.search("VERSION = '([^']+)'", fd.read()).group(1)
|
||||
|
||||
with open(os.path.join(ROOT, 'README.rst'), 'rb') as fd:
|
||||
README = fd.read().decode('utf8')
|
||||
|
||||
|
||||
needs_pytest = {'pytest', 'test', 'ptr'}.intersection(sys.argv)
|
||||
pytest_runner = ['pytest-runner'] if needs_pytest else []
|
||||
|
||||
|
||||
def run_setup(with_extension):
|
||||
if with_extension:
|
||||
extension_path = os.path.join('tinycss', 'speedups')
|
||||
if CYTHON_INSTALLED:
|
||||
extension_path += '.pyx'
|
||||
print('Building with Cython %s.' % Cython.Compiler.Version.version)
|
||||
else:
|
||||
extension_path += '.c'
|
||||
if not os.path.exists(extension_path):
|
||||
print("WARNING: Trying to build without Cython, but "
|
||||
"pre-generated '%s' does not seem to be available."
|
||||
% extension_path)
|
||||
else:
|
||||
print('Building without Cython.')
|
||||
kwargs = dict(
|
||||
cmdclass=dict(build_ext=ve_build_ext),
|
||||
ext_modules=[Extension('tinycss.speedups',
|
||||
sources=[extension_path])],
|
||||
)
|
||||
else:
|
||||
kwargs = dict()
|
||||
|
||||
setup(
|
||||
name='tinycss',
|
||||
version=VERSION,
|
||||
url='http://tinycss.readthedocs.io/',
|
||||
license='BSD',
|
||||
author='Simon Sapin',
|
||||
author_email='simon.sapin@exyr.org',
|
||||
description='tinycss is a complete yet simple CSS parser for Python.',
|
||||
long_description=README,
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: BSD License',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: Implementation :: CPython',
|
||||
'Programming Language :: Python :: Implementation :: PyPy',
|
||||
],
|
||||
setup_requires=pytest_runner,
|
||||
tests_require=[
|
||||
'pytest-cov', 'pytest-flake8', 'pytest-isort', 'pytest-runner'],
|
||||
extras_require={'test': (
|
||||
'pytest-runner', 'pytest-cov', 'pytest-flake8', 'pytest-isort')},
|
||||
packages=['tinycss', 'tinycss.tests'],
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
IS_PYPY = hasattr(sys, 'pypy_translation_info')
|
||||
try:
|
||||
run_setup(not IS_PYPY)
|
||||
except BuildFailed:
|
||||
BUILD_EXT_WARNING = ('WARNING: The extension could not be compiled, '
|
||||
'speedups are not enabled.')
|
||||
print('*' * 75)
|
||||
print(BUILD_EXT_WARNING)
|
||||
print('Failure information, if any, is above.')
|
||||
print('Retrying the build without the Cython extension now.')
|
||||
print('*' * 75)
|
||||
|
||||
run_setup(False)
|
||||
|
||||
print('*' * 75)
|
||||
print(BUILD_EXT_WARNING)
|
||||
print('Plain-Python installation succeeded.')
|
||||
print('*' * 75)
|
File diff suppressed because it is too large
Load Diff
|
@ -6,5 +6,5 @@
|
|||
"tetra"
|
||||
],
|
||||
"title": "Portal Auth",
|
||||
"version": "1.7"
|
||||
}
|
||||
"version": "1.8"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue