Repository: EdinburghGenomics/pyclarity-lims

Issue:
Support for different file encodings
We should be able to read `utf-16`-encoded files, e.g. from the Spectramax. `requests` can return text with any encoding:

```python
>>> request.encoding
'utf-8'
>>> request.text
'some_glitchy_looking_binary_data'
>>> request.encoding = 'utf-16'
>>> request.text
'some_well_formed_data'
```

We should add this to `Lims.get_file_contents`. We should also be able to replace CRLFs with `\n`.


Discussion:

Patch:
diff --git a/pyclarity_lims/lims.py b/pyclarity_lims/lims.py
index 4f64117..67f26ad 100644
--- a/pyclarity_lims/lims.py
+++ b/pyclarity_lims/lims.py
@@ -89,18 +89,21 @@ class Lims(object):
         else:
             return self.parse_response(r)
 
-    def get_file_contents(self, id=None, uri=None):
+    def get_file_contents(self, id=None, uri=None, encoding=None, crlf=False):
         """Returns the contents of the file of <ID> or <uri>"""
         if id:
-            segments = ['api', self.VERSION, 'files', id, 'download']
+            url = self.get_uri('files', id, 'download')
         elif uri:
-            segments = [uri, 'download']
+            url = uri.rstrip('/') + '/download'
         else:
-            raise ValueError("id or uri required")
-        url = urljoin(self.baseuri, '/'.join(segments))
+            raise ValueError('id or uri required')
+
         r = self.request_session.get(url, auth=(self.username, self.password), timeout=TIMEOUT)
         self.validate_response(r)
-        return r.text
+        if encoding:
+            r.encoding = encoding
+
+        return r.text.replace('\r\n', '\n') if crlf else r.text
 
     def upload_new_file(self, entity, file_to_upload):
         """Upload a file and attach it to the provided entity."""


Test patch:
diff --git a/tests/test_lims.py b/tests/test_lims.py
index ffa503b..bcf82db 100644
--- a/tests/test_lims.py
+++ b/tests/test_lims.py
@@ -1,4 +1,3 @@
-import xml
 from unittest import TestCase
 
 from requests.exceptions import HTTPError
@@ -19,6 +18,7 @@ else:
     from unittest.mock import patch, Mock
     import builtins
 
+
 class TestLims(TestCase):
     url = 'http://testgenologics.com:4040'
     username = 'test'
@@ -36,12 +36,10 @@ class TestLims(TestCase):
 <exc:exception xmlns:exc="http://pyclarity_lims.com/ri/exception">
 </exc:exception>"""
 
-
     def test_get_uri(self):
         lims = Lims(self.url, username=self.username, password=self.password)
         assert lims.get_uri('artifacts',sample_name='test_sample') == '{url}/api/v2/artifacts?sample_name=test_sample'.format(url=self.url)
 
-
     def test_parse_response(self):
         lims = Lims(self.url, username=self.username, password=self.password)
         r = Mock(content = self.sample_xml, status_code=200)
@@ -56,7 +54,6 @@ class TestLims(TestCase):
         r = Mock(content = self.error_no_msg_xml, status_code=400)
         self.assertRaises(HTTPError, lims.parse_response, r)
 
-
     @patch('requests.Session.get',return_value=Mock(content = sample_xml, status_code=200))
     def test_get(self, mocked_instance):
         lims = Lims(self.url, username=self.username, password=self.password)
@@ -88,7 +85,6 @@ class TestLims(TestCase):
             self.assertRaises(HTTPError, lims.post, uri=uri, data=self.sample_xml)
             assert mocked_put.call_count == 1
 
-
     @patch('os.path.isfile', return_value=True)
     @patch.object(builtins, 'open')
     def test_upload_new_file(self, mocked_open, mocked_isfile):
@@ -124,8 +120,6 @@ class TestLims(TestCase):
         lims.route_artifacts(artifact_list=[artifact], workflow_uri=self.url+'/api/v2/configuration/workflows/1')
         assert mocked_post.call_count == 1
 
-
-
     def test_tostring(self):
         lims = Lims(self.url, username=self.username, password=self.password)
         from xml.etree import ElementTree as ET
@@ -139,5 +133,16 @@ class TestLims(TestCase):
         string = lims.tostring(etree)
         assert string == expected_string
 
+    def test_get_file_contents(self):
+        lims = Lims(self.url, username=self.username, password=self.password)
+        lims.validate_response = Mock()
+        lims.request_session = Mock(get=Mock(return_value=Mock(encoding=None, text='some data\r\n')))
+        exp_url = self.url + '/api/v2/files/an_id/download'
 
+        assert lims.get_file_contents(uri=self.url + '/api/v2/files/an_id') == 'some data\r\n'
+        assert lims.request_session.get.return_value.encoding is None
+        lims.request_session.get.assert_called_with(exp_url, auth=(self.username, self.password), timeout=16)
 
+        assert lims.get_file_contents(id='an_id', encoding='utf-16', crlf=True) == 'some data\n'
+        assert lims.request_session.get.return_value.encoding == 'utf-16'
+        lims.request_session.get.assert_called_with(exp_url, auth=(self.username, self.password), timeout=16)