Repository: dwavesystems/dimod

Issue:
Change subpackage dimod/io to dimod/serialization or similar to avoid name shadowing issues
Attempting to build dimod with pycharm raises:
```
module 'io' has no attribute 'OpenWrapper'
```

@conta877 

Discussion:

Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 6fc05151..4eaa1a2e 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -81,10 +81,10 @@ jobs:
 
   test-osx-3.7: &osx-tests-template
     macos:
-      xcode: "9.4.1"
+      xcode: "10.1.0"
     environment:
       PYTHON: 3.7.0
-      # HOMEBREW_NO_AUTO_UPDATE: 1  # for 3.7 we need to update homebrew
+      HOMEBREW_NO_AUTO_UPDATE: 1
 
     working_directory: ~/repo
 
diff --git a/MANIFEST.in b/MANIFEST.in
index 2d9b3b94..700a523b 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,4 +1,2 @@
-include dimod/io/bqm_json_schema.json
-include dimod/io/sampleset_json_schema.json
-recursive-include dimod/roof_duality/src *.hpp *.cpp
-recursive-include dimod/roof_duality *.cpp *.pyx
+recursive-include dimod/serialization *.json
+recursive-include dimod/roof_duality *.cpp *.pyx *.hpp
diff --git a/dimod/binary_quadratic_model.py b/dimod/binary_quadratic_model.py
index ebb2a707..563fbc63 100644
--- a/dimod/binary_quadratic_model.py
+++ b/dimod/binary_quadratic_model.py
@@ -1534,7 +1534,7 @@ class BinaryQuadraticModel(abc.Sized, abc.Container, abc.Iterable):
             1 1 1.000000
 
         """
-        import dimod.io.coo as coo
+        import dimod.serialization.coo as coo
 
         if fp is None:
             return coo.dumps(self, vartype_header)
@@ -1600,7 +1600,7 @@ class BinaryQuadraticModel(abc.Sized, abc.Container, abc.Iterable):
             True
 
         """
-        import dimod.io.coo as coo
+        import dimod.serialization.coo as coo
 
         if isinstance(obj, str):
             return coo.loads(obj, cls=cls, vartype=vartype)
@@ -1662,12 +1662,12 @@ class BinaryQuadraticModel(abc.Sized, abc.Container, abc.Iterable):
 
         """
         if use_bytes:
-            from dimod.io.bson import bqm_bson_encoder
+            from dimod.serialization.bson import bqm_bson_encoder
 
             return bqm_bson_encoder(self)
         else:
             # we we don't use bytes then use json encoder
-            from dimod.io.json import DimodEncoder
+            from dimod.serialization.json import DimodEncoder
 
             return DimodEncoder().default(self)
 
@@ -1699,8 +1699,8 @@ class BinaryQuadraticModel(abc.Sized, abc.Container, abc.Iterable):
             :func:`json.loads`, :func:`json.load` JSON deserialization functions
 
         """
-        from dimod.io.json import bqm_decode_hook
-        from dimod.io.bson import bqm_bson_decoder
+        from dimod.serialization.json import bqm_decode_hook
+        from dimod.serialization.bson import bqm_bson_decoder
 
         # try decoding with json
         dct = bqm_decode_hook(obj, cls=cls)
diff --git a/dimod/reference/composites/__init__.py b/dimod/reference/composites/__init__.py
index 23f0d3d5..1d1f4794 100644
--- a/dimod/reference/composites/__init__.py
+++ b/dimod/reference/composites/__init__.py
@@ -16,3 +16,4 @@
 
 from dimod.reference.composites.spin_transform import *
 from dimod.reference.composites.structure import *
