From 9bb4d47bcd83d9edc6c9957aafee2d8e8a2fdb18 Mon Sep 17 00:00:00 2001 From: Alexander Held Date: Mon, 22 Nov 2021 13:13:13 +0100 Subject: [PATCH 1/9] allow skipping workspace validation --- src/pyhf/workspace.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pyhf/workspace.py b/src/pyhf/workspace.py index c64d3d0181..7dcd0b5767 100644 --- a/src/pyhf/workspace.py +++ b/src/pyhf/workspace.py @@ -286,7 +286,7 @@ class Workspace(_ChannelSummaryMixin, dict): valid_joins = ['none', 'outer', 'left outer', 'right outer'] - def __init__(self, spec, **config_kwargs): + def __init__(self, spec, validate: bool = True, **config_kwargs): """Workspaces hold the model, data and measurements.""" spec = copy.deepcopy(spec) super().__init__(spec, channels=spec['channels']) @@ -295,7 +295,8 @@ def __init__(self, spec, **config_kwargs): # run jsonschema validation of input specification against the (provided) schema log.info(f"Validating spec against schema: {self.schema}") - utils.validate(self, self.schema, version=self.version) + if validate: + utils.validate(self, self.schema, version=self.version) self.measurement_names = [] for measurement in self.get('measurements', []): From d36b0ccebe6ba88deee7c557df7b4a5e2fed4713 Mon Sep 17 00:00:00 2001 From: Alexander Held Date: Mon, 22 Nov 2021 13:15:13 +0100 Subject: [PATCH 2/9] only log validation info if validation is performed --- src/pyhf/pdf.py | 2 +- src/pyhf/workspace.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pyhf/pdf.py b/src/pyhf/pdf.py index 5f3827ff60..8cf9f5db89 100644 --- a/src/pyhf/pdf.py +++ b/src/pyhf/pdf.py @@ -657,8 +657,8 @@ def __init__( self.schema = config_kwargs.pop('schema', 'model.json') self.version = config_kwargs.pop('version', None) # run jsonschema validation of input specification against the (provided) schema - log.info(f"Validating spec against schema: {self.schema:s}") if validate: + log.info(f"Validating spec against schema: {self.schema:s}") utils.validate(self.spec, self.schema, version=self.version) # build up our representation of the specification poi_name = config_kwargs.pop('poi_name', 'mu') diff --git a/src/pyhf/workspace.py b/src/pyhf/workspace.py index 7dcd0b5767..0435a89453 100644 --- a/src/pyhf/workspace.py +++ b/src/pyhf/workspace.py @@ -294,8 +294,8 @@ def __init__(self, spec, validate: bool = True, **config_kwargs): self.version = config_kwargs.pop('version', spec.get('version', None)) # run jsonschema validation of input specification against the (provided) schema - log.info(f"Validating spec against schema: {self.schema}") if validate: + log.info(f"Validating spec against schema: {self.schema}") utils.validate(self, self.schema, version=self.version) self.measurement_names = [] From 8087e3b7189a00d36816d96f9a66c9c91e5a61f5 Mon Sep 17 00:00:00 2001 From: Alexander Held Date: Mon, 22 Nov 2021 13:15:39 +0100 Subject: [PATCH 3/9] kwarg typing for validation --- src/pyhf/pdf.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pyhf/pdf.py b/src/pyhf/pdf.py index 8cf9f5db89..b92876c08d 100644 --- a/src/pyhf/pdf.py +++ b/src/pyhf/pdf.py @@ -635,7 +635,12 @@ class Model: """The main pyhf model class.""" def __init__( - self, spec, modifier_set=None, batch_size=None, validate=True, **config_kwargs + self, + spec, + modifier_set=None, + batch_size=None, + validate: bool = True, + **config_kwargs, ): """ Construct a HistFactory Model. From 6255b38b25923d94c46e4acc6ffe407555b7ca04 Mon Sep 17 00:00:00 2001 From: Alexander Held Date: Mon, 22 Nov 2021 13:33:58 +0100 Subject: [PATCH 4/9] propagate validation kwarg from Workspace.build --- src/pyhf/workspace.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pyhf/workspace.py b/src/pyhf/workspace.py index 0435a89453..dd42c9c6cb 100644 --- a/src/pyhf/workspace.py +++ b/src/pyhf/workspace.py @@ -785,7 +785,7 @@ def sorted(cls, workspace): return cls(newspec) @classmethod - def build(cls, model, data, name='measurement'): + def build(cls, model, data, name='measurement', validate: bool = True): """ Build a workspace from model and data. @@ -793,6 +793,7 @@ def build(cls, model, data, name='measurement'): model (~pyhf.pdf.Model): A model to store into a workspace data (:obj:`tensor`): A array holding observations to store into a workspace name (:obj:`str`): The name of the workspace measurement + validate (:obj:`bool`): Whether to validate against a JSON schema Returns: ~pyhf.workspace.Workspace: A new workspace object @@ -824,4 +825,4 @@ def build(cls, model, data, name='measurement'): {'name': k, 'data': list(data[model.config.channel_slices[k]])} for k in model.config.channels ] - return cls(workspace) + return cls(workspace, validate=validate) From 9b2792620c41a90bb6909690fa47611d06641b19 Mon Sep 17 00:00:00 2001 From: Alexander Held Date: Mon, 22 Nov 2021 13:34:38 +0100 Subject: [PATCH 5/9] document validate kwarg for model construction --- src/pyhf/pdf.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pyhf/pdf.py b/src/pyhf/pdf.py index b92876c08d..96ad5a6469 100644 --- a/src/pyhf/pdf.py +++ b/src/pyhf/pdf.py @@ -647,7 +647,9 @@ def __init__( Args: spec (:obj:`jsonable`): The HistFactory JSON specification - batch_size (:obj:`None` or :obj:`int`): Number of simultaneous (batched) Models to compute. + batch_size (:obj:`None` or :obj:`int`): Number of simultaneous (batched) + Models to compute. + validate (:obj:`bool`): Whether to validate against a JSON schema config_kwargs: Possible keyword arguments for the model configuration Returns: From fe77aa0ffc860bd0b96e50b321ef7dc3687ed044 Mon Sep 17 00:00:00 2001 From: Alexander Held Date: Mon, 22 Nov 2021 13:35:09 +0100 Subject: [PATCH 6/9] add test for workspace construction without validation --- tests/test_workspace.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/test_workspace.py b/tests/test_workspace.py index a8f7497c56..152641f65d 100644 --- a/tests/test_workspace.py +++ b/tests/test_workspace.py @@ -898,3 +898,18 @@ def test_wspace_unexpected_keyword_argument(simplemodels_model_data): with pytest.raises(pyhf.exceptions.Unsupported): pyhf.Workspace(spec, abc=True) + + +def test_workspace_without_validation(mocker): + # TODO: refactor if #1709 is accepted / merged + model = pyhf.simplemodels.uncorrelated_background( + signal=[12.0, 11.0], bkg=[50.0, 52.0], bkg_uncertainty=[3.0, 7.0] + ) + data = [51, 48] + + mocker.patch('pyhf.utils.validate') + ws = pyhf.Workspace.build(model, data, validate=False) + assert pyhf.utils.validate.called is False + + pyhf.Workspace(dict(ws), validate=False) + assert pyhf.utils.validate.called is False From 2e69b536870d91378b8d0e668c3f427e952e72d6 Mon Sep 17 00:00:00 2001 From: Matthew Feickert Date: Tue, 23 Nov 2021 00:48:27 -0600 Subject: [PATCH 7/9] Add space to docstring for alignment in Sphinx build --- src/pyhf/pdf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyhf/pdf.py b/src/pyhf/pdf.py index 96ad5a6469..61a8a30ef9 100644 --- a/src/pyhf/pdf.py +++ b/src/pyhf/pdf.py @@ -648,7 +648,7 @@ def __init__( Args: spec (:obj:`jsonable`): The HistFactory JSON specification batch_size (:obj:`None` or :obj:`int`): Number of simultaneous (batched) - Models to compute. + Models to compute. validate (:obj:`bool`): Whether to validate against a JSON schema config_kwargs: Possible keyword arguments for the model configuration From 4d7e86b1b5a6772388d6179f265da5c4d9d3b124 Mon Sep 17 00:00:00 2001 From: Alexander Held Date: Tue, 23 Nov 2021 15:41:09 +0100 Subject: [PATCH 8/9] expand docstring for workspace constructor --- src/pyhf/workspace.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/pyhf/workspace.py b/src/pyhf/workspace.py index dd42c9c6cb..ae38173de0 100644 --- a/src/pyhf/workspace.py +++ b/src/pyhf/workspace.py @@ -287,7 +287,18 @@ class Workspace(_ChannelSummaryMixin, dict): valid_joins = ['none', 'outer', 'left outer', 'right outer'] def __init__(self, spec, validate: bool = True, **config_kwargs): - """Workspaces hold the model, data and measurements.""" + """ + Workspaces hold the model, data and measurements. + + Args: + spec (:obj:`jsonable`): The HistFactory JSON specification + validate (:obj:`bool`): Whether to validate against a JSON schema + config_kwargs: Possible keyword arguments for the workspace configuration + + Returns: + model (:class:`~pyhf.workspace.Workspace`): The Workspace instance + + """ spec = copy.deepcopy(spec) super().__init__(spec, channels=spec['channels']) self.schema = config_kwargs.pop('schema', 'workspace.json') From e737e4da0dd78d1913479bb815a87ad5281e65bc Mon Sep 17 00:00:00 2001 From: Alexander Held Date: Wed, 24 Nov 2021 19:10:00 +0100 Subject: [PATCH 9/9] refactor: use fixture introduced in #1709 --- tests/test_workspace.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/test_workspace.py b/tests/test_workspace.py index 152641f65d..70a10bbaed 100644 --- a/tests/test_workspace.py +++ b/tests/test_workspace.py @@ -900,12 +900,8 @@ def test_wspace_unexpected_keyword_argument(simplemodels_model_data): pyhf.Workspace(spec, abc=True) -def test_workspace_without_validation(mocker): - # TODO: refactor if #1709 is accepted / merged - model = pyhf.simplemodels.uncorrelated_background( - signal=[12.0, 11.0], bkg=[50.0, 52.0], bkg_uncertainty=[3.0, 7.0] - ) - data = [51, 48] +def test_workspace_without_validation(mocker, simplemodels_model_data): + model, data = simplemodels_model_data mocker.patch('pyhf.utils.validate') ws = pyhf.Workspace.build(model, data, validate=False)