Skip to content

Commit

Permalink
Add patch CLI (#258)
Browse files Browse the repository at this point in the history
adds a --patch flag to pyhf cls and tests

Additionally adds jsonpatch as a core dependency

c.f. https://github.com/stefankoegl/python-json-patch
  • Loading branch information
lukasheinrich authored and matthewfeickert committed Sep 13, 2018
1 parent a2733c1 commit 75edf5b
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 2 deletions.
11 changes: 9 additions & 2 deletions pyhf/commandline.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
import click
import json
import os
import jsonpatch

from . import readxml
from . import writexml
from .utils import runOnePoint
from .pdf import Model


@click.group(context_settings=dict(help_option_names=['-h', '--help']))
def pyhf():
pass
Expand Down Expand Up @@ -45,8 +47,9 @@ def json2xml(workspace,xmlfile,specroot,dataroot):
@click.argument('workspace', default = '-')
@click.option('--output-file', help='The location of the output json file. If not specified, prints to screen.', default=None)
@click.option('--measurement', default=None)
@click.option('-p','--patch', multiple = True)
@click.option('--qualify-names/--no-qualify-names', default=False)
def cls(workspace, output_file, measurement, qualify_names):
def cls(workspace, output_file, measurement, qualify_names, patch):
specstream = click.open_file(workspace)
d = json.load(specstream)
measurements = d['toplvl']['measurements']
Expand All @@ -63,7 +66,11 @@ def cls(workspace, output_file, measurement, qualify_names):
measurement_index = measurement_names.index(measurement)

log.debug('calculating CLs for measurement {0:s}'.format(measurements[measurement_index]['name']))
p = Model({'channels':d['channels']}, poiname=measurements[measurement_index]['config']['poi'], qualify_names=qualify_names)
spec = {'channels':d['channels']}
for p in patch:
p = jsonpatch.JsonPatch(json.loads(click.open_file(p).read()))
spec = p.apply(spec)
p = Model(spec, poiname=measurements[measurement_index]['config']['poi'], qualify_names=qualify_names)
result = runOnePoint(1.0, sum((d['data'][c['name']] for c in d['channels']),[]) + p.config.auxdata, p)
result = {'CLs_obs': result[-2].tolist()[0], 'CLs_exp': result[-1].ravel().tolist()}
if output_file is None:
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
'tqdm', # for readxml
'six', # for modifiers
'jsonschema>=v3.0.0a2', # for utils, alpha-release for draft 6
'jsonpatch'
],
extras_require = {
'xmlimport': [
Expand Down
39 changes: 39 additions & 0 deletions tests/test_scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,42 @@ def test_import_and_export(tmpdir, script_runner):

command = 'pyhf json2xml {0:s} --specroot {1:s} --dataroot {1:s}'.format(temp.strpath,str(tmpdir))
ret = script_runner.run(*shlex.split(command))
assert ret.success

def test_patch(tmpdir, script_runner):
patch = tmpdir.join('patch.json')

patchcontent = u'''
[{"op": "replace", "path": "/channels/0/samples/0/data", "value": [5,6]}]
'''
patch.write(patchcontent)

temp = tmpdir.join("parsed_output.json")
command = 'pyhf xml2json validation/xmlimport_input/config/example.xml --basedir validation/xmlimport_input/ --output-file {0:s}'.format(temp.strpath)
ret = script_runner.run(*shlex.split(command))

command = 'pyhf cls {0:s} --patch {1:s}'.format(temp.strpath,patch.strpath)
ret = script_runner.run(*shlex.split(command))
assert ret.success
import io
command = 'pyhf cls {0:s} --patch -'.format(temp.strpath,patch.strpath)

pipefile = io.StringIO(patchcontent) #python 2.7 pytest-files are not file-like enough
ret = script_runner.run(*shlex.split(command), stdin = pipefile)
print(ret.stderr)
assert ret.success


def test_patch_fail(tmpdir, script_runner):
patch = tmpdir.join('patch.json')

patch.write('''not,json''')

temp = tmpdir.join("parsed_output.json")
command = 'pyhf xml2json validation/xmlimport_input/config/example.xml --basedir validation/xmlimport_input/ --output-file {0:s}'.format(temp.strpath)
ret = script_runner.run(*shlex.split(command))

command = 'pyhf cls {0:s} --patch {1:s}'.format(temp.strpath,patch.strpath)
ret = script_runner.run(*shlex.split(command))
assert not ret.success

0 comments on commit 75edf5b

Please sign in to comment.