+from dimod.reference.composites.fixedvariable import *
diff --git a/dimod/reference/composites/fixedvariable.py b/dimod/reference/composites/fixedvariable.py
new file mode 100644
index 00000000..de61bbd3
--- /dev/null
+++ b/dimod/reference/composites/fixedvariable.py
@@ -0,0 +1,172 @@
+# Copyright 2018 D-Wave Systems Inc.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+# ================================================================================================
+"""
+A composite that fixes the variables provided and removes them from the
+bqm object before sending to its child sampler.
+
+See `Ocean Glossary <https://docs.ocean.dwavesys.com/en/latest/glossary.html>`_ for explanations
+of technical terms in descriptions of Ocean tools.
+"""
+import numpy as np
+
+from dimod.core.composite import ComposedSampler
+from dimod.response import SampleSet
+
+__all__ = ['FixedVariableComposite']
+
+
+class FixedVariableComposite(ComposedSampler):
+    """Composite to fix variables of a problem to provided, assigned values
+
+    Inherits from :class:`dimod.ComposedSampler`.
+
+    Fixes variables of a bqm and modifies linear and quadratic terms
+    accordingly. Returned samples include the fixed variable
+
+    Args:
+       sampler (:obj:`dimod.Sampler`):
+            A dimod sampler
+
+    Examples:
+       This example uses :class:`.FixedVariableComposite` to instantiate a
+       composed sampler that submits a simple Ising problem to a sampler.
+       The composed sampler fixes a variable and modifies linear and quadratic
+       biases according.
+
+       >>> import dimod
+       >>> sampler = dimod.FixedVariableComposite(dimod.ExactSolver())
+       >>> linear = {1: -1.3, 4: -0.5}
+       >>> quadratic = {(1, 4): -0.6}
+       >>> response = sampler.sample_ising(linear,quadratic,fixed_variables={1: -1})
+       >>> print(response.first)  # doctest: +SKIP
+       Sample(sample={1: -1, 4: -1}, energy=1.2000000000000002, num_occurrences=1)
+
+    """
+
+    def __init__(self, child_sampler):
+        self._children = [child_sampler]
+
+    @property
+    def children(self):
+        return self._children
+
+    @property
+    def parameters(self):
+        return self.child.parameters.copy()
+
+    @property
+    def properties(self):
+        return {'child_properties': self.child.properties.copy()}
+
+    def sample(self, bqm, fixed_variables=None, **parameters):
+        """Sample from the provided binary quadratic model.
+
+        Args:
+            bqm (:obj:`dimod.BinaryQuadraticModel`):
+                Binary quadratic model to be sampled from.
+
+            fixed_variables (dict):
+                A dictionary of variable assignments.
+
+            **parameters:
+                Parameters for the sampling method, specified by the child sampler.
+
+        Returns:
+            :obj:`dimod.SampleSet`
+
+        """
+
+        # solve the problem on the child system
+        child = self.child
+        bqm_copy = bqm.copy()
+        if fixed_variables is None:
+            fixed_variables = {}
+
+        bqm_copy.fix_variables(fixed_variables)
+        response = child.sample(bqm_copy, **parameters)
+        return _release_response(response, fixed_variables)
+
+
+def _release_response(response, fixed_variables):
+    """will add the fixed variables and their assigned values to the samples
+       of the response object. Energies of the response do not change since
+       in fixing step the offset is populated by the constant energy shift
+       associated with fixing the variables.
+
+    Args:
+        response (:obj:`.Response`):
+            Response from the bqm with fixed variables.
+
+        fixed_variables (dict):
+            The dict of fixed variables and their assigned values.
+            These are the variables that will be added back to the samples
+            of the response object.
+
+    Returns:
+        :obj:`dimod.SampleSet`:
+            Response for the source binary quadratic model.
+
+    Examples:
+       This example uses :class:`.FixedVariableComposite` to instantiate a
+       composed sampler that submits a simple Ising problem to a sampler.
+       The composed sampler fixes a variable and modifies linear and quadratic
+       biases according.
+
+       >>> import dimod
+       >>> sampler = dimod.FixedVariableComposite(dimod.ExactSolver())
+       >>> h = {'d': -4}
+       >>> J = {('a', 'b'): 1, ('b', 'c'): 1, ('a', 'c'): 1, ('c', 'd'): -.1}
+       >>> bqm = dimod.BinaryQuadraticModel.from_ising(h, J)
+       >>> fixed_variables = dimod.roof_duality.fix_variables(bqm)
+       >>> response = sampler.sample(bqm, fixed_variables=fixed_variables)
+       >>> print(response.first)
+       Sample(sample={'a': -1, 'b': 1, 'c': 1, 'd': 1}, energy=-5.1, num_occurrences=1)
+
+    """
+
+    record = response.record
+    original_variables = list(response.variables)
+    samples = np.asarray(record.sample)
+    energy = np.asarray(record.energy)
+
+    num_samples, num_variables = np.shape(samples)
+    num_variables += len(fixed_variables)
+
+    if len(fixed_variables) > 0:
+        b = []
+        for v, val in fixed_variables.items():
+            original_variables.append(v)
+            b.append([val] * num_samples)
+        samples = np.concatenate((samples, np.transpose(b)), axis=1)
+
+    datatypes = [('sample', np.dtype(np.int8), (num_variables,)),
+                 ('energy', energy.dtype)]
+
+    datatypes.extend((name, record[name].dtype, record[name].shape[1:])
+                     for name in record.dtype.names if
+                     name not in {'sample',
+                                  'energy'})
+
+    data = np.rec.array(np.empty(num_samples, dtype=datatypes))
+
+    data.sample = samples
+    data.energy = energy
+    for name in record.dtype.names:
+        if name not in {'sample', 'energy'}:
+            data[name] = record[name]
+
+    return SampleSet(data, original_variables, response.info,
+                     response.vartype)
diff --git a/dimod/sampleset.py b/dimod/sampleset.py
index 41ff5c1c..db42668a 100644
--- a/dimod/sampleset.py
+++ b/dimod/sampleset.py
@@ -739,7 +739,7 @@ class SampleSet(Iterable, Sized):
             :meth:`~.SampleSet.from_serializable`
 
         """
-        from dimod.io.json import DimodEncoder
+        from dimod.serialization.json import DimodEncoder
         return DimodEncoder().default(self)
 
     @classmethod
@@ -767,7 +767,7 @@ class SampleSet(Iterable, Sized):
             :meth:`~.SampleSet.to_serializable`
 
         """
