aboutsummaryrefslogtreecommitdiffstats
path: root/pkg_resources.py
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2013-12-08 10:05:17 -0500
committerJason R. Coombs <jaraco@jaraco.com>2013-12-08 10:05:17 -0500
commit5dfdad23a56b4187222274785b6ed9a7996a92e3 (patch)
tree7bca21b8ea5f50f15f3166bf0757875076888553 /pkg_resources.py
parent706797871041656997c422c76db0e834c9aa6b55 (diff)
downloadexternal_python_setuptools-5dfdad23a56b4187222274785b6ed9a7996a92e3.tar.gz
external_python_setuptools-5dfdad23a56b4187222274785b6ed9a7996a92e3.tar.bz2
external_python_setuptools-5dfdad23a56b4187222274785b6ed9a7996a92e3.zip
Encapsulate marker evaluation functionality in a class.
Diffstat (limited to 'pkg_resources.py')
-rw-r--r--pkg_resources.py212
1 files changed, 116 insertions, 96 deletions
diff --git a/pkg_resources.py b/pkg_resources.py
index 31411d22..42b20e3a 100644
--- a/pkg_resources.py
+++ b/pkg_resources.py
@@ -24,6 +24,9 @@ import warnings
import stat
import functools
import pkgutil
+import token
+import symbol
+import operator
from pkgutil import get_importer
try:
@@ -1103,16 +1106,6 @@ def to_filename(name):
"""
return name.replace('-','_')
-_marker_values = {
- 'os_name': lambda: os.name,
- 'sys_platform': lambda: sys.platform,
- 'python_full_version': lambda: sys.version.split()[0],
- 'python_version': lambda:'%s.%s' % (sys.version_info[0], sys.version_info[1]),
- 'platform_version': lambda: _platinfo('version'),
- 'platform_machine': lambda: _platinfo('machine'),
- 'python_implementation': lambda: _platinfo('python_implementation') or _pyimp(),
-}
-
def _platinfo(attr):
try:
import platform
@@ -1130,108 +1123,133 @@ def _pyimp():
else:
return 'CPython'
-def normalize_exception(exc):
- """
- Given a SyntaxError from a marker evaluation, normalize the error message:
- - Remove indications of filename and line number.
- - Replace platform-specific error messages with standard error messages.
- """
- subs = {
- 'unexpected EOF while parsing': 'invalid syntax',
- 'parenthesis is never closed': 'invalid syntax',
+
+class MarkerEvaluation(object):
+ values = {
+ 'os_name': lambda: os.name,
+ 'sys_platform': lambda: sys.platform,
+ 'python_full_version': lambda: sys.version.split()[0],
+ 'python_version': lambda:'%s.%s' % (sys.version_info[0], sys.version_info[1]),
+ 'platform_version': lambda: _platinfo('version'),
+ 'platform_machine': lambda: _platinfo('machine'),
+ 'python_implementation': lambda: _platinfo('python_implementation') or _pyimp(),
}
- exc.filename = None
- exc.lineno = None
- exc.msg = subs.get(exc.msg, exc.msg)
- return exc
+ @classmethod
+ def is_invalid_marker(cls, text):
+ """
+ Validate text as a PEP 426 environment marker; return an exception
+ if invalid or False otherwise.
+ """
+ try:
+ cls.evaluate_marker(text)
+ except SyntaxError:
+ return cls.normalize_exception(sys.exc_info()[1])
+ return False
-def invalid_marker(text):
- """Validate text as a PEP 426 environment marker; return exception or False"""
- try:
- evaluate_marker(text)
- except SyntaxError:
- return normalize_exception(sys.exc_info()[1])
- return False
+ @staticmethod
+ def normalize_exception(exc):
+ """
+ Given a SyntaxError from a marker evaluation, normalize the error message:
+ - Remove indications of filename and line number.
+ - Replace platform-specific error messages with standard error messages.
+ """
+ subs = {
+ 'unexpected EOF while parsing': 'invalid syntax',
+ 'parenthesis is never closed': 'invalid syntax',
+ }
+ exc.filename = None
+ exc.lineno = None
+ exc.msg = subs.get(exc.msg, exc.msg)
+ return exc
+
+ @classmethod
+ def and_test(cls, nodelist):
+ # MUST NOT short-circuit evaluation, or invalid syntax can be skipped!
+ return functools.reduce(operator.and_, [cls.interpret(nodelist[i]) for i in range(1,len(nodelist),2)])
+
+ @classmethod
+ def test(cls, nodelist):
+ # MUST NOT short-circuit evaluation, or invalid syntax can be skipped!
+ return functools.reduce(operator.or_, [cls.interpret(nodelist[i]) for i in range(1,len(nodelist),2)])
+
+ @classmethod
+ def atom(cls, nodelist):
+ t = nodelist[1][0]
+ if t == token.LPAR:
+ if nodelist[2][0] == token.RPAR:
+ raise SyntaxError("Empty parentheses")
+ return cls.interpret(nodelist[2])
+ raise SyntaxError("Language feature not supported in environment markers")
-def evaluate_marker(text, extra=None, _ops={}):
- """
- Evaluate a PEP 426 environment marker on CPython 2.4+.
- Return a boolean indicating the marker result in this environment.
- Raise SyntaxError if marker is invalid.
+ @classmethod
+ def comparison(cls, nodelist):
+ if len(nodelist)>4:
+ raise SyntaxError("Chained comparison not allowed in environment markers")
+ comp = nodelist[2][1]
+ cop = comp[1]
+ if comp[0] == token.NAME:
+ if len(nodelist[2]) == 3:
+ if cop == 'not':
+ cop = 'not in'
+ else:
+ cop = 'is not'
+ try:
+ cop = cls.get_op(cop)
+ except KeyError:
+ raise SyntaxError(repr(cop)+" operator not allowed in environment markers")
+ return cop(cls.evaluate(nodelist[1]), cls.evaluate(nodelist[3]))
+
+ @classmethod
+ def get_op(cls, op):
+ ops = {
+ symbol.test: cls.test,
+ symbol.and_test: cls.and_test,
+ symbol.atom: cls.atom,
+ symbol.comparison: cls.comparison,
+ 'not in': lambda x, y: x not in y,
+ 'in': lambda x, y: x in y,
+ '==': operator.eq,
+ '!=': operator.ne,
+ }
+ if hasattr(symbol, 'or_test'):
+ ops[symbol.or_test] = cls.test
+ return ops[op]
+
+ @classmethod
+ def evaluate_marker(cls, text, extra=None):
+ """
+ Evaluate a PEP 426 environment marker on CPython 2.4+.
+ Return a boolean indicating the marker result in this environment.
+ Raise SyntaxError if marker is invalid.
- This implementation uses the 'parser' module, which is not implemented on
- Jython and has been superseded by the 'ast' module in Python 2.6 and
- later.
- """
+ This implementation uses the 'parser' module, which is not implemented on
+ Jython and has been superseded by the 'ast' module in Python 2.6 and
+ later.
+ """
+ return cls.interpret(parser.expr(text).totuple(1)[1])
- if not _ops:
-
- from token import NAME, STRING
- import token
- import symbol
- import operator
-
- def and_test(nodelist):
- # MUST NOT short-circuit evaluation, or invalid syntax can be skipped!
- return functools.reduce(operator.and_, [interpret(nodelist[i]) for i in range(1,len(nodelist),2)])
-
- def test(nodelist):
- # MUST NOT short-circuit evaluation, or invalid syntax can be skipped!
- return functools.reduce(operator.or_, [interpret(nodelist[i]) for i in range(1,len(nodelist),2)])
-
- def atom(nodelist):
- t = nodelist[1][0]
- if t == token.LPAR:
- if nodelist[2][0] == token.RPAR:
- raise SyntaxError("Empty parentheses")
- return interpret(nodelist[2])
- raise SyntaxError("Language feature not supported in environment markers")
-
- def comparison(nodelist):
- if len(nodelist)>4:
- raise SyntaxError("Chained comparison not allowed in environment markers")
- comp = nodelist[2][1]
- cop = comp[1]
- if comp[0] == NAME:
- if len(nodelist[2]) == 3:
- if cop == 'not':
- cop = 'not in'
- else:
- cop = 'is not'
- try:
- cop = _ops[cop]
- except KeyError:
- raise SyntaxError(repr(cop)+" operator not allowed in environment markers")
- return cop(evaluate(nodelist[1]), evaluate(nodelist[3]))
-
- _ops.update({
- symbol.test: test, symbol.and_test: and_test, symbol.atom: atom,
- symbol.comparison: comparison, 'not in': lambda x,y: x not in y,
- 'in': lambda x,y: x in y, '==': operator.eq, '!=': operator.ne,
- })
- if hasattr(symbol,'or_test'):
- _ops[symbol.or_test] = test
-
- def interpret(nodelist):
+ @classmethod
+ def interpret(cls, nodelist):
while len(nodelist)==2: nodelist = nodelist[1]
try:
- op = _ops[nodelist[0]]
+ op = cls.get_op(nodelist[0])
except KeyError:
raise SyntaxError("Comparison or logical expression expected")
return op(nodelist)
- def evaluate(nodelist):
+ @classmethod
+ def evaluate(cls, nodelist):
while len(nodelist)==2: nodelist = nodelist[1]
kind = nodelist[0]
name = nodelist[1]
- if kind==NAME:
+ if kind==token.NAME:
try:
- op = _marker_values[name]
+ op = cls.values[name]
except KeyError:
raise SyntaxError("Unknown name %r" % name)
return op()
- if kind==STRING:
+ if kind==token.STRING:
s = nodelist[1]
if s[:1] not in "'\"" or s.startswith('"""') or s.startswith("'''") \
or '\\' in s:
@@ -1240,8 +1258,6 @@ def evaluate_marker(text, extra=None, _ops={}):
return s[1:-1]
raise SyntaxError("Language feature not supported in environment markers")
- return interpret(parser.expr(text).totuple(1)[1])
-
def _markerlib_evaluate(text):
"""
Evaluate a PEP 426 environment marker using markerlib.
@@ -1262,7 +1278,11 @@ def _markerlib_evaluate(text):
raise SyntaxError(e.args[0])
return result
-if 'parser' not in globals():
+invalid_marker = MarkerEvaluation.is_invalid_marker
+
+if 'parser' in globals():
+ evaluate_marker = MarkerEvaluation.evaluate_marker
+else:
# fallback to less-complete _markerlib implementation if 'parser' module
# is not available.
evaluate_marker = _markerlib_evaluate