From 795e68f9efada5cecb26f372a82f799dedbc3c17 Mon Sep 17 00:00:00 2001 From: Andrew Halberstadt Date: Fri, 27 Oct 2017 11:45:07 -0400 Subject: [PATCH] Bug 1412136 - Upgrade third_party/python/jsone to version 2.3.1, r=dustin This patch was generated by: $ hg rm third_party/python/jsone/* $ cd third_party/python/jsone $ pip wheel jsone $ unzip MozReview-Commit-ID: BdjFByECFBT --HG-- extra : rebase_source : 4e82bd4ff8cad57579c4d3a5a1547878445dfcab --- third_party/python/json-e/MANIFEST.in | 2 - third_party/python/json-e/PKG-INFO | 10 - third_party/python/json-e/jsone/__init__.py | 10 +- third_party/python/json-e/jsone/builtins.py | 194 ++++++++---------- .../python/json-e/jsone/interpreter.py | 57 +++-- .../python/json-e/jsone/prattparser.py | 4 +- third_party/python/json-e/jsone/render.py | 84 ++++++-- third_party/python/json-e/jsone/shared.py | 38 +++- third_party/python/json-e/setup.cfg | 4 - third_party/python/json-e/setup.py | 24 --- 10 files changed, 221 insertions(+), 206 deletions(-) delete mode 100644 third_party/python/json-e/MANIFEST.in delete mode 100644 third_party/python/json-e/PKG-INFO delete mode 100644 third_party/python/json-e/setup.cfg delete mode 100644 third_party/python/json-e/setup.py diff --git a/third_party/python/json-e/MANIFEST.in b/third_party/python/json-e/MANIFEST.in deleted file mode 100644 index f26b8d5ab6eb..000000000000 --- a/third_party/python/json-e/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -include jsone *.py -recursive-exclude test * diff --git a/third_party/python/json-e/PKG-INFO b/third_party/python/json-e/PKG-INFO deleted file mode 100644 index 02e85933fae4..000000000000 --- a/third_party/python/json-e/PKG-INFO +++ /dev/null @@ -1,10 +0,0 @@ -Metadata-Version: 1.0 -Name: json-e -Version: 2.1.1 -Summary: A data-structure parameterization system written for embedding context in JSON objects -Home-page: https://taskcluster.github.io/json-e/ -Author: Dustin J. Mitchell -Author-email: dustin@mozilla.com -License: MPL2 -Description: UNKNOWN -Platform: UNKNOWN diff --git a/third_party/python/json-e/jsone/__init__.py b/third_party/python/json-e/jsone/__init__.py index 6307e537c2dd..71f7bfcd6e38 100644 --- a/third_party/python/json-e/jsone/__init__.py +++ b/third_party/python/json-e/jsone/__init__.py @@ -1,18 +1,20 @@ from __future__ import absolute_import, print_function, unicode_literals +import datetime import re from .render import renderValue -from .shared import JSONTemplateError, DeleteMarker -from .builtins import builtins +from .shared import JSONTemplateError, DeleteMarker, TemplateError +from . import builtins _context_re = re.compile(r'[a-zA-Z_][a-zA-Z0-9_]*$') def render(template, context): if not all(_context_re.match(c) for c in context): - raise JSONTemplateError('top level keys of context must follow ' + raise TemplateError('top level keys of context must follow ' '/[a-zA-Z_][a-zA-Z0-9_]*/') - full_context = builtins.copy() + full_context = {'now': datetime.datetime.utcnow()} + full_context.update(builtins.build(full_context)) full_context.update(context) rv = renderValue(template, full_context) if rv is DeleteMarker: diff --git a/third_party/python/json-e/jsone/builtins.py b/third_party/python/json-e/jsone/builtins.py index 35c47907b7e2..a2472c3e36ac 100644 --- a/third_party/python/json-e/jsone/builtins.py +++ b/third_party/python/json-e/jsone/builtins.py @@ -1,128 +1,116 @@ from __future__ import absolute_import, print_function, unicode_literals import math -from .interpreter import ExpressionError -from .shared import string, fromNow - -builtins = {} +from .shared import string, to_str, fromNow, JSONTemplateError -def builtin(name, variadic=None, argument_tests=None, minArgs=None): - def wrap(fn): - def bad(reason=None): - raise ExpressionError((reason or 'invalid arguments to {}').format(name)) - if variadic: - def invoke(args): - if minArgs: - if len(args) < minArgs: - bad("too few arguments to {}") - for arg in args: - if not variadic(arg): +class BuiltinError(JSONTemplateError): + pass + + +def build(context): + builtins = {} + + def builtin(name, variadic=None, argument_tests=None, minArgs=None): + def wrap(fn): + def bad(reason=None): + raise BuiltinError((reason or 'invalid arguments to {}').format(name)) + if variadic: + def invoke(*args): + if minArgs: + if len(args) < minArgs: + bad("too few arguments to {}") + for arg in args: + if not variadic(arg): + bad() + return fn(*args) + + elif argument_tests: + def invoke(*args): + if len(args) != len(argument_tests): bad() - return fn(*args) + for t, arg in zip(argument_tests, args): + if not t(arg): + bad() + return fn(*args) - elif argument_tests: - def invoke(args): - if len(args) != len(argument_tests): - bad() - for t, arg in zip(argument_tests, args): - if not t(arg): - bad() - return fn(*args) + else: + def invoke(*args): + return fn(*args) - else: - def invoke(args): - return fn(*args) + builtins[name] = invoke + return fn + return wrap - builtins[name] = invoke - return fn - return wrap + def is_number(v): + return isinstance(v, (int, float)) and not isinstance(v, bool) + def is_string(v): + return isinstance(v, string) -def is_number(v): - return isinstance(v, (int, float)) and not isinstance(v, bool) + def is_string_or_array(v): + return isinstance(v, (string, list)) + def anything(v): + return isinstance(v, (string, int, float, list, dict)) or v is None or callable(v) -def is_string(v): - return isinstance(v, string) + # --- + builtin('min', variadic=is_number, minArgs=1)(min) + builtin('max', variadic=is_number, minArgs=1)(max) + builtin('sqrt', argument_tests=[is_number])(math.sqrt) + builtin('abs', argument_tests=[is_number])(abs) -def is_string_or_array(v): - return isinstance(v, (string, list)) + @builtin('ceil', argument_tests=[is_number]) + def ceil(v): + return int(math.ceil(v)) + @builtin('floor', argument_tests=[is_number]) + def floor(v): + return int(math.floor(v)) -def anything(v): - return isinstance(v, (string, int, float, list, dict)) or v is None or callable(v) + @builtin('lowercase', argument_tests=[is_string]) + def lowercase(v): + return v.lower() -# --- + @builtin('uppercase', argument_tests=[is_string]) + def lowercase(v): + return v.upper() + builtin('len', argument_tests=[is_string_or_array])(len) + builtin('str', argument_tests=[anything])(to_str) -builtin('min', variadic=is_number, minArgs=1)(min) -builtin('max', variadic=is_number, minArgs=1)(max) -builtin('sqrt', argument_tests=[is_number])(math.sqrt) -builtin('abs', argument_tests=[is_number])(abs) + @builtin('strip', argument_tests=[is_string]) + def strip(s): + return s.strip() + @builtin('rstrip', argument_tests=[is_string]) + def rstrip(s): + return s.rstrip() -@builtin('ceil', argument_tests=[is_number]) -def ceil(v): - return int(math.ceil(v)) + @builtin('lstrip', argument_tests=[is_string]) + def lstrip(s): + return s.lstrip() + @builtin('fromNow', variadic=is_string, minArgs=1) + def fromNow_builtin(offset, reference=None): + return fromNow(offset, reference or context.get('now')) -@builtin('floor', argument_tests=[is_number]) -def floor(v): - return int(math.floor(v)) + @builtin('typeof', argument_tests=[anything]) + def typeof(v): + if isinstance(v, bool): + return 'boolean' + elif isinstance(v, string): + return 'string' + elif isinstance(v, (int, float)): + return 'number' + elif isinstance(v, list): + return 'array' + elif isinstance(v, dict): + return 'object' + elif v is None: + return None + elif callable(v): + return 'function' - -@builtin('lowercase', argument_tests=[is_string]) -def lowercase(v): - return v.lower() - - -@builtin('uppercase', argument_tests=[is_string]) -def lowercase(v): - return v.upper() - - -builtin('len', argument_tests=[is_string_or_array])(len) - - -@builtin('str', argument_tests=[anything]) -def to_str(v): - if isinstance(v, bool): - return {True: 'true', False: 'false'}[v] - elif isinstance(v, list): - return ','.join(to_str(e) for e in v) - else: - return str(v) - - -@builtin('str', argument_tests=[anything]) -def to_str(v): - if isinstance(v, bool): - return {True: 'true', False: 'false'}[v] - elif isinstance(v, list): - return ','.join(to_str(e) for e in v) - elif v is None: - return 'null' - else: - return str(v) - - -builtin('fromNow', argument_tests=[is_string])(fromNow) - -@builtin('typeof', argument_tests=[anything]) -def typeof(v): - if isinstance(v, bool): - return 'boolean' - elif isinstance(v, string): - return 'string' - elif isinstance(v, (int, float)): - return 'number' - elif isinstance(v, list): - return 'array' - elif isinstance(v, dict): - return 'object' - elif v is None: - return None - elif callable(v): - return 'function' + return builtins diff --git a/third_party/python/json-e/jsone/interpreter.py b/third_party/python/json-e/jsone/interpreter.py index 6d020af041aa..729d900fc6a1 100644 --- a/third_party/python/json-e/jsone/interpreter.py +++ b/third_party/python/json-e/jsone/interpreter.py @@ -1,7 +1,7 @@ from __future__ import absolute_import, print_function, unicode_literals from .prattparser import PrattParser, infix, prefix -from .shared import JSONTemplateError, string +from .shared import TemplateError, string import operator import json @@ -21,11 +21,8 @@ OPERATORS = { } -class ExpressionError(JSONTemplateError): - - @classmethod - def expectation(cls, operator, expected): - return cls('{} expected {}'.format(operator, expected)) +def expectationError(operator, expected): + return TemplateError('{} expected {}'.format(operator, expected)) class ExpressionEvaluator(PrattParser): @@ -67,7 +64,7 @@ class ExpressionEvaluator(PrattParser): def parse(self, expression): if not isinstance(expression, string): - raise ExpressionError('expression to be evaluated must be a string') + raise TemplateError('expression to be evaluated must be a string') return super(ExpressionEvaluator, self).parse(expression) @prefix('number') @@ -83,14 +80,14 @@ class ExpressionEvaluator(PrattParser): def uminus(self, token, pc): v = pc.parse('unary') if not isNumber(v): - raise ExpressionError.expectation('unary -', 'number') + raise expectationError('unary -', 'number') return -v @prefix("+") def uplus(self, token, pc): v = pc.parse('unary') if not isNumber(v): - raise ExpressionError.expectation('unary +', 'number') + raise expectationError('unary +', 'number') return v @prefix("identifier") @@ -98,7 +95,7 @@ class ExpressionEvaluator(PrattParser): try: return self.context[token.value] except KeyError: - raise ExpressionError('no context value named "{}"'.format(token.value)) + raise TemplateError('no context value named "{}"'.format(token.value)) @prefix("null") def null(self, token, pc): @@ -133,23 +130,23 @@ class ExpressionEvaluator(PrattParser): @infix("+") def plus(self, left, token, pc): if not isinstance(left, (string, int, float)) or isinstance(left, bool): - raise ExpressionError.expectation('+', 'number or string') + raise expectationError('+', 'number or string') right = pc.parse(token.kind) if not isinstance(right, (string, int, float)) or isinstance(right, bool): - raise ExpressionError.expectation('+', 'number or string') + raise expectationError('+', 'number or string') if type(right) != type(left) and \ (isinstance(left, string) or isinstance(right, string)): - raise ExpressionError.expectation('+', 'matching types') + raise expectationError('+', 'matching types') return left + right @infix('-', '*', '/', '**') def arith(self, left, token, pc): op = token.kind if not isNumber(left): - raise ExpressionError.expectation(op, 'number') + raise expectationError(op, 'number') right = pc.parse({'**': '**-right-associative'}.get(op)) if not isNumber(right): - raise ExpressionError.expectation(op, 'number') + raise expectationError(op, 'number') return OPERATORS[op](left, right) @infix("[") @@ -177,19 +174,19 @@ class ExpressionEvaluator(PrattParser): @infix(".") def property_dot(self, left, token, pc): if not isinstance(left, dict): - raise ExpressionError.expectation('.', 'object') + raise expectationError('.', 'object') k = pc.require('identifier').value try: return left[k] except KeyError: - raise ExpressionError('{} not found in {}'.format(k, json.dumps(left))) + raise TemplateError('{} not found in {}'.format(k, json.dumps(left))) @infix("(") def function_call(self, left, token, pc): if not callable(left): - raise ExpressionError('function call', 'callable') + raise TemplateError('function call', 'callable') args = parseList(pc, ',', ')') - return left(args) + return left(*args) @infix('==', '!=', '||', '&&') def equality_and_logic(self, left, token, pc): @@ -203,7 +200,7 @@ class ExpressionEvaluator(PrattParser): right = pc.parse(op) if type(left) != type(right) or \ not (isinstance(left, (int, float, string)) and not isinstance(left, bool)): - raise ExpressionError.expectation(op, 'matching types') + raise expectationError(op, 'matching types') return OPERATORS[op](left, right) @infix("in") @@ -211,16 +208,16 @@ class ExpressionEvaluator(PrattParser): right = pc.parse(token.kind) if isinstance(right, dict): if not isinstance(left, string): - raise ExpressionError.expectation('in-object', 'string on left side') + raise expectationError('in-object', 'string on left side') elif isinstance(right, string): if not isinstance(left, string): - raise ExpressionError.expectation('in-string', 'string on left side') + raise expectationError('in-string', 'string on left side') elif not isinstance(right, list): - raise ExpressionError.expectation('in', 'Array, string, or object on right side') + raise expectationError('in', 'Array, string, or object on right side') try: return left in right except TypeError: - raise ExpressionError.expectation('in', 'scalar value, collection') + raise expectationError('in', 'scalar value, collection') def isNumber(v): @@ -268,22 +265,22 @@ def accessProperty(value, a, b, is_interval): try: return value[a:b] except TypeError: - raise ExpressionError.expectation('[..]', 'integer') + raise expectationError('[..]', 'integer') else: try: return value[a] except IndexError: - raise ExpressionError('index out of bounds') + raise TemplateError('index out of bounds') except TypeError: - raise ExpressionError.expectation('[..]', 'integer') + raise expectationError('[..]', 'integer') if not isinstance(value, dict): - raise ExpressionError.expectation('[..]', 'object, array, or string') + raise expectationError('[..]', 'object, array, or string') if not isinstance(a, string): - raise ExpressionError.expectation('[..]', 'string index') + raise expectationError('[..]', 'string index') try: return value[a] except KeyError: return None - #raise ExpressionError('{} not found in {}'.format(a, json.dumps(value))) + #raise TemplateError('{} not found in {}'.format(a, json.dumps(value))) diff --git a/third_party/python/json-e/jsone/prattparser.py b/third_party/python/json-e/jsone/prattparser.py index 054e71870d73..8575b1a0e5ba 100644 --- a/third_party/python/json-e/jsone/prattparser.py +++ b/third_party/python/json-e/jsone/prattparser.py @@ -2,11 +2,11 @@ from __future__ import absolute_import, print_function, unicode_literals import re from collections import namedtuple -from .shared import JSONTemplateError +from .shared import TemplateError from .six import with_metaclass, viewitems -class SyntaxError(JSONTemplateError): +class SyntaxError(TemplateError): @classmethod def unexpected(cls, got, exp): diff --git a/third_party/python/json-e/jsone/render.py b/third_party/python/json-e/jsone/render.py index 10a02d8d9f11..fac167b5d969 100644 --- a/third_party/python/json-e/jsone/render.py +++ b/third_party/python/json-e/jsone/render.py @@ -2,11 +2,11 @@ from __future__ import absolute_import, print_function, unicode_literals import re import json as json -from .shared import JSONTemplateError, DeleteMarker, string +from .shared import JSONTemplateError, TemplateError, DeleteMarker, string, to_str from . import shared -from . import builtins from .interpreter import ExpressionEvaluator from .six import viewitems +import functools operators = {} @@ -38,8 +38,9 @@ def interpolate(string, context): string = string[mo.end():] parsed, offset = evaluator.parseUntilTerminator(string, '}') if isinstance(parsed, (list, dict)): - raise JSONTemplateError('cannot interpolate array/object: ' + string) - result.append(builtins.to_str(parsed)) + raise TemplateError( + "interpolation of '{}' produced an array or object".format(string[:offset])) + result.append(to_str(parsed)) string = string[offset + 1:] else: # found `$${` result.append('${') @@ -62,7 +63,7 @@ def eval(template, context): def flatten(template, context): value = renderValue(template['$flatten'], context) if not isinstance(value, list): - raise JSONTemplateError('$flatten value must evaluate to an array of arrays') + raise TemplateError('$flatten value must evaluate to an array') def gen(): for e in value: @@ -78,7 +79,7 @@ def flatten(template, context): def flattenDeep(template, context): value = renderValue(template['$flattenDeep'], context) if not isinstance(value, list): - raise JSONTemplateError('$flatten value must evaluate to an array') + raise TemplateError('$flattenDeep value must evaluate to an array') def gen(value): if isinstance(value, list): @@ -94,9 +95,11 @@ def flattenDeep(template, context): @operator('$fromNow') def fromNow(template, context): offset = renderValue(template['$fromNow'], context) + reference = renderValue(template['from'], context) if 'from' in template else context.get('now') + if not isinstance(offset, string): - raise JSONTemplateError("$fromnow expects a string") - return shared.fromNow(offset) + raise TemplateError("$fromNow expects a string") + return shared.fromNow(offset, reference) @operator('$if') @@ -122,13 +125,13 @@ def jsonConstruct(template, context): def let(template, context): variables = renderValue(template['$let'], context) if not isinstance(variables, dict): - raise JSONTemplateError("$let value must evaluate to an object") + raise TemplateError("$let value must evaluate to an object") subcontext = context.copy() subcontext.update(variables) try: in_expression = template['in'] except KeyError: - raise JSONTemplateError("$let operator requires an `in` clause") + raise TemplateError("$let operator requires an `in` clause") return renderValue(in_expression, subcontext) @@ -136,13 +139,13 @@ def let(template, context): def map(template, context): value = renderValue(template['$map'], context) if not isinstance(value, list) and not isinstance(value, dict): - raise JSONTemplateError("$map value must evaluate to an array or object") + raise TemplateError("$map value must evaluate to an array or object") is_obj = isinstance(value, dict) each_keys = [k for k in template if k.startswith('each(')] if len(each_keys) != 1: - raise JSONTemplateError("$map requires exactly one other property, each(..)") + raise TemplateError("$map requires exactly one other property, each(..)") each_key = each_keys[0] each_var = each_key[5:-1] each_template = template[each_key] @@ -171,18 +174,40 @@ def map(template, context): def merge(template, context): value = renderValue(template['$merge'], context) if not isinstance(value, list) or not all(isinstance(e, dict) for e in value): - raise JSONTemplateError("$reverse value must evaluate to an array of objects") + raise TemplateError("$merge value must evaluate to an array of objects") v = dict() for e in value: v.update(e) return v +@operator('$mergeDeep') +def merge(template, context): + value = renderValue(template['$mergeDeep'], context) + if not isinstance(value, list) or not all(isinstance(e, dict) for e in value): + raise TemplateError("$mergeDeep value must evaluate to an array of objects") + def merge(l, r): + if isinstance(l, list) and isinstance(r, list): + return l + r + if isinstance(l, dict) and isinstance(r, dict): + res = l.copy() + for k, v in viewitems(r): + if k in l: + res[k] = merge(l[k], v) + else: + res[k] = v + return res + return r + if len(value) == 0: + return {} + return functools.reduce(merge, value[1:], value[0]) + + @operator('$reverse') def reverse(template, context): value = renderValue(template['$reverse'], context) if not isinstance(value, list): - raise JSONTemplateError("$reverse value must evaluate to an array") + raise TemplateError("$reverse value must evaluate to an array") return list(reversed(value)) @@ -190,7 +215,7 @@ def reverse(template, context): def sort(template, context): value = renderValue(template['$sort'], context) if not isinstance(value, list): - raise JSONTemplateError("$sort value must evaluate to an array") + raise TemplateError("$sort value must evaluate to an array") # handle by(..) if given, applying the schwartzian transform by_keys = [k for k in template if k.startswith('by(')] @@ -208,7 +233,7 @@ def sort(template, context): elif len(by_keys) == 0: to_sort = [(e, e) for e in value] else: - raise JSONTemplateError('only one by(..) is allowed') + raise TemplateError('only one by(..) is allowed') # check types try: @@ -216,9 +241,9 @@ def sort(template, context): except IndexError: return [] if eltype in (list, dict, bool, type(None)): - raise JSONTemplateError('$sort values must be sortable') + raise TemplateError('$sort values must be sortable') if not all(isinstance(e[0], eltype) for e in to_sort): - raise JSONTemplateError('$sorted values must all have the same type') + raise TemplateError('$sorted values must all have the same type') # unzip the schwartzian transform return list(e[1] for e in sorted(to_sort)) @@ -232,7 +257,7 @@ def renderValue(template, context): matches = [k for k in template if k in operators] if matches: if len(matches) > 1: - raise JSONTemplateError("only one operator allowed") + raise TemplateError("only one operator allowed") return operators[matches[0]](template, context) def updated(): @@ -241,14 +266,29 @@ def renderValue(template, context): k = k[1:] else: k = interpolate(k, context) - v = renderValue(v, context) + try: + v = renderValue(v, context) + except JSONTemplateError as e: + if re.match('^[a-zA-Z][a-zA-Z0-9]*$', k): + e.add_location('.{}'.format(k)) + else: + e.add_location('[{}]'.format(json.dumps(k))) + raise if v is not DeleteMarker: yield k, v return dict(updated()) elif isinstance(template, list): - rendered = (renderValue(e, context) for e in template) - return [e for e in rendered if e is not DeleteMarker] + def updated(): + for i, e in enumerate(template): + try: + v = renderValue(e, context) + if v is not DeleteMarker: + yield v + except JSONTemplateError as e: + e.add_location('[{}]'.format(i)) + raise + return list(updated()) else: return template diff --git a/third_party/python/json-e/jsone/shared.py b/third_party/python/json-e/jsone/shared.py index 83d3945e4786..06dd89822e00 100644 --- a/third_party/python/json-e/jsone/shared.py +++ b/third_party/python/json-e/jsone/shared.py @@ -3,15 +3,28 @@ from __future__ import absolute_import, print_function, unicode_literals import re import datetime -# this will be overridden in tests -utcnow = datetime.datetime.utcnow - class DeleteMarker: pass class JSONTemplateError(Exception): + def __init__(self, message): + super(JSONTemplateError, self).__init__(message) + self.location = [] + + def add_location(self, loc): + self.location.insert(0, loc) + + def __str__(self): + location = ' at template' + ''.join(self.location) + return "{}{}: {}".format( + self.__class__.__name__, + location if self.location else '', + self.args[0]) + + +class TemplateError(JSONTemplateError): pass @@ -28,7 +41,7 @@ FROMNOW_RE = re.compile(''.join([ ])) -def fromNow(offset): +def fromNow(offset, reference): # copied from taskcluster-client.py # We want to handle past dates as well as future future = True @@ -72,12 +85,27 @@ def fromNow(offset): seconds=seconds, ) - return stringDate(utcnow() + delta if future else utcnow() - delta) + if isinstance(reference, str): + reference = datetime.datetime.strptime(reference, '%Y-%m-%dT%H:%M:%S.%fZ') + elif reference is None: + reference = datetime.datetime.utcnow() + return stringDate(reference + delta if future else reference - delta) datefmt_re = re.compile(r'(\.[0-9]{3})[0-9]*(\+00:00)?') +def to_str(v): + if isinstance(v, bool): + return {True: 'true', False: 'false'}[v] + elif isinstance(v, list): + return ','.join(to_str(e) for e in v) + elif v is None: + return 'null' + else: + return str(v) + + def stringDate(date): # Convert to isoFormat string = date.isoformat() diff --git a/third_party/python/json-e/setup.cfg b/third_party/python/json-e/setup.cfg deleted file mode 100644 index 8bfd5a12f85b..000000000000 --- a/third_party/python/json-e/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[egg_info] -tag_build = -tag_date = 0 - diff --git a/third_party/python/json-e/setup.py b/third_party/python/json-e/setup.py deleted file mode 100644 index 048567558c82..000000000000 --- a/third_party/python/json-e/setup.py +++ /dev/null @@ -1,24 +0,0 @@ -import json -import os -from setuptools import setup, find_packages - -package_json = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'package.json') -with open(package_json) as f: - version = json.load(f)['version'] - -setup(name='json-e', - version=version, - description='A data-structure parameterization system written for embedding context in JSON objects', - author='Dustin J. Mitchell', - url='https://taskcluster.github.io/json-e/', - author_email='dustin@mozilla.com', - packages=['jsone'], - test_suite='nose.collector', - license='MPL2', - tests_require=[ - "hypothesis", - "nose", - "PyYAML", - "python-dateutil", - ] -)