-        from dimod.io.json import sampleset_decode_hook
+        from dimod.serialization.json import sampleset_decode_hook
         return sampleset_decode_hook(obj, cls=cls)
 
     ###############################################################################################
diff --git a/dimod/io/__init__.py b/dimod/serialization/__init__.py
similarity index 100%
rename from dimod/io/__init__.py
rename to dimod/serialization/__init__.py
diff --git a/dimod/io/bqm_json_schema.json b/dimod/serialization/bqm_json_schema.json
similarity index 100%
rename from dimod/io/bqm_json_schema.json
rename to dimod/serialization/bqm_json_schema.json
diff --git a/dimod/io/bson.py b/dimod/serialization/bson.py
similarity index 100%
rename from dimod/io/bson.py
rename to dimod/serialization/bson.py
diff --git a/dimod/io/coo.py b/dimod/serialization/coo.py
similarity index 100%
rename from dimod/io/coo.py
rename to dimod/serialization/coo.py
diff --git a/dimod/io/json.py b/dimod/serialization/json.py
similarity index 100%
rename from dimod/io/json.py
rename to dimod/serialization/json.py
diff --git a/dimod/io/sampleset_json_schema.json b/dimod/serialization/sampleset_json_schema.json
similarity index 100%
rename from dimod/io/sampleset_json_schema.json
rename to dimod/serialization/sampleset_json_schema.json
diff --git a/docs/reference/ref_samplers_composites.rst b/docs/reference/ref_samplers_composites.rst
index 037255b2..fae35f45 100644
--- a/docs/reference/ref_samplers_composites.rst
+++ b/docs/reference/ref_samplers_composites.rst
@@ -113,3 +113,24 @@ Methods
    :toctree: generated/
 
    StructureComposite.sample
