Repository: dr-leo/pandaSDMX (python)

Issue:
Rename `open_file()` to `read_sdmx()`
As raised by @dr-leo via e-mail:

> I feel strongly, e.g., that 'open_file' should be renamed to 'read_sdmx' as it is more explicit and consistent with similar Pandas functions.

Pull request description:
Rename `open_file()` to `read_sdmx()`
Closes #87.

Patch:
diff --git a/doc/howto.rst b/doc/howto.rst
index 2d52fa9..71fa79b 100644
--- a/doc/howto.rst
+++ b/doc/howto.rst
@@ -43,7 +43,7 @@ Convert SDMX data to other formats
 `Pandas <https://pandas.pydata.org>`_ supports output to `many popular file formats <http://pandas.pydata.org/pandas-docs/stable/user_guide/io.html>`_.
 Call these methods on the :class:`pandas.DataFrame` objects returned by :meth:`pandasdmx.to_pandas`. For instance::
 
-    msg = sdmx.open_file('data.xml')
+    msg = sdmx.read_sdmx('data.xml')
     sdmx.to_pandas(msg).to_excel('data.xlsx')
 
 
@@ -65,11 +65,11 @@ pandaSDMX can also be used with `odo <https://github.com/blaze/odo>`_ by registe
 
     @odo.discover.register(PandaSDMX)
     def _discover(obj):
-        return odo.discover(sdmx.to_pandas(sdmx.open_file(obj.uri)))
+        return odo.discover(sdmx.to_pandas(sdmx.read_sdmx(obj.uri)))
 
     @odo.convert.register(pd.DataFrame, PandaSDMX)
     def _convert(obj, **kwargs):
-        msg = sdmx.open_file(obj.uri)
+        msg = sdmx.read_sdmx(obj.uri)
         return sdxm.to_pandas(msg, **keyfilter(op.contains(keywords(write)),
                                                kwargs))
 
diff --git a/doc/walkthrough.rst b/doc/walkthrough.rst
index e0e0b68..1aadd1a 100644
--- a/doc/walkthrough.rst
+++ b/doc/walkthrough.rst
@@ -94,11 +94,11 @@ SDMX messages in databases such as MongoDB, Redis or SQLite.  See the
 Load messages from file
 :::::::::::::::::::::::
 
-:meth:`open_file` can be used to load SDMX messages from local files:
+:meth:`read_sdmx` can be used to load SDMX messages from local files:
 
 .. ipython:: python
 
-    sdmx.open_file('saved_message.xml')
+    sdmx.read_sdmx('saved_message.xml')
 
 Obtain and explore metadata
 ---------------------------
diff --git a/pandasdmx/__init__.py b/pandasdmx/__init__.py
index 677c546..b2c01f6 100644
--- a/pandasdmx/__init__.py
+++ b/pandasdmx/__init__.py
@@ -1,4 +1,4 @@
-from pandasdmx.api import Request, open_file, read_url
+from pandasdmx.api import Request, read_sdmx, read_url
 from pandasdmx.source import add_source, list_sources
 from pandasdmx.writer import write as to_pandas
 import logging
@@ -7,7 +7,7 @@ __all__ = [
     'Request',
     'add_source',
     'list_sources',
-    'open_file',
+    'read_sdmx',
     'read_url',
     'to_pandas',
     ]
diff --git a/pandasdmx/api.py b/pandasdmx/api.py
index 60e179b..74223f0 100644
--- a/pandasdmx/api.py
+++ b/pandasdmx/api.py
@@ -420,7 +420,7 @@ class Request:
             return list(all_keys)
 
 
-def open_file(filename_or_obj, format=None):
+def read_sdmx(filename_or_obj, format=None):
     """Load a SDMX-ML or SDMX-JSON message from a file or file-like object.
 
     Parameters


Test patch:
diff --git a/tests/__init__.py b/tests/__init__.py
index c4c1cf6..deaeb69 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -103,8 +103,8 @@ class MessageTest:
 
     @pytest.fixture(scope='class')
     def msg(self):
-        import pandasdmx
-        return pandasdmx.open_file(self.path / self.filename)
+        import pandasdmx as sdmx
+        return sdmx.read_sdmx(self.path / self.filename)
 
 
 # thanks to xarray
diff --git a/tests/test_api.py b/tests/test_api.py
index 8dd7a3e..b88d2c1 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -8,7 +8,7 @@ import pytest
 from . import specimen
 
 
-def test_open_file(tmp_path):
+def test_read_sdmx(tmp_path):
     # Copy the file to a temporary file with an urecognizable suffix
     target = tmp_path / 'foo.badsuffix'
     with specimen('exr-flat.json', opened=False) as original:
@@ -18,20 +18,20 @@ def test_open_file(tmp_path):
     exc = ("cannot identify SDMX message format from file name 'foo.badsuffix'"
            "; use  format='...'")
     with pytest.raises(RuntimeError, match=exc):
-        sdmx.open_file(target)
+        sdmx.read_sdmx(target)
 
     # Using the format= kwarg suppresses the error
-    sdmx.open_file(target, format='JSON')
+    sdmx.read_sdmx(target, format='JSON')
 
     # Format can be inferred from an already-open file without extension
     with specimen('exr-flat.json') as f:
-        sdmx.open_file(f)
+        sdmx.read_sdmx(f)
 
     # Exception raised when the file contents don't allow to guess the format
     bad_file = StringIO('#! neither XML nor JSON')
     exc = "cannot infer SDMX message format from '#! ne..'"
     with pytest.raises(RuntimeError, match=exc):
-        sdmx.open_file(bad_file)
+        sdmx.read_sdmx(bad_file)
 
 
 
diff --git a/tests/test_dataset.py b/tests/test_dataset.py
index da25e36..510c04d 100644
--- a/tests/test_dataset.py
+++ b/tests/test_dataset.py
@@ -1,6 +1,6 @@
 import pandas as pd
 import pandas.testing as pdt
-import pandasdmx
+import pandasdmx as sdmx
 from pandasdmx import message, model
 
 from . import MessageTest, test_data_path
@@ -17,10 +17,10 @@ class TestGenericFlatDataSet(DataMessageTest):
         assert isinstance(msg, message.DataMessage)
 
     def test_header_attributes(self, msg):
-        # CHANGED: the internal reference ID of the StructureUsage and the
-        #          maintained ID of the DataStructureDefinition it references
-        #          are both available
+        # Internal reference of the StructureUsage is available
         assert msg.dataflow.id == 'STR1'
+
+        # Maintained ID of the DataStructureDefinition is available
         assert msg.structure.id == 'ECB_EXR_NG'
         assert msg.observation_dimension == model.AllDimensions
 
@@ -35,31 +35,23 @@ class TestGenericFlatDataSet(DataMessageTest):
 
         o0 = data.obs[0]
 
-        # REMOVE? What is this measuring?
-        # - Not the length of the Observation.key—that is 6.
-        # - Something else?
-        # assert len(o0) ==  3
-
         assert isinstance(o0.key, model.Key)
         assert o0.key.FREQ == 'M'
         assert o0.key.CURRENCY == 'CHF'
         assert o0.value == '1.3413'
 
-        # REMOVE: duck typing → test for desired behaviour of attrib instead
-        # assert isinstance(o0.attrib, tuple)
-
         assert o0.attrib.OBS_STATUS == 'A'
         assert o0.attrib.DECIMALS == '4'
 
     def test_to_pandas(self, msg):
         # Single data series is converted to pd.Series
-        data_series = pandasdmx.to_pandas(msg.data[0])
+        data_series = sdmx.to_pandas(msg.data[0])
         assert isinstance(data_series, pd.Series)
 
         # When len(msg.data) is 1, the data series in a single Dataset are
         # unwrapped automatically
         assert len(msg.data) == 1
-        data_series2 = pandasdmx.to_pandas(msg.data)  # NB no '[0]' index
+        data_series2 = sdmx.to_pandas(msg.data)  # NB no '[0]' index
         pdt.assert_series_equal(data_series, data_series2)
 
 
@@ -74,8 +66,7 @@ class TestGenericSeriesDataSet(DataMessageTest):
     def test_generic_obs(self, msg):
         data = msg.data[0]
 
-        # Number of observations in the dataset
-        # CHANGED: obs gives access to all observations in the data set
+        # Number of observations in the entire dataset
         assert len(data.obs) == 12
 
         # Number of series in the dataset
@@ -84,9 +75,6 @@ class TestGenericSeriesDataSet(DataMessageTest):
         # Access to series by index
         s3 = data.series[3]
 
-        # REMOVE: Series is not in the IM
-        # assert isinstance(s3, model.Series)
-
         # Observations in series have .series_key with correct length & values
         assert isinstance(s3[0].series_key, model.Key)
         assert len(s3[0].series_key) == 5
@@ -101,16 +89,10 @@ class TestGenericSeriesDataSet(DataMessageTest):
         # Series observations can be reversed, and accessed by index
         o0 = list(reversed(s3))[2]
 
-        # REMOVE? see TestGenericFlatDataSet.test_generic_obs
-        # assert len(o0) == 3
-
         # Series observations have expected value
         assert o0.dim == '2010-08'
         assert o0.value == '1.2894'
 
-        # REMOVE: see TestGenericFlatDataSet.test_generic_obs
-        # assert isinstance(o0.attrib, tuple)
-
         assert o0.attrib.OBS_STATUS == 'A'
 
     def test_pandas(self, msg):
@@ -123,7 +105,7 @@ class TestGenericSeriesDataSet(DataMessageTest):
 
         # Convert the observations for one SeriesKey to a pd.Series
         s3_key = series_keys[3]
-        s3 = pandasdmx.to_pandas(data.series[s3_key])
+        s3 = sdmx.to_pandas(data.series[s3_key])
         assert isinstance(s3, pd.Series)
 
         # Test a particular value
@@ -133,7 +115,7 @@ class TestGenericSeriesDataSet(DataMessageTest):
         assert len(s3.index.names) == 6
 
         # Convert again, with attributes
-        pd_data = pandasdmx.to_pandas(data, attributes='osgd')
+        pd_data = sdmx.to_pandas(data, attributes='osgd')
 
         # Select one SeriesKey's data out of the DataFrame
         keys, levels = zip(*[(kv.value, kv.id) for kv in s3_key])
@@ -167,18 +149,18 @@ class TestGenericSeriesDataSet(DataMessageTest):
         assert len(data.series) == 4
 
         # Conversion without attributes gives a Series with a MultiIndex
-        s_all = pandasdmx.to_pandas(data, attributes='')
+        s_all = sdmx.to_pandas(data, attributes='')
         assert isinstance(s_all, pd.Series)
         assert isinstance(s_all.index, pd.MultiIndex)
 
         # Single series can be converted
-        s3 = pandasdmx.to_pandas(data.series[3], attributes='')
+        s3 = sdmx.to_pandas(data.series[3], attributes='')
         assert isinstance(s3, pd.Series)
         assert s3[0] == 1.2894
 
         # Conversion with attribute gives a DataFrame with attribute columns
         # and a MultiIndex
-        df = pandasdmx.to_pandas(data, attributes='ogsd')
+        df = sdmx.to_pandas(data, attributes='ogsd')
         assert isinstance(df, pd.DataFrame)
         assert isinstance(df.index, pd.MultiIndex)
         assert all(df.columns == ['value', 'OBS_STATUS', 'CONF_STATUS_OBS',
@@ -186,7 +168,7 @@ class TestGenericSeriesDataSet(DataMessageTest):
                                   'COLL_METHOD', 'TITLE'])
 
         # Single series can be converted with attributes
-        s3 = pandasdmx.to_pandas(data.series[3], attributes='ogsd')
+        s3 = sdmx.to_pandas(data.series[3], attributes='ogsd')
         assert isinstance(s3, pd.DataFrame)
         assert isinstance(s3.index, pd.MultiIndex)
 
@@ -197,14 +179,14 @@ class TestGenericSeriesDataSet(DataMessageTest):
         assert s3.iloc[0, :]['OBS_STATUS'] == 'A'
 
     def test_write2pandas(self, msg):
-        df = pandasdmx.to_pandas(msg, attributes='')
+        df = sdmx.to_pandas(msg, attributes='')
 
         assert isinstance(df, pd.Series)
 
         assert df.shape == (12,)
 
         # with metadata
-        df = pandasdmx.to_pandas(msg, attributes='osgd')
+        df = sdmx.to_pandas(msg, attributes='osgd')
         df, mdf = df.iloc[:, 0], df.iloc[:, 1:]
         assert mdf.shape == (12, 7)
         assert mdf.iloc[1].OBS_STATUS == 'A'
@@ -216,14 +198,13 @@ class TestGenericSeriesDataSet2(DataMessageTest):
     def test_header_attributes(self, msg):
         assert msg.dataflow.id == 'STR1'
         assert msg.structure.id == 'ECB_EXR_NG'
-        # CHANGED: observation_dimension can be 1-or-more Dimensions; must
-        #          compare with an iterable of Dimension or Dimension IDs.
+
+        # Observation dimension is 1 or more Dimensions
         assert msg.observation_dimension == ['TIME_PERIOD']
 
     def test_generic_obs(self, msg):
         data = msg.data[0]
 
-        # CHANGED: obs gives access to all observations in the data set
         assert len(data.obs) == 12
 
         assert len(data.series) == 4
@@ -231,12 +212,10 @@ class TestGenericSeriesDataSet2(DataMessageTest):
         assert len(series_list) == 4
         s3 = series_list[3]
 
-        # REMOVE: Series is not in the IM
-        # assert isinstance(s3, model.Series)
-
-        # CHANGED: access SeriesKey from Observations in the series, or keys of
-        #          DataSet.series.
+        # SeriesKey can be accessed by reference from each Observation in the
+        # series
         assert isinstance(s3[0].series_key, model.Key)
+
         assert len(s3[0].series_key) == 5
         assert s3[0].key.CURRENCY == 'USD'
         assert s3[0].attrib.DECIMALS == '4'
@@ -244,19 +223,13 @@ class TestGenericSeriesDataSet2(DataMessageTest):
         assert len(obs_list) == 3
         o0 = obs_list[2]
 
-        # REMOVE: see TestGenericFlatDataSet.test_generic_obs
-        # assert len(o0) == 3
-
         assert o0.dim == '2010-08'
         assert o0.value == '1.2894'
 
-        # REMOVE: see TestGenericFlatDataSet.test_generic_obs
-        # assert isinstance(o0.attrib, tuple)
-
         assert o0.attrib.OBS_STATUS == 'A'
 
     def test_dataframe(self, msg):
-        df = pandasdmx.to_pandas(msg.data[0]).iloc[::-1]
+        df = sdmx.to_pandas(msg.data[0]).iloc[::-1]
 
         assert isinstance(df, pd.Series)
 
@@ -270,11 +243,11 @@ class TestGenericSeriesData_SiblingGroup_TS(DataMessageTest):
     def test_groups(self, msg):
         data = msg.data[0]
 
-        # CHANGED: groups → group; list() is no longer required
+        # Data have expected number of groups and series
         assert len(data.group) == 4
         assert len(data.series) == 4
 
-        # CHANGED: access GroupKeys from keys of DataSet.group
+        # GroupKeys can be retrieved from keys of DataSet.group
         g2_key, g2 = list(data.group.items())[2]
         assert g2_key.CURRENCY == 'JPY'
         assert g2[0].attrib.TITLE == ('ECB reference exchange rate, Japanese '
@@ -285,9 +258,6 @@ class TestGenericSeriesData_SiblingGroup_TS(DataMessageTest):
         g_attrib = s.group_attrib
         assert len(g_attrib) == 1
 
-        # REMOVE: duck typing → test for desired behaviour of attrib instead
-        # assert isinstance(g_attrib, tuple)
-
 
 class TestGenericSeriesData_RateGroup_TS(DataMessageTest):
     path = test_data_path / 'exr' / 'ecb_exr_rg' / 'generic'
@@ -296,11 +266,10 @@ class TestGenericSeriesData_RateGroup_TS(DataMessageTest):
     def test_groups(self, msg):
         data = msg.data[0]
 
-        # CHANGED: groups → group; list() is no longer required
         assert len(data.group) == 5
         assert len(data.series) == 4
 
-        # CHANGED: .group is DictLike; retrieve the key and obs separately
+        # .group is DictLike; retrieve the key and obs separately
         g2_key, g2 = list(data.group.items())[2]
         assert g2_key.CURRENCY == 'GBP'
         assert g2_key.attrib.TITLE == ('ECB reference exchange rate, U.K. '
@@ -310,11 +279,8 @@ class TestGenericSeriesData_RateGroup_TS(DataMessageTest):
         g_attrib = s.group_attrib
         assert len(g_attrib) == 5
 
-        # REMOVE: see TestGenericFlatDataSet.test_generic_obs
-        # assert isinstance(g_attrib, tuple)
-
     def test_footer(self):
-        f = pandasdmx.open_file(test_data_path / 'estat' / 'footer.xml').footer
+        f = sdmx.read_sdmx(test_data_path / 'estat' / 'footer.xml').footer
         assert f.code == 413
         assert f.severity == 'Infomation'
         assert str(f.text[1]).startswith('http')
diff --git a/tests/test_dataset_bare.py b/tests/test_dataset_bare.py
index e9c7d43..d025491 100644
--- a/tests/test_dataset_bare.py
+++ b/tests/test_dataset_bare.py
@@ -1,4 +1,4 @@
-import pandasdmx
+import pandasdmx as sdmx
 from pandasdmx.message import (
     Header,
     DataMessage,
@@ -52,16 +52,16 @@ def test_flat():
     msg.data.append(ds)
 
     # Write to pd.Dataframe
-    df1 = pandasdmx.to_pandas(msg)
+    df1 = sdmx.to_pandas(msg)
 
-    ref = pandasdmx.open_file(test_data_path / 'json' / 'exr-flat.json')
-    df2 = pandasdmx.to_pandas(ref)
+    ref = sdmx.read_sdmx(test_data_path / 'json' / 'exr-flat.json')
+    df2 = sdmx.to_pandas(ref)
 
     assert_pd_equal(df1, df2)
 
 
 def test_bare_series():
-    ref = pandasdmx.open_file(test_data_path / 'exr' / 'ecb_exr_ng' /
-                              'generic' / 'ecb_exr_ng_ts.xml')
+    sdmx.read_sdmx(test_data_path / 'exr' / 'ecb_exr_ng' /
+                   'generic' / 'ecb_exr_ng_ts.xml')
 
     # TODO generate the series and observations
diff --git a/tests/test_dsd.py b/tests/test_dsd.py
index e3e7cbb..d13e186 100644
--- a/tests/test_dsd.py
+++ b/tests/test_dsd.py
@@ -62,7 +62,7 @@ class test_dsd_common(MessageTest):
 
 
 def test_exr_constraints():
-    m = sdmx.open_file(test_data_path / 'exr_flow.xml')
+    m = sdmx.read_sdmx(test_data_path / 'exr_flow.xml')
     ECB_EXR1 = m.structure['ECB_EXR1']
 
     # Test DimensionDescriptor
diff --git a/tests/test_insee.py b/tests/test_insee.py
index f3a136b..d45a9d7 100644
--- a/tests/test_insee.py
+++ b/tests/test_insee.py
@@ -1,6 +1,6 @@
 from collections import OrderedDict
 
-import pandasdmx
+import pandasdmx as sdmx
 from pandasdmx import Request
 import pytest
 
@@ -41,32 +41,31 @@ class TestINSEE:
     def test_load_dataset(self, req):
         dataset_code = 'IPI-2010-A21'
 
-        '''load all dataflows'''
-        dataflows_response = pandasdmx.open_file(DATAFLOW_FP)
+        # Load all dataflows
+        dataflows_response = sdmx.read_sdmx(DATAFLOW_FP)
         dataflows = dataflows_response.dataflow
 
         assert len(dataflows) == 663
         assert dataset_code in dataflows
 
-        '''load datastructure for current dataset_code'''
+        # Load datastructure for current dataset_code
         fp_datastructure = DATASETS[dataset_code]['datastructure-fp']
-        datastructure_response = pandasdmx.open_file(fp_datastructure)
+        datastructure_response = sdmx.read_sdmx(fp_datastructure)
         assert dataset_code in datastructure_response.dataflow
         dsd = datastructure_response.dataflow[dataset_code].structure
 
-        '''Verify dimensions list'''
+        # Verify dimensions list
         dimensions = OrderedDict([dim.id, dim] for dim in
                                  dsd.dimensions if dim.id not in
                                  ['TIME', 'TIME_PERIOD'])
         dim_keys = list(dimensions.keys())
         assert dim_keys == ['FREQ', 'PRODUIT', 'NATURE']
 
-        '''load datas for the current dataset'''
+        # Load datas for the current dataset
         fp_data = DATASETS[dataset_code]['data-fp']
-        data = pandasdmx.open_file(fp_data)
+        data = sdmx.read_sdmx(fp_data)
 
-        '''Verify series count and values'''
-        # CHANGED: dataset index added; list() not required
+        # Verify series count and values
         series = data.data[0].series
         series_count = len(series)
         assert series_count == DATASETS[dataset_code]['series_count']
@@ -84,12 +83,11 @@ class TestINSEE:
         assert last_obs.value == '139.22'
 
     def test_fixe_key_names(self, req):
-        """Verify key or attribute contains '-' in name
-        """
+        """Verify key or attribute contains '-' in name."""
         dataset_code = 'CNA-2010-CONSO-SI-A17'
 
         fp_datastructure = DATASETS[dataset_code]['datastructure-fp']
-        datastructure_response = pandasdmx.open_file(fp_datastructure)
+        datastructure_response = sdmx.read_sdmx(fp_datastructure)
         assert dataset_code in datastructure_response.dataflow
         dsd = datastructure_response.dataflow[dataset_code].structure
 
@@ -100,11 +98,8 @@ class TestINSEE:
         assert dim_keys == ['SECT-INST', 'OPERATION', 'PRODUIT', 'PRIX']
 
         fp_data = DATASETS[dataset_code]['data-fp']
-        data = pandasdmx.open_file(fp_data)
-
-        # CHANGED: dataset index added; list() not required
+        data = sdmx.read_sdmx(fp_data)
         series = data.data[0].series
-
         series_key = list(series.keys())[0]
 
         assert (list(series_key.values.keys()) ==
@@ -120,6 +115,6 @@ class TestINSEE:
         # INSEE time series provide the FREQ value as attribute on the series
         # instead of a dimension. This caused a runtime error when writing as
         # pandas dataframe.
-        data_response = pandasdmx.open_file(
+        data_response = sdmx.read_sdmx(
             SERIES['UNEMPLOYMENT_CAT_A_B_C']['data-fp'])
-        pandasdmx.to_pandas(data_response)
+        sdmx.to_pandas(data_response)
diff --git a/tests/test_message.py b/tests/test_message.py
index 17b1067..b60b4b9 100644
--- a/tests/test_message.py
+++ b/tests/test_message.py
@@ -51,5 +51,5 @@ EXPECTED = {
 def test_message_repr():
     for pattern, result in EXPECTED.items():
         with specimen(pattern) as f:
-            msg = sdmx.open_file(f)
+            msg = sdmx.read_sdmx(f)
         assert str(msg) == result
diff --git a/tests/test_reader_json.py b/tests/test_reader_json.py
index c2f895b..94d3cfb 100644
--- a/tests/test_reader_json.py
+++ b/tests/test_reader_json.py
@@ -1,4 +1,4 @@
-import pandasdmx
+import pandasdmx as sdmx
 import pytest
 
 from . import test_data_path, test_files
@@ -7,9 +7,9 @@ from . import test_data_path, test_files
 @pytest.mark.parametrize('path', **test_files(format='json'))
 def test_json_read(path):
     """Test that the samples from the SDMX-JSON spec can be read."""
-    pandasdmx.open_file(path)
+    sdmx.read_sdmx(path)
 
 
 def test_header():
-    resp = pandasdmx.open_file(test_data_path / 'json' / 'exr-flat.json')
+    resp = sdmx.read_sdmx(test_data_path / 'json' / 'exr-flat.json')
     assert resp.header.id == '62b5f19d-f1c9-495d-8446-a3661ed24753'
diff --git a/tests/test_reader_xml.py b/tests/test_reader_xml.py
index 2133772..cb9a6a6 100644
--- a/tests/test_reader_xml.py
+++ b/tests/test_reader_xml.py
@@ -1,6 +1,6 @@
 import warnings
 
-import pandasdmx
+import pandasdmx as sdmx
 import pytest
 
 from . import test_data_path, test_files
@@ -12,18 +12,18 @@ warnings.filterwarnings('error')
 # Read example data files
 @pytest.mark.parametrize('path', **test_files(format='xml', kind='data'))
 def test_read_xml(path):
-    pandasdmx.open_file(path)
+    sdmx.read_sdmx(path)
 
 
 # Read example structure files
 @pytest.mark.parametrize('path', **test_files(format='xml', kind='structure'))
 def test_read_xml_structure(path):
-    pandasdmx.open_file(path)
+    sdmx.read_sdmx(path)
 
 
 def test_read_xml_structure_insee():
-    msg = pandasdmx.open_file(test_data_path / 'insee' /
-                              'insee-IPI-2010-A21-datastructure.xml')
+    msg = sdmx.read_sdmx(test_data_path / 'insee' /
+                         'insee-IPI-2010-A21-datastructure.xml')
 
     # Same objects referenced
     assert (id(msg.dataflow['IPI-2010-A21'].structure) ==
diff --git a/tests/test_writer.py b/tests/test_writer.py
index 17d1a9f..5c3280c 100644
--- a/tests/test_writer.py
+++ b/tests/test_writer.py
@@ -60,7 +60,7 @@ def pytest_generate_tests(metafunc):
 
 
 def test_write_data_arguments():
-    msg = sdmx.open_file(test_files(kind='data')['argvalues'][0])
+    msg = sdmx.read_sdmx(test_files(kind='data')['argvalues'][0])
 
     # Attributes must be a string
     with raises(TypeError):
@@ -72,7 +72,7 @@ def test_write_data_arguments():
 
 
 def test_write_data(data_path):
-    msg = sdmx.open_file(data_path)
+    msg = sdmx.read_sdmx(data_path)
 
     result = sdmx.to_pandas(msg)
 
@@ -87,7 +87,7 @@ def test_write_data(data_path):
 
 @pytest.mark.parametrize('path', **test_files(kind='data'))
 def test_write_data_attributes(path):
-    msg = sdmx.open_file(path)
+    msg = sdmx.read_sdmx(path)
 
     result = sdmx.to_pandas(msg, attributes='osgd')
     # TODO incomplete
@@ -97,7 +97,7 @@ def test_write_data_attributes(path):
 def test_write_agencyscheme():
     # Convert an agency scheme
     with specimen('ecb_orgscheme.xml') as f:
-        msg = sdmx.open_file(f)
+        msg = sdmx.read_sdmx(f)
         data = sdmx.to_pandas(msg)
 
     assert data['organisation_scheme']['AGENCIES']['ESTAT'] == 'Eurostat'
@@ -105,7 +105,7 @@ def test_write_agencyscheme():
 
 def test_write_categoryscheme():
     with specimen('insee-IPI-2010-A21-datastructure.xml') as f:
-        msg = sdmx.open_file(f)
+        msg = sdmx.read_sdmx(f)
         print(msg.category_scheme)
         data = sdmx.to_pandas(msg)
 
@@ -120,7 +120,7 @@ def test_write_categoryscheme():
 
 def test_write_codelist():
     # Retrieve codelists from a test specimen and convert to pandas
-    dsd_common = sdmx.open_file(test_data_path / 'common' / 'common.xml')
+    dsd_common = sdmx.read_sdmx(test_data_path / 'common' / 'common.xml')
     codelists = sdmx.to_pandas(dsd_common)['codelist']
 
     # File contains 5 code lists
@@ -138,7 +138,7 @@ def test_write_codelist():
 
     # Hierarchical code list
     with specimen('unsd_codelist_partial.xml') as f:
-        msg = sdmx.open_file(f)
+        msg = sdmx.read_sdmx(f)
 
     # Convert single codelist
     CL_AREA = sdmx.to_pandas(msg.codelist['CL_AREA'])
@@ -155,7 +155,7 @@ def test_write_codelist():
 
 def test_write_conceptscheme():
     with specimen('common.xml') as f:
-        msg = sdmx.open_file(f)
+        msg = sdmx.read_sdmx(f)
         data = sdmx.to_pandas(msg)
 
     cdc = data['concept_scheme']['CROSS_DOMAIN_CONCEPTS']
@@ -165,7 +165,7 @@ def test_write_conceptscheme():
 def test_write_dataflow():
     # Read the INSEE dataflow definition
     with specimen('insee-dataflow') as f:
-        msg = sdmx.open_file(f)
+        msg = sdmx.read_sdmx(f)
 
     # Convert to pandas
     result = sdmx.to_pandas(msg, include='dataflow')
@@ -187,7 +187,7 @@ def test_write_dataflow():
 
 @pytest.mark.parametrize('path', **test_files(kind='structure'))
 def test_writer_structure(path):
-    msg = sdmx.open_file(path)
+    msg = sdmx.read_sdmx(path)
 
     sdmx.to_pandas(msg)
 
@@ -198,7 +198,7 @@ def test_writer_structure(path):
 def test_write_constraint():
     """'constraint' argument to writer.write_dataset."""
     with specimen('generic/ecb_exr_ng_ts.xml') as f:
-        msg = sdmx.open_file(f)
+        msg = sdmx.read_sdmx(f)
 
     # Fetch the message's DSD
     assert msg.structure.is_external_reference