+
+
+
+Fixed Variable Composite
+------------------------
+
+.. automodule:: dimod.reference.composites.fixedvariable
+
+Class
+~~~~~
+
+.. currentmodule:: dimod.reference.composites
+.. autoclass:: FixedVariableComposite
+
+Methods
+~~~~~~~
+
+.. autosummary::
+   :toctree: generated/
+
+   FixedVariableComposite.sample
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 8d22842d..7cb6c4c4 100644
--- a/setup.py
+++ b/setup.py
@@ -45,13 +45,14 @@ extras_require = {'all': ['networkx>=2.0,<3.0',
 
 packages = ['dimod',
             'dimod.core',
-            'dimod.io',
             'dimod.generators',
             'dimod.reference',
             'dimod.reference.composites',
             'dimod.reference.samplers',
             'dimod.roof_duality',
-            'dimod.testing']
+            'dimod.serialization',
+            'dimod.testing',
+            ]
 
 classifiers = [
     'License :: OSI Approved :: Apache Software License',


Test patch:
diff --git a/tests/test_binary_quadratic_model.py b/tests/test_binary_quadratic_model.py
index bc7b52d7..f7421023 100644
--- a/tests/test_binary_quadratic_model.py
+++ b/tests/test_binary_quadratic_model.py
@@ -28,7 +28,7 @@ import jsonschema
 import numpy as np
 
 import dimod
-from dimod.io.json import bqm_json_schema
+from dimod.serialization.json import bqm_json_schema
 
 try:
     import networkx as nx
diff --git a/tests/test_fixedvariablecomposite.py b/tests/test_fixedvariablecomposite.py
new file mode 100644
index 00000000..ceae036f
--- /dev/null
+++ b/tests/test_fixedvariablecomposite.py
@@ -0,0 +1,67 @@
+# Copyright 2018 D-Wave Systems Inc.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+# ================================================================================================
+
+import unittest
+
+import dimod.testing as dtest
+from dimod.vartypes import Vartype
+
+from dimod import BinaryQuadraticModel
+from dimod import FixedVariableComposite, ExactSolver
+from dimod import SampleSet
+
+
+class TestFixedVariableComposite(unittest.TestCase):
+
+    def test_instantiation_smoketest(self):
+        sampler = FixedVariableComposite(ExactSolver())
+
+        dtest.assert_sampler_api(sampler)
+
+    def test_sample(self):
+        bqm = BinaryQuadraticModel(linear={1: -1.3, 4: -0.5},
+                                   quadratic={(1, 4): -0.6},
+                                   offset=0,
+                                   vartype=Vartype.SPIN)
+
+        fixed_variables = {1: -1}
+        sampler = FixedVariableComposite(ExactSolver())
+        response = sampler.sample(bqm, fixed_variables=fixed_variables)
+
+        self.assertEqual(response.first.sample, {4: -1, 1: -1})
+        self.assertAlmostEqual(response.first.energy, 1.2)
+
+    def test_empty_bqm(self):
+        bqm = BinaryQuadraticModel(linear={1: -1.3, 4: -0.5},
+                                   quadratic={(1, 4): -0.6},
+                                   offset=0,
+                                   vartype=Vartype.SPIN)
+
+        fixed_variables = {1: -1, 4: -1}
+        sampler = FixedVariableComposite(ExactSolver())
+        response = sampler.sample(bqm, fixed_variables=fixed_variables)
+        self.assertIsInstance(response, SampleSet)
+
+    def test_empty_fix(self):
+        linear = {1: -1.3, 4: -0.5}
+        quadratic = {(1, 4): -0.6}
+
+        sampler = FixedVariableComposite(ExactSolver())
+        response = sampler.sample_ising(linear, quadratic)
+        self.assertIsInstance(response, SampleSet)
+
+        self.assertEqual(response.first.sample, {4: 1, 1: 1})
+        self.assertAlmostEqual(response.first.energy, -2.4)
diff --git a/tests/test_io_coo.py b/tests/test_serialization_coo.py
similarity index 99%
rename from tests/test_io_coo.py
rename to tests/test_serialization_coo.py
index bc119f6f..9fd94d47 100644
--- a/tests/test_io_coo.py
+++ b/tests/test_serialization_coo.py
@@ -20,7 +20,7 @@ import shutil
 import os
 
 import dimod
-import dimod.io.coo as coo
+import dimod.serialization.coo as coo
 
 
 class TestCOO(unittest.TestCase):
diff --git a/tests/test_io_json.py b/tests/test_serialization_json.py
similarity index 98%
rename from tests/test_io_json.py
rename to tests/test_serialization_json.py
index 9b94bfa6..da185dfb 100644
--- a/tests/test_io_json.py
+++ b/tests/test_serialization_json.py
@@ -20,7 +20,7 @@ import json
 import jsonschema
 
 import dimod
-import dimod.io.json as dson
+import dimod.serialization.json as dson
 
 
 class TestDimodEncoder(unittest.TestCase):