4823: Fix tests broken by prior refactoring. Renamed 'api.py' to 'apisetup.py'
authorPeter Amstutz <peter.amstutz@curoverse.com>
Fri, 20 Feb 2015 20:58:14 +0000 (15:58 -0500)
committerPeter Amstutz <peter.amstutz@curoverse.com>
Fri, 20 Feb 2015 20:58:14 +0000 (15:58 -0500)
so it wouldn't be awkwardly shadowed by the 'api' method.

12 files changed:
sdk/python/arvados/__init__.py
sdk/python/arvados/_normalize_stream.py
sdk/python/arvados/apisetup.py [moved from sdk/python/arvados/api.py with 94% similarity]
sdk/python/arvados/arvfile.py
sdk/python/arvados/collection.py
sdk/python/arvados/safeapi.py
sdk/python/arvados/stream.py
sdk/python/tests/run_test_server.py
sdk/python/tests/test_arvfile.py
sdk/python/tests/test_collections.py
sdk/python/tests/test_sdk.py
sdk/python/tests/test_stream.py

index e4d148e1ca1beedb95fa71bbe5b7a8eb1fb755d6..91fe460aea4d61d729b0ba13baf826f3c1e7127c 100644 (file)
@@ -18,7 +18,7 @@ import fcntl
 import time
 import threading
 
-from api import *
+from apisetup import api, http_cache
 from collection import CollectionReader, CollectionWriter, ResumableCollectionWriter
 from keep import *
 from stream import *
index 4423639af7dd92fa109fe790e494f32169394055..400a38e46bedf96c99b2c3081ca594efd5ccd877 100644 (file)
@@ -9,6 +9,7 @@ def normalize_stream(stream_name, stream):
 
     """
 
+    stream_name = stream_name.replace(' ', '\\040')
     stream_tokens = [stream_name]
     sortedfiles = list(stream.keys())
     sortedfiles.sort()
similarity index 94%
rename from sdk/python/arvados/api.py
rename to sdk/python/arvados/apisetup.py
index cf1c29be2df90a43ecf7e843fad0211fca1c6e24..830be96416923908fd9cdace2d7bd0f208fff32d 100644 (file)
@@ -76,14 +76,22 @@ def http_cache(data_type):
 def api(version=None, cache=True, host=None, token=None, insecure=False, **kwargs):
     """Return an apiclient Resources object for an Arvados instance.
 
-    Arguments:
-    * version: A string naming the version of the Arvados API to use (for
+    :version:
+      A string naming the version of the Arvados API to use (for
       example, 'v1').
-    * cache: Use a cache (~/.cache/arvados/discovery) for the discovery
+
+    :cache:
+      Use a cache (~/.cache/arvados/discovery) for the discovery
       document.
-    * host: The Arvados API server host (and optional :port) to connect to.
-    * token: The authentication token to send with each API call.
-    * insecure: If True, ignore SSL certificate validation errors.
+
+    :host:
+      The Arvados API server host (and optional :port) to connect to.
+
+    :token:
+      The authentication token to send with each API call.
+
+    :insecure:
+      If True, ignore SSL certificate validation errors.
 
     Additional keyword arguments will be passed directly to
     `apiclient_discovery.build` if a new Resource object is created.
index b5eb6e6ced737560d73ff8cf6278233a842c6bcf..d9d9cd287a3b2a81ae85ec283bc06c840f8f81b2 100644 (file)
@@ -2,7 +2,7 @@ import functools
 import os
 import zlib
 import bz2
-from ._ranges import locators_and_ranges, replace_range
+from ._ranges import locators_and_ranges, replace_range, Range
 from arvados.retry import retry_method
 import config
 import hashlib
@@ -81,7 +81,7 @@ class ArvadosFileReaderBase(_FileLikeObjectBase):
     def decompressed_name(self):
         return re.sub('\.(bz2|gz)$', '', self.name)
 
-    @FileLikeObjectBase._before_close
+    @_FileLikeObjectBase._before_close
     def seek(self, pos, whence=os.SEEK_CUR):
         if whence == os.SEEK_CUR:
             pos += self._filepos
@@ -92,7 +92,7 @@ class ArvadosFileReaderBase(_FileLikeObjectBase):
     def tell(self):
         return self._filepos
 
-    @FileLikeObjectBase._before_close
+    @_FileLikeObjectBase._before_close
     @retry_method
     def readall(self, size=2**20, num_retries=None):
         while True:
@@ -101,7 +101,7 @@ class ArvadosFileReaderBase(_FileLikeObjectBase):
                 break
             yield data
 
-    @FileLikeObjectBase._before_close
+    @_FileLikeObjectBase._before_close
     @retry_method
     def readline(self, size=float('inf'), num_retries=None):
         cache_pos, cache_data = self._readline_cache
@@ -125,7 +125,7 @@ class ArvadosFileReaderBase(_FileLikeObjectBase):
         self._readline_cache = (self.tell(), data[nextline_index:])
         return data[:nextline_index]
 
-    @FileLikeObjectBase._before_close
+    @_FileLikeObjectBase._before_close
     @retry_method
     def decompress(self, decompress, size, num_retries=None):
         for segment in self.readall(size, num_retries):
@@ -133,7 +133,7 @@ class ArvadosFileReaderBase(_FileLikeObjectBase):
             if data:
                 yield data
 
-    @FileLikeObjectBase._before_close
+    @_FileLikeObjectBase._before_close
     @retry_method
     def readall_decompressed(self, size=2**20, num_retries=None):
         self.seek(0)
@@ -148,7 +148,7 @@ class ArvadosFileReaderBase(_FileLikeObjectBase):
         else:
             return self.readall(size, num_retries=num_retries)
 
-    @FileLikeObjectBase._before_close
+    @_FileLikeObjectBase._before_close
     @retry_method
     def readlines(self, sizehint=float('inf'), num_retries=None):
         data = []
@@ -183,7 +183,7 @@ class StreamFileReader(ArvadosFileReaderBase):
         n = self.segments[-1]
         return n.range_start + n.range_size
 
-    @FileLikeObjectBase._before_close
+    @_FileLikeObjectBase._before_close
     @retry_method
     def read(self, size, num_retries=None):
         """Read up to 'size' bytes from the stream, starting at the current file position"""
@@ -201,7 +201,7 @@ class StreamFileReader(ArvadosFileReaderBase):
         self._filepos += len(data)
         return data
 
-    @FileLikeObjectBase._before_close
+    @_FileLikeObjectBase._before_close
     @retry_method
     def readfrom(self, start, size, num_retries=None):
         """Read up to 'size' bytes from the stream, starting at 'start'"""
@@ -300,9 +300,9 @@ class _BufferBlock(object):
             (self._state == _BufferBlock.PENDING and nextstate == _BufferBlock.COMMITTED)):
             self._state = nextstate
             if self._state == _BufferBlock.COMMITTED:
-                    bufferblock._locator = loc
-                    bufferblock.buffer_view = None
-                    bufferblock.buffer_block = None
+                self._locator = loc
+                self.buffer_view = None
+                self.buffer_block = None
         else:
             raise AssertionError("Invalid state change from %s to %s" % (self.state, state))
 
@@ -821,6 +821,7 @@ class ArvadosFile(object):
 
     @synchronized
     def manifest_text(self, stream_name=".", portable_locators=False, normalize=False):
+        buf = ""
         item = self
         filestream = []
         for segment in item.segments:
@@ -852,7 +853,10 @@ class ArvadosFileReader(ArvadosFileReaderBase):
     def size(self):
         return self.arvadosfile.size()
 
-    @FileLikeObjectBase._before_close
+    def stream_name(self):
+        return self.arvadosfile.parent.stream_name()
+
+    @_FileLikeObjectBase._before_close
     @retry_method
     def read(self, size, num_retries=None):
         """Read up to `size` bytes from the stream, starting at the current file position."""
@@ -860,7 +864,7 @@ class ArvadosFileReader(ArvadosFileReaderBase):
         self._filepos += len(data)
         return data
 
-    @FileLikeObjectBase._before_close
+    @_FileLikeObjectBase._before_close
     @retry_method
     def readfrom(self, offset, size, num_retries=None):
         """Read up to `size` bytes from the stream, starting at the current file position."""
@@ -881,7 +885,7 @@ class ArvadosFileWriter(ArvadosFileReader):
     def __init__(self, arvadosfile, name, mode, num_retries=None):
         super(ArvadosFileWriter, self).__init__(arvadosfile, name, mode, num_retries=num_retries)
 
-    @FileLikeObjectBase._before_close
+    @_FileLikeObjectBase._before_close
     @retry_method
     def write(self, data, num_retries=None):
         if self.mode[0] == "a":
@@ -890,7 +894,7 @@ class ArvadosFileWriter(ArvadosFileReader):
             self.arvadosfile.writeto(self._filepos, data, num_retries)
             self._filepos += len(data)
 
-    @FileLikeObjectBase._before_close
+    @_FileLikeObjectBase._before_close
     @retry_method
     def writelines(self, seq, num_retries=None):
         for s in seq:
index 82b97456f7ac1d86a49c80ca125f38db577c28e3..08b9deb64fefc3dba1231701c03326b379381b90 100644 (file)
@@ -8,10 +8,10 @@ import time
 from collections import deque
 from stat import *
 
-from .arvfile import split, FileLikeObjectBase, ArvadosFile, ArvadosFileWriter, ArvadosFileReader, _BlockManager, synchronized, must_be_writable, SYNC_READONLY, SYNC_EXPLICIT, NoopLock
+from .arvfile import split, _FileLikeObjectBase, ArvadosFile, ArvadosFileWriter, ArvadosFileReader, _BlockManager, synchronized, must_be_writable, SYNC_READONLY, SYNC_EXPLICIT, NoopLock
 from keep import *
-from .stream import StreamReader, normalize_stream, locator_block_size
-from .ranges import Range, LocatorAndRange
+from .stream import StreamReader, normalize_stream
+from ._ranges import Range, LocatorAndRange
 from .safeapi import ThreadSafeApiCache
 import config
 import errors
@@ -54,7 +54,7 @@ class CollectionBase(object):
         return ''.join(clean)
 
 
-class _WriterFile(FileLikeObjectBase):
+class _WriterFile(_FileLikeObjectBase):
     def __init__(self, coll_writer, name):
         super(_WriterFile, self).__init__(name, 'wb')
         self.dest = coll_writer
@@ -63,16 +63,16 @@ class _WriterFile(FileLikeObjectBase):
         super(_WriterFile, self).close()
         self.dest.finish_current_file()
 
-    @FileLikeObjectBase._before_close
+    @_FileLikeObjectBase._before_close
     def write(self, data):
         self.dest.write(data)
 
-    @FileLikeObjectBase._before_close
+    @_FileLikeObjectBase._before_close
     def writelines(self, seq):
         for data in seq:
             self.write(data)
 
-    @FileLikeObjectBase._before_close
+    @_FileLikeObjectBase._before_close
     def flush(self):
         self.dest.flush_data()
 
@@ -494,9 +494,6 @@ class SynchronizedCollectionBase(CollectionBase):
     def _my_block_manager(self):
         raise NotImplementedError()
 
-    def _populate(self):
-        raise NotImplementedError()
-
     def sync_mode(self):
         raise NotImplementedError()
 
@@ -506,6 +503,9 @@ class SynchronizedCollectionBase(CollectionBase):
     def notify(self, event, collection, name, item):
         raise NotImplementedError()
 
+    def stream_name(self):
+        raise NotImplementedError()
+
     @must_be_writable
     @synchronized
     def find_or_create(self, path, create_type):
@@ -554,7 +554,7 @@ class SynchronizedCollectionBase(CollectionBase):
                 if isinstance(item, SynchronizedCollectionBase):
                     return item.find_or_create("/".join(pathcomponents), create_type)
                 else:
-                    raise errors.ArgumentError("Interior path components must be subcollection")
+                    raise IOError((errno.ENOTDIR, "Interior path components must be subcollection"))
         else:
             return self
 
@@ -580,7 +580,7 @@ class SynchronizedCollectionBase(CollectionBase):
                 if isinstance(item, SynchronizedCollectionBase):
                     return item.find("/".join(pathcomponents))
                 else:
-                    raise errors.ArgumentError("Interior path components must be subcollection")
+                    raise IOError((errno.ENOTDIR, "Interior path components must be subcollection"))
         else:
             return self
 
@@ -593,7 +593,7 @@ class SynchronizedCollectionBase(CollectionBase):
         """
         return self.find_or_create(path, COLLECTION)
 
-    def open(self, path, mode):
+    def open(self, path, mode="r"):
         """Open a file-like object for access.
 
         :path:
@@ -613,7 +613,7 @@ class SynchronizedCollectionBase(CollectionBase):
         """
         mode = mode.replace("b", "")
         if len(mode) == 0 or mode[0] not in ("r", "w", "a"):
-            raise ArgumentError("Bad mode '%s'" % mode)
+            raise errors.ArgumentError("Bad mode '%s'" % mode)
         create = (mode != "r")
 
         if create and self.sync_mode() == SYNC_READONLY:
@@ -632,10 +632,12 @@ class SynchronizedCollectionBase(CollectionBase):
         if mode[0] == "w":
             arvfile.truncate(0)
 
+        name = os.path.basename(path)
+
         if mode == "r":
-            return ArvadosFileReader(arvfile, path, mode, num_retries=self.num_retries)
+            return ArvadosFileReader(arvfile, name, mode, num_retries=self.num_retries)
         else:
-            return ArvadosFileWriter(arvfile, path, mode, num_retries=self.num_retries)
+            return ArvadosFileWriter(arvfile, name, mode, num_retries=self.num_retries)
 
     @synchronized
     def modified(self):
@@ -832,10 +834,10 @@ class SynchronizedCollectionBase(CollectionBase):
 
         """
 
-        portable_locators = strip
         if self.modified() or self._manifest_text is None or normalize:
             item  = self
             stream = {}
+            buf = ""
             sorted_keys = sorted(item.keys())
             for filename in [s for s in sorted_keys if isinstance(item[s], ArvadosFile)]:
                 # Create a stream per file `k`
@@ -845,19 +847,19 @@ class SynchronizedCollectionBase(CollectionBase):
                     loc = segment.locator
                     if arvfile.parent._my_block_manager().is_bufferblock(loc):
                         loc = arvfile.parent._my_block_manager().get_bufferblock(loc).locator()
-                    if portable_locators:
+                    if strip:
                         loc = KeepLocator(loc).stripped()
-                    filestream.append(LocatorAndRange(loc, locator_block_size(loc),
+                    filestream.append(LocatorAndRange(loc, KeepLocator(loc).size,
                                          segment.segment_offset, segment.range_size))
                 stream[filename] = filestream
             if stream:
                 buf += ' '.join(normalize_stream(stream_name, stream))
                 buf += "\n"
             for dirname in [s for s in sorted_keys if isinstance(item[s], SynchronizedCollectionBase)]:
-                buf += item[dirname].manifest_text(stream_name=os.path.join(stream_name, dirname), portable_locators=portable_locators)
+                buf += item[dirname].manifest_text(stream_name=os.path.join(stream_name, dirname), strip=strip)
             return buf
         else:
-            if portable_locators:
+            if strip:
                 return self.stripped_manifest()
             else:
                 return self._manifest_text
@@ -870,7 +872,7 @@ class SynchronizedCollectionBase(CollectionBase):
         """
         changes = []
         if holding_collection is None:
-            holding_collection = Collection(api_client=self._my_api(), keep_client=self._my_keep(), sync=SYNC_EXPLICIT)
+            holding_collection = Collection(api_client=self._my_api(), keep_client=self._my_keep())
         for k in self:
             if k not in end_collection:
                changes.append((DEL, os.path.join(prefix, k), self[k].clone(holding_collection)))
@@ -1029,14 +1031,13 @@ class Collection(SynchronizedCollectionBase):
         else:
             self._config = config.settings()
 
-        self.num_retries = num_retries if num_retries is not None else 2
+        self.num_retries = num_retries if num_retries is not None else 0
         self._manifest_locator = None
         self._manifest_text = None
         self._api_response = None
 
         self._sync = SYNC_EXPLICIT
-        if not self.lock:
-            self.lock = threading.RLock()
+        self.lock = threading.RLock()
         self.callbacks = []
         self.events = None
 
@@ -1057,6 +1058,9 @@ class Collection(SynchronizedCollectionBase):
     def root_collection(self):
         return self
 
+    def stream_name(self):
+        return "."
+
     def sync_mode(self):
         return self._sync
 
@@ -1071,8 +1075,8 @@ class Collection(SynchronizedCollectionBase):
             if self._manifest_locator is None:
                 raise errors.ArgumentError("`other` is None but collection does not have a manifest_locator uuid")
             response = self._my_api().collections().get(uuid=self._manifest_locator).execute(num_retries=num_retries)
-            other = import_manifest(response["manifest_text"])
-        baseline = import_manifest(self._manifest_text)
+            other = CollectionReader(response["manifest_text"])
+        baseline = CollectionReader(self._manifest_text)
         self.apply(baseline.diff(other))
 
     @synchronized
@@ -1088,7 +1092,7 @@ class Collection(SynchronizedCollectionBase):
             if self._api_client is None:
                 self._my_api()
             else:
-                self._keep_client = KeepClient(api=self._api_client)
+                self._keep_client = KeepClient(api_client=self._api_client)
         return self._keep_client
 
     @synchronized
@@ -1156,7 +1160,7 @@ class Collection(SynchronizedCollectionBase):
                     error_via_keep))
         # populate
         self._baseline_manifest = self._manifest_text
-        import_manifest(self._manifest_text, self)
+        self._import_manifest(self._manifest_text)
 
 
     def _has_collection_uuid(self):
@@ -1173,14 +1177,17 @@ class Collection(SynchronizedCollectionBase):
             self._block_manager.stop_threads()
 
     @synchronized
-    def clone(self, new_parent=None, new_sync=SYNC_READONLY, new_config=None):
+    def clone(self, new_parent=None, readonly=False, new_config=None):
         if new_config is None:
             new_config = self._config
-        newcollection = Collection(parent=new_parent, apiconfig=new_config, sync=SYNC_EXPLICIT)
-        if new_sync == SYNC_READONLY:
-            newcollection.lock = NoopLock()
+        if readonly:
+            newcollection = CollectionReader(parent=new_parent, apiconfig=new_config)
+        else:
+            newcollection = Collection(parent=new_parent, apiconfig=new_config)
+
+        newcollection._sync = None
         self._cloneinto(newcollection)
-        newcollection._sync = new_sync
+        newcollection._sync = SYNC_READONLY if readonly else SYNC_EXPLICIT
         return newcollection
 
     @synchronized
@@ -1363,6 +1370,7 @@ class Subcollection(SynchronizedCollectionBase):
     def __init__(self, parent):
         super(Subcollection, self).__init__(parent)
         self.lock = self.root_collection().lock
+        self._manifest_text = None
 
     def root_collection(self):
         return self.parent.root_collection()
@@ -1379,12 +1387,15 @@ class Subcollection(SynchronizedCollectionBase):
     def _my_block_manager(self):
         return self.root_collection()._my_block_manager()
 
-    def _populate(self):
-        self.root_collection()._populate()
-
     def notify(self, event, collection, name, item):
         return self.root_collection().notify(event, collection, name, item)
 
+    def stream_name(self):
+        for k, v in self.parent.items():
+            if v is self:
+                return os.path.join(self.parent.stream_name(), k)
+        return '.'
+
     @synchronized
     def clone(self, new_parent):
         c = Subcollection(new_parent)
@@ -1403,16 +1414,20 @@ class CollectionReader(Collection):
         if not args and not kwargs.get("manifest_locator_or_text"):
             raise errors.ArgumentError("Must provide manifest locator or text to initialize ReadOnlyCollection")
 
+        super(CollectionReader, self).__init__(*args, **kwargs)
+
         # Forego any locking since it should never change once initialized.
         self.lock = NoopLock()
-
-        super(ReadOnlyCollection, self).__init__(*args, **kwargs)
-
         self._sync = SYNC_READONLY
 
-        self._streams = [sline.split()
-                         for sline in self._manifest_text.split("\n")
-                         if sline]
+        # Backwards compatability with old CollectionReader
+        # all_streams() and all_files()
+        if self._manifest_text:
+            self._streams = [sline.split()
+                             for sline in self._manifest_text.split("\n")
+                             if sline]
+        else:
+            self._streams = []
 
     def normalize(self):
         # Rearrange streams
index 5c5c87250ac678f9b9bf93cbf56cb335707c6554..baada91abdf148f9f23cd73add717bb860a93a69 100644 (file)
@@ -1,5 +1,5 @@
 import threading
-import api
+import apisetup
 import keep
 import config
 import copy
@@ -21,7 +21,7 @@ class ThreadSafeApiCache(object):
 
     def localapi(self):
         if 'api' not in self.local.__dict__:
-            self.local.api = api.api_from_config('v1', apiconfig=self.apiconfig)
+            self.local.api = apisetup.api_from_config('v1', apiconfig=self.apiconfig)
         return self.local.api
 
     def __getattr__(self, name):
index a6e086366c8ac8611dbc7271ad55cfa80d0f55f0..85c0320119acde2b745458b03d07abaa87fbbabd 100644 (file)
@@ -6,7 +6,7 @@ import threading
 import functools
 import copy
 
-from ._ranges import locators_and_ranges
+from ._ranges import locators_and_ranges, Range
 from .arvfile import StreamFileReader
 from arvados.retry import retry_method
 from keep import *
index 18011af7a64e61dd43b3d2f40ec7400ff6324d9c..b9502f0f8e5bb5a6292da85bb69ef1f783163cab 100644 (file)
@@ -25,7 +25,7 @@ if __name__ == '__main__' and os.path.exists(
     # Add the Python SDK source to the library path.
     sys.path.insert(1, os.path.dirname(MY_DIRNAME))
 
-import arvados.api
+import arvados
 import arvados.config
 
 ARVADOS_DIR = os.path.realpath(os.path.join(MY_DIRNAME, '../../..'))
index e5670e37cd7a9597173ec421c41331f249d80dbb..b6e8426495b683bc6668fa2d1426e6231169c669 100644 (file)
@@ -9,8 +9,9 @@ import unittest
 import hashlib
 
 import arvados
-from arvados import Range, KeepLocator
-from arvados.collection import import_manifest, export_manifest, ReadOnlyCollection, WritableCollection
+from arvados._ranges import Range
+from arvados.keep import KeepLocator
+from arvados.collection import Collection, CollectionReader
 from arvados.arvfile import ArvadosFile, ArvadosFileReader, SYNC_READONLY, SYNC_EXPLICIT
 
 import arvados_testutil as tutil
@@ -61,7 +62,7 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
                                                  "manifest_text":". 781e5e245d69b566979b86e28d23f2c7+10 0:8:count.txt\n"},
                                                 {"uuid":"zzzzz-4zz18-mockcollection0",
                                                  "manifest_text":". 781e5e245d69b566979b86e28d23f2c7+10 0:8:count.txt\n"})
-        with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n',
+        with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n',
                              api_client=api, keep_client=keep) as c:
             writer = c.open("count.txt", "r+")
             self.assertEqual(writer.size(), 10)
@@ -83,7 +84,7 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
                                                  "manifest_text": ". 781e5e245d69b566979b86e28d23f2c7+10 acbd18db4cc2f85cedef654fccc4a4d8+3 0:13:count.txt\n"},
                                                 {"uuid":"zzzzz-4zz18-mockcollection0",
                                                  "manifest_text": ". 781e5e245d69b566979b86e28d23f2c7+10 acbd18db4cc2f85cedef654fccc4a4d8+3 0:13:count.txt\n"})
-        with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n',
+        with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n',
                              api_client=api, keep_client=keep) as c:
             writer = c.open("count.txt", "r+")
             self.assertEqual(writer.size(), 10)
@@ -110,7 +111,7 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
 
     def test_append(self):
         keep = ArvadosFileWriterTestCase.MockKeep({"781e5e245d69b566979b86e28d23f2c7+10": "0123456789"})
-        c = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n', keep_client=keep)
+        c = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n', keep_client=keep)
         writer = c.open("count.txt", "a+")
         self.assertEqual(writer.read(20), "0123456789")
         writer.seek(0, os.SEEK_SET)
@@ -122,11 +123,11 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
         writer.write("world")
         self.assertEqual(writer.read(20), "0123456789helloworld")
 
-        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 fc5e038d38a57032085441e7fe7010b0+10 0:20:count.txt\n", export_manifest(c))
+        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 fc5e038d38a57032085441e7fe7010b0+10 0:20:count.txt\n", c.manifest_text())
 
     def test_write_at_beginning(self):
         keep = ArvadosFileWriterTestCase.MockKeep({"781e5e245d69b566979b86e28d23f2c7+10": "0123456789"})
-        with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n',
+        with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n',
                              keep_client=keep) as c:
             writer = c.open("count.txt", "r+")
             self.assertEqual("0123456789", writer.readfrom(0, 13))
@@ -134,11 +135,11 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
             writer.write("foo")
             self.assertEqual(writer.size(), 10)
             self.assertEqual("foo3456789", writer.readfrom(0, 13))
-            self.assertEqual(". acbd18db4cc2f85cedef654fccc4a4d8+3 781e5e245d69b566979b86e28d23f2c7+10 0:3:count.txt 6:7:count.txt\n", export_manifest(c))
+            self.assertEqual(". acbd18db4cc2f85cedef654fccc4a4d8+3 781e5e245d69b566979b86e28d23f2c7+10 0:3:count.txt 6:7:count.txt\n", c.manifest_text())
 
     def test_write_in_middle(self):
         keep = ArvadosFileWriterTestCase.MockKeep({"781e5e245d69b566979b86e28d23f2c7+10": "0123456789"})
-        with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n',
+        with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n',
                              keep_client=keep) as c:
             writer = c.open("count.txt", "r+")
             self.assertEqual("0123456789", writer.readfrom(0, 13))
@@ -146,11 +147,11 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
             writer.write("foo")
             self.assertEqual(writer.size(), 10)
             self.assertEqual("012foo6789", writer.readfrom(0, 13))
-            self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 acbd18db4cc2f85cedef654fccc4a4d8+3 0:3:count.txt 10:3:count.txt 6:4:count.txt\n", export_manifest(c))
+            self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 acbd18db4cc2f85cedef654fccc4a4d8+3 0:3:count.txt 10:3:count.txt 6:4:count.txt\n", c.manifest_text())
 
     def test_write_at_end(self):
         keep = ArvadosFileWriterTestCase.MockKeep({"781e5e245d69b566979b86e28d23f2c7+10": "0123456789"})
-        with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n',
+        with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n',
                              keep_client=keep) as c:
             writer = c.open("count.txt", "r+")
             self.assertEqual("0123456789", writer.readfrom(0, 13))
@@ -158,11 +159,11 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
             writer.write("foo")
             self.assertEqual(writer.size(), 10)
             self.assertEqual("0123456foo", writer.readfrom(0, 13))
-            self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 acbd18db4cc2f85cedef654fccc4a4d8+3 0:7:count.txt 10:3:count.txt\n", export_manifest(c))
+            self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 acbd18db4cc2f85cedef654fccc4a4d8+3 0:7:count.txt 10:3:count.txt\n", c.manifest_text())
 
     def test_write_across_segment_boundary(self):
         keep = ArvadosFileWriterTestCase.MockKeep({"781e5e245d69b566979b86e28d23f2c7+10": "0123456789"})
-        with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt 0:10:count.txt\n',
+        with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt 0:10:count.txt\n',
                              keep_client=keep) as c:
             writer = c.open("count.txt", "r+")
             self.assertEqual("012345678901234", writer.readfrom(0, 15))
@@ -170,11 +171,11 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
             writer.write("foobar")
             self.assertEqual(writer.size(), 20)
             self.assertEqual("0123456foobar34", writer.readfrom(0, 15))
-            self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 3858f62230ac3c915f300c664312c63f+6 0:7:count.txt 10:6:count.txt 3:7:count.txt\n", export_manifest(c))
+            self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 3858f62230ac3c915f300c664312c63f+6 0:7:count.txt 10:6:count.txt 3:7:count.txt\n", c.manifest_text())
 
     def test_write_across_several_segments(self):
         keep = ArvadosFileWriterTestCase.MockKeep({"781e5e245d69b566979b86e28d23f2c7+10": "0123456789"})
-        with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:4:count.txt 0:4:count.txt 0:4:count.txt',
+        with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:4:count.txt 0:4:count.txt 0:4:count.txt',
                              keep_client=keep) as c:
             writer = c.open("count.txt", "r+")
             self.assertEqual("012301230123", writer.readfrom(0, 15))
@@ -182,7 +183,7 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
             writer.write("abcdefg")
             self.assertEqual(writer.size(), 12)
             self.assertEqual("01abcdefg123", writer.readfrom(0, 15))
-            self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 7ac66c0f148de9519b8bd264312c4d64+7 0:2:count.txt 10:7:count.txt 1:3:count.txt\n", export_manifest(c))
+            self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 7ac66c0f148de9519b8bd264312c4d64+7 0:2:count.txt 10:7:count.txt 1:3:count.txt\n", c.manifest_text())
 
     def test_write_large(self):
         keep = ArvadosFileWriterTestCase.MockKeep({})
@@ -190,7 +191,7 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
                                                  "manifest_text": ". a5de24f4417cfba9d5825eadc2f4ca49+67108000 598cc1a4ccaef8ab6e4724d87e675d78+32892000 0:100000000:count.txt\n"},
                                                 {"uuid":"zzzzz-4zz18-mockcollection0",
                                                  "manifest_text": ". a5de24f4417cfba9d5825eadc2f4ca49+67108000 598cc1a4ccaef8ab6e4724d87e675d78+32892000 0:100000000:count.txt\n"})
-        with WritableCollection('. ' + arvados.config.EMPTY_BLOCK_LOCATOR + ' 0:0:count.txt',
+        with Collection('. ' + arvados.config.EMPTY_BLOCK_LOCATOR + ' 0:0:count.txt',
                              api_client=api, keep_client=keep) as c:
             writer = c.open("count.txt", "r+")
             text = ''.join(["0123456789" for a in xrange(0, 100)])
@@ -206,7 +207,7 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
 
     def test_rewrite_on_empty_file(self):
         keep = ArvadosFileWriterTestCase.MockKeep({})
-        with WritableCollection('. ' + arvados.config.EMPTY_BLOCK_LOCATOR + ' 0:0:count.txt',
+        with Collection('. ' + arvados.config.EMPTY_BLOCK_LOCATOR + ' 0:0:count.txt',
                              keep_client=keep) as c:
             writer = c.open("count.txt", "r+")
             for b in xrange(0, 10):
@@ -215,11 +216,11 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
             writer.arvadosfile._repack_writes()
             self.assertEqual(writer.size(), 10)
             self.assertEqual("0123456789", writer.readfrom(0, 20))
-            self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n", export_manifest(c))
+            self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n", c.manifest_text())
 
     def test_rewrite_append_existing_file(self):
         keep = ArvadosFileWriterTestCase.MockKeep({"781e5e245d69b566979b86e28d23f2c7+10": "0123456789"})
-        with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt',
+        with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt',
                              keep_client=keep) as c:
             writer = c.open("count.txt", "r+")
             for b in xrange(0, 10):
@@ -228,11 +229,11 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
             writer.arvadosfile._repack_writes()
             self.assertEqual(writer.size(), 20)
             self.assertEqual("0123456789abcdefghij", writer.readfrom(0, 20))
-            self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 a925576942e94b2ef57a066101b48876+10 0:20:count.txt\n", export_manifest(c))
+            self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 a925576942e94b2ef57a066101b48876+10 0:20:count.txt\n", c.manifest_text())
 
     def test_rewrite_over_existing_file(self):
         keep = ArvadosFileWriterTestCase.MockKeep({"781e5e245d69b566979b86e28d23f2c7+10": "0123456789"})
-        with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt',
+        with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt',
                              keep_client=keep) as c:
             writer = c.open("count.txt", "r+")
             for b in xrange(0, 10):
@@ -241,7 +242,7 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
             writer.arvadosfile._repack_writes()
             self.assertEqual(writer.size(), 15)
             self.assertEqual("01234abcdefghij", writer.readfrom(0, 20))
-            self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 a925576942e94b2ef57a066101b48876+10 0:5:count.txt 10:10:count.txt\n", export_manifest(c))
+            self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 a925576942e94b2ef57a066101b48876+10 0:5:count.txt 10:10:count.txt\n", c.manifest_text())
 
     def test_write_large_rewrite(self):
         keep = ArvadosFileWriterTestCase.MockKeep({})
@@ -249,7 +250,7 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
                                                  "manifest_text": ". 37400a68af9abdd76ca5bf13e819e42a+32892003 a5de24f4417cfba9d5825eadc2f4ca49+67108000 32892000:3:count.txt 32892006:67107997:count.txt 0:32892000:count.txt\n"},
                                                 {"uuid":"zzzzz-4zz18-mockcollection0",
                                                  "manifest_text": ". 37400a68af9abdd76ca5bf13e819e42a+32892003 a5de24f4417cfba9d5825eadc2f4ca49+67108000 32892000:3:count.txt 32892006:67107997:count.txt 0:32892000:count.txt\n"})
-        with WritableCollection('. ' + arvados.config.EMPTY_BLOCK_LOCATOR + ' 0:0:count.txt',
+        with Collection('. ' + arvados.config.EMPTY_BLOCK_LOCATOR + ' 0:0:count.txt',
                              api_client=api, keep_client=keep) as c:
             writer = c.open("count.txt", "r+")
             text = ''.join(["0123456789" for a in xrange(0, 100)])
@@ -271,7 +272,7 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
                                                  "manifest_text":". 2e9ec317e197819358fbc43afca7d837+8 0:8:count.txt\n"},
                                                 {"uuid":"zzzzz-4zz18-mockcollection0",
                                                  "manifest_text":". 2e9ec317e197819358fbc43afca7d837+8 0:8:count.txt\n"})
-        with WritableCollection(api_client=api, keep_client=keep) as c:
+        with Collection(api_client=api, keep_client=keep) as c:
             writer = c.open("count.txt", "w+")
             self.assertEqual(writer.size(), 0)
             writer.write("01234567")
@@ -292,7 +293,7 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
                                                  "manifest_text":"./foo/bar 2e9ec317e197819358fbc43afca7d837+8 0:8:count.txt\n"},
                                                 {"uuid":"zzzzz-4zz18-mockcollection0",
                                                  "manifest_text":"./foo/bar 2e9ec317e197819358fbc43afca7d837+8 0:8:count.txt\n"})
-        with WritableCollection(api_client=api, keep_client=keep) as c:
+        with Collection(api_client=api, keep_client=keep) as c:
             self.assertIsNone(c.api_response())
             writer = c.open("foo/bar/count.txt", "w+")
             writer.write("01234567")
@@ -305,7 +306,7 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
                                                  "manifest_text":". 2e9ec317e197819358fbc43afca7d837+8 0:8:count.txt\n"},
                                                 {"uuid":"zzzzz-4zz18-mockcollection0",
                                                  "manifest_text":". 2e9ec317e197819358fbc43afca7d837+8 0:8:count.txt\n"})
-        with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n',
+        with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n',
                              api_client=api, keep_client=keep) as c:
             writer = c.open("count.txt", "w+")
             self.assertEqual(writer.size(), 0)
@@ -319,12 +320,12 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
             self.assertEqual(False, c.modified())
 
     def test_file_not_found(self):
-        with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n') as c:
+        with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n') as c:
             with self.assertRaises(IOError):
                 writer = c.open("nocount.txt", "r")
 
     def test_cannot_open_directory(self):
-        with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n') as c:
+        with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n') as c:
             with self.assertRaises(IOError):
                 writer = c.open(".", "r")
 
@@ -334,7 +335,7 @@ class ArvadosFileWriterTestCase(unittest.TestCase):
                                                  "manifest_text":". 2e9ec317e197819358fbc43afca7d837+8 e8dc4081b13434b45189a720b77b6818+8 0:8:count1.txt 8:8:count2.txt\n"},
                                                 {"uuid":"zzzzz-4zz18-mockcollection0",
                                                  "manifest_text":". 2e9ec317e197819358fbc43afca7d837+8 e8dc4081b13434b45189a720b77b6818+8 0:8:count1.txt 8:8:count2.txt\n"})
-        with WritableCollection(api_client=api, keep_client=keep) as c:
+        with Collection(api_client=api, keep_client=keep) as c:
             w1 = c.open("count1.txt", "w")
             w2 = c.open("count2.txt", "w")
             w1.write("01234567")
@@ -410,21 +411,21 @@ class ArvadosFileReaderTestCase(StreamFileReaderTestCase):
 
     def test_prefetch(self):
         keep = ArvadosFileWriterTestCase.MockKeep({"2e9ec317e197819358fbc43afca7d837+8": "01234567", "e8dc4081b13434b45189a720b77b6818+8": "abcdefgh"})
-        with WritableCollection(". 2e9ec317e197819358fbc43afca7d837+8 e8dc4081b13434b45189a720b77b6818+8 0:16:count.txt\n", keep_client=keep) as c:
+        with Collection(". 2e9ec317e197819358fbc43afca7d837+8 e8dc4081b13434b45189a720b77b6818+8 0:16:count.txt\n", keep_client=keep) as c:
             r = c.open("count.txt", "r")
             self.assertEqual("0123", r.read(4))
         self.assertIn("2e9ec317e197819358fbc43afca7d837+8", keep.requests)
         self.assertIn("e8dc4081b13434b45189a720b77b6818+8", keep.requests)
 
     def test__eq__from_manifest(self):
-        with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt') as c1:
-            with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt') as c2:
+        with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt') as c1:
+            with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt') as c2:
                 self.assertTrue(c1["count1.txt"] == c2["count1.txt"])
                 self.assertFalse(c1["count1.txt"] != c2["count1.txt"])
 
     def test__eq__from_writes(self):
-        with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt') as c1:
-            with WritableCollection() as c2:
+        with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt') as c1:
+            with Collection() as c2:
                 with c2.open("count1.txt", "w") as f:
                     f.write("0123456789")
 
@@ -432,8 +433,8 @@ class ArvadosFileReaderTestCase(StreamFileReaderTestCase):
                 self.assertFalse(c1["count1.txt"] != c2["count1.txt"])
 
     def test__ne__(self):
-        with WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt') as c1:
-            with WritableCollection() as c2:
+        with Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt') as c1:
+            with Collection() as c2:
                 with c2.open("count1.txt", "w") as f:
                     f.write("1234567890")
 
@@ -454,7 +455,7 @@ class ArvadosFileReadTestCase(unittest.TestCase, StreamRetryTestMixin):
                 n += k.size
             except ValueError:
                 pass
-        col = ReadOnlyCollection(keep_client=self.keep_client())
+        col = Collection(keep_client=self.keep_client())
         col._my_block_manager().prefetch_enabled = False
         af = ArvadosFile(col,
                          stream=stream,
@@ -487,7 +488,7 @@ class ArvadosFileReadlinesTestCase(ArvadosFileReadTestCase):
 class BlockManagerTest(unittest.TestCase):
     def test_bufferblock_append(self):
         keep = ArvadosFileWriterTestCase.MockKeep({})
-        blockmanager = arvados.arvfile.BlockManager(keep)
+        blockmanager = arvados.arvfile._BlockManager(keep)
         bufferblock = blockmanager.alloc_bufferblock()
         bufferblock.append("foo")
 
@@ -501,20 +502,20 @@ class BlockManagerTest(unittest.TestCase):
         self.assertEqual(bufferblock.buffer_view[0:6], "foobar")
         self.assertEqual(bufferblock.locator(), "3858f62230ac3c915f300c664312c63f+6")
 
-        bufferblock.set_state(arvados.arvfile.BufferBlock.PENDING)
+        bufferblock.set_state(arvados.arvfile._BufferBlock.PENDING)
         with self.assertRaises(arvados.errors.AssertionError):
             bufferblock.append("bar")
 
     def test_bufferblock_dup(self):
         keep = ArvadosFileWriterTestCase.MockKeep({})
-        blockmanager = arvados.arvfile.BlockManager(keep)
+        blockmanager = arvados.arvfile._BlockManager(keep)
         bufferblock = blockmanager.alloc_bufferblock()
         bufferblock.append("foo")
 
         self.assertEqual(bufferblock.size(), 3)
         self.assertEqual(bufferblock.buffer_view[0:3], "foo")
         self.assertEqual(bufferblock.locator(), "acbd18db4cc2f85cedef654fccc4a4d8+3")
-        bufferblock.set_state(arvados.arvfile.BufferBlock.PENDING)
+        bufferblock.set_state(arvados.arvfile._BufferBlock.PENDING)
 
         bufferblock2 = blockmanager.dup_block(bufferblock, None)
         self.assertNotEqual(bufferblock.blockid, bufferblock2.blockid)
@@ -531,7 +532,7 @@ class BlockManagerTest(unittest.TestCase):
 
     def test_bufferblock_get(self):
         keep = ArvadosFileWriterTestCase.MockKeep({"781e5e245d69b566979b86e28d23f2c7+10": "0123456789"})
-        blockmanager = arvados.arvfile.BlockManager(keep)
+        blockmanager = arvados.arvfile._BlockManager(keep)
         bufferblock = blockmanager.alloc_bufferblock()
         bufferblock.append("foo")
 
@@ -540,22 +541,22 @@ class BlockManagerTest(unittest.TestCase):
 
     def test_bufferblock_commit(self):
         mockkeep = mock.MagicMock()
-        blockmanager = arvados.arvfile.BlockManager(mockkeep)
+        blockmanager = arvados.arvfile._BlockManager(mockkeep)
         bufferblock = blockmanager.alloc_bufferblock()
         bufferblock.append("foo")
         blockmanager.commit_all()
         self.assertTrue(mockkeep.put.called)
-        self.assertEqual(bufferblock.state(), arvados.arvfile.BufferBlock.COMMITTED)
+        self.assertEqual(bufferblock.state(), arvados.arvfile._BufferBlock.COMMITTED)
         self.assertIsNone(bufferblock.buffer_view)
 
 
     def test_bufferblock_commit_with_error(self):
         mockkeep = mock.MagicMock()
         mockkeep.put.side_effect = arvados.errors.KeepWriteError("fail")
-        blockmanager = arvados.arvfile.BlockManager(mockkeep)
+        blockmanager = arvados.arvfile._BlockManager(mockkeep)
         bufferblock = blockmanager.alloc_bufferblock()
         bufferblock.append("foo")
         with self.assertRaises(arvados.errors.KeepWriteError) as err:
             blockmanager.commit_all()
         self.assertEquals(str(err.exception), "Error writing some blocks: acbd18db4cc2f85cedef654fccc4a4d8+3 raised KeepWriteError (fail)")
-        self.assertEqual(bufferblock.state(), arvados.arvfile.BufferBlock.PENDING)
+        self.assertEqual(bufferblock.state(), arvados.arvfile._BufferBlock.PENDING)
index de06b16f36a1bdb5dbf4e46113f6060ec6e09a81..aebfbd0724abe41f9941a6dd72a5593777c6cb89 100644 (file)
@@ -13,10 +13,10 @@ import tempfile
 import unittest
 
 import run_test_server
-import arvados_testutil as tutil
-from arvados.ranges import Range, LocatorAndRange
-from arvados.collection import import_manifest, export_manifest, ReadOnlyCollection, WritableCollection
+from arvados._ranges import Range, LocatorAndRange
+from arvados.collection import Collection, CollectionReader
 from arvados.arvfile import SYNC_EXPLICIT
+import arvados_testutil as tutil
 
 class TestResumableWriter(arvados.ResumableCollectionWriter):
     KEEP_BLOCK_SIZE = 1024  # PUT to Keep every 1K.
@@ -546,9 +546,8 @@ class CollectionReaderTestCase(unittest.TestCase, CollectionTestMixin):
 
     def test_uuid_init_failure_raises_api_error(self):
         client = self.api_client_mock(500)
-        reader = arvados.CollectionReader(self.DEFAULT_UUID, api_client=client)
         with self.assertRaises(arvados.errors.ApiError):
-            reader.manifest_text()
+            reader = arvados.CollectionReader(self.DEFAULT_UUID, api_client=client)
 
     def test_locator_init(self):
         client = self.api_client_mock(200)
@@ -571,11 +570,10 @@ class CollectionReaderTestCase(unittest.TestCase, CollectionTestMixin):
     def test_uuid_init_no_fallback_to_keep(self):
         # Do not look up a collection UUID in Keep.
         client = self.api_client_mock(404)
-        reader = arvados.CollectionReader(self.DEFAULT_UUID,
-                                          api_client=client)
         with tutil.mock_get_responses(self.DEFAULT_MANIFEST, 200):
             with self.assertRaises(arvados.errors.ApiError):
-                reader.manifest_text()
+                reader = arvados.CollectionReader(self.DEFAULT_UUID,
+                                                  api_client=client)
 
     def test_try_keep_first_if_permission_hint(self):
         # To verify that CollectionReader tries Keep first here, we
@@ -651,12 +649,6 @@ class CollectionReaderTestCase(unittest.TestCase, CollectionTestMixin):
         cfile = reader.open('./foo')
         self.check_open_file(cfile, '.', 'foo', 3)
 
-    def test_open_collection_file_two_arguments(self):
-        client = self.api_client_mock(200)
-        reader = arvados.CollectionReader(self.DEFAULT_UUID, api_client=client)
-        cfile = reader.open('.', 'foo')
-        self.check_open_file(cfile, '.', 'foo', 3)
-
     def test_open_deep_file(self):
         coll_name = 'collection_with_files_in_subdir'
         client = self.api_client_mock(200)
@@ -670,12 +662,12 @@ class CollectionReaderTestCase(unittest.TestCase, CollectionTestMixin):
     def test_open_nonexistent_stream(self):
         client = self.api_client_mock(200)
         reader = arvados.CollectionReader(self.DEFAULT_UUID, api_client=client)
-        self.assertRaises(ValueError, reader.open, './nonexistent', 'foo')
+        self.assertRaises(IOError, reader.open, './nonexistent/foo')
 
     def test_open_nonexistent_file(self):
         client = self.api_client_mock(200)
         reader = arvados.CollectionReader(self.DEFAULT_UUID, api_client=client)
-        self.assertRaises(ValueError, reader.open, '.', 'nonexistent')
+        self.assertRaises(IOError, reader.open, 'nonexistent')
 
 
 @tutil.skip_sleep
@@ -816,75 +808,70 @@ class CollectionWriterTestCase(unittest.TestCase, CollectionTestMixin):
 
 
 class NewCollectionTestCase(unittest.TestCase, CollectionTestMixin):
-    def test_import_export_manifest(self):
-        m1 = """. 5348b82a029fd9e971a811ce1f71360b+43 0:43:md5sum.txt
-. 085c37f02916da1cad16f93c54d899b7+41 0:41:md5sum.txt
-. 8b22da26f9f433dea0a10e5ec66d73ba+43 0:43:md5sum.txt
-"""
-        self.assertEqual(". 5348b82a029fd9e971a811ce1f71360b+43 085c37f02916da1cad16f93c54d899b7+41 8b22da26f9f433dea0a10e5ec66d73ba+43 0:127:md5sum.txt\n", export_manifest(import_manifest(m1)))
 
     def test_init_manifest(self):
         m1 = """. 5348b82a029fd9e971a811ce1f71360b+43 0:43:md5sum.txt
 . 085c37f02916da1cad16f93c54d899b7+41 0:41:md5sum.txt
 . 8b22da26f9f433dea0a10e5ec66d73ba+43 0:43:md5sum.txt
 """
-        self.assertEqual(". 5348b82a029fd9e971a811ce1f71360b+43 085c37f02916da1cad16f93c54d899b7+41 8b22da26f9f433dea0a10e5ec66d73ba+43 0:127:md5sum.txt\n", export_manifest(ReadOnlyCollection(m1)))
+        self.assertEqual(m1, CollectionReader(m1).manifest_text(normalize=False))
+        self.assertEqual(". 5348b82a029fd9e971a811ce1f71360b+43 085c37f02916da1cad16f93c54d899b7+41 8b22da26f9f433dea0a10e5ec66d73ba+43 0:127:md5sum.txt\n", CollectionReader(m1).manifest_text(normalize=True))
 
 
     def test_remove(self):
-        c = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt 0:10:count2.txt\n')
-        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt 0:10:count2.txt\n", export_manifest(c))
+        c = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt 0:10:count2.txt\n')
+        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt 0:10:count2.txt\n", c.manifest_text())
         self.assertIn("count1.txt", c)
         c.remove("count1.txt")
         self.assertNotIn("count1.txt", c)
-        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n", export_manifest(c))
+        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n", c.manifest_text())
 
     def test_remove_in_subdir(self):
-        c = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n')
+        c = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n')
         c.remove("foo/count2.txt")
-        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n", export_manifest(c))
+        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n", c.manifest_text())
 
     def test_remove_empty_subdir(self):
-        c = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n')
+        c = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n')
         c.remove("foo/count2.txt")
         c.remove("foo")
-        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n", export_manifest(c))
+        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n", c.manifest_text())
 
     def test_remove_nonempty_subdir(self):
-        c = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n')
+        c = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n')
         with self.assertRaises(IOError):
             c.remove("foo")
         c.remove("foo", recursive=True)
-        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n", export_manifest(c))
+        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n", c.manifest_text())
 
     def test_copy_to_file_in_dir(self):
-        c = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
+        c = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
         c.copy("count1.txt", "foo/count2.txt")
-        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n", export_manifest(c))
+        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n", c.manifest_text())
 
     def test_copy_file(self):
-        c = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
+        c = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
         c.copy("count1.txt", "count2.txt")
         self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt 0:10:count2.txt\n", c.manifest_text())
 
     def test_copy_to_existing_dir(self):
-        c = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n')
+        c = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n')
         c.copy("count1.txt", "foo")
-        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt 0:10:count2.txt\n", export_manifest(c))
+        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt 0:10:count2.txt\n", c.manifest_text())
 
     def test_copy_to_new_dir(self):
-        c = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
+        c = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
         c.copy("count1.txt", "foo/")
-        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n", export_manifest(c))
+        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n", c.manifest_text())
 
     def test_clone(self):
-        c = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n')
+        c = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n')
         cl = c.clone()
-        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n", export_manifest(cl))
+        self.assertEqual(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n", cl.manifest_text())
 
     def test_diff_del_add(self):
-        c1 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
-        c2 = WritableCollection('. 5348b82a029fd9e971a811ce1f71360b+43 0:10:count2.txt\n')
+        c1 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
+        c2 = Collection('. 5348b82a029fd9e971a811ce1f71360b+43 0:10:count2.txt\n')
         d = c2.diff(c1)
         self.assertEqual(d, [('del', './count2.txt', c2["count2.txt"]),
                              ('add', './count1.txt', c1["count1.txt"])])
@@ -896,8 +883,8 @@ class NewCollectionTestCase(unittest.TestCase, CollectionTestMixin):
         self.assertEqual(c1.manifest_text(), c2.manifest_text())
 
     def test_diff_same(self):
-        c1 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
-        c2 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
+        c1 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
+        c2 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
         d = c2.diff(c1)
         self.assertEqual(d, [])
         d = c1.diff(c2)
@@ -908,8 +895,8 @@ class NewCollectionTestCase(unittest.TestCase, CollectionTestMixin):
         self.assertEqual(c1.manifest_text(), c2.manifest_text())
 
     def test_diff_mod(self):
-        c1 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
-        c2 = WritableCollection('. 5348b82a029fd9e971a811ce1f71360b+43 0:10:count1.txt\n')
+        c1 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
+        c2 = Collection('. 5348b82a029fd9e971a811ce1f71360b+43 0:10:count1.txt\n')
         d = c2.diff(c1)
         self.assertEqual(d, [('mod', './count1.txt', c2["count1.txt"], c1["count1.txt"])])
         d = c1.diff(c2)
@@ -920,8 +907,8 @@ class NewCollectionTestCase(unittest.TestCase, CollectionTestMixin):
         self.assertEqual(c1.manifest_text(), c2.manifest_text())
 
     def test_diff_add(self):
-        c1 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
-        c2 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 5348b82a029fd9e971a811ce1f71360b+43 0:10:count1.txt 10:20:count2.txt\n')
+        c1 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
+        c2 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 5348b82a029fd9e971a811ce1f71360b+43 0:10:count1.txt 10:20:count2.txt\n')
         d = c2.diff(c1)
         self.assertEqual(d, [('del', './count2.txt', c2["count2.txt"])])
         d = c1.diff(c2)
@@ -932,8 +919,8 @@ class NewCollectionTestCase(unittest.TestCase, CollectionTestMixin):
         self.assertEqual(c1.manifest_text(), c2.manifest_text())
 
     def test_diff_add_in_subcollection(self):
-        c1 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
-        c2 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 5348b82a029fd9e971a811ce1f71360b+43 0:10:count2.txt\n')
+        c1 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
+        c2 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 5348b82a029fd9e971a811ce1f71360b+43 0:10:count2.txt\n')
         d = c2.diff(c1)
         self.assertEqual(d, [('del', './foo', c2["foo"])])
         d = c1.diff(c2)
@@ -944,8 +931,8 @@ class NewCollectionTestCase(unittest.TestCase, CollectionTestMixin):
         self.assertEqual(c1.manifest_text(), c2.manifest_text())
 
     def test_diff_del_add_in_subcollection(self):
-        c1 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 5348b82a029fd9e971a811ce1f71360b+43 0:10:count2.txt\n')
-        c2 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 5348b82a029fd9e971a811ce1f71360b+43 0:3:count3.txt\n')
+        c1 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 5348b82a029fd9e971a811ce1f71360b+43 0:10:count2.txt\n')
+        c2 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 5348b82a029fd9e971a811ce1f71360b+43 0:3:count3.txt\n')
 
         d = c2.diff(c1)
         self.assertEqual(d, [('del', './foo/count3.txt', c2.find("foo/count3.txt")),
@@ -959,8 +946,8 @@ class NewCollectionTestCase(unittest.TestCase, CollectionTestMixin):
         self.assertEqual(c1.manifest_text(), c2.manifest_text())
 
     def test_diff_mod_in_subcollection(self):
-        c1 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 5348b82a029fd9e971a811ce1f71360b+43 0:10:count2.txt\n')
-        c2 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt 0:3:foo\n')
+        c1 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n./foo 5348b82a029fd9e971a811ce1f71360b+43 0:10:count2.txt\n')
+        c2 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt 0:3:foo\n')
         d = c2.diff(c1)
         self.assertEqual(d, [('mod', './foo', c2["foo"], c1["foo"])])
         d = c1.diff(c2)
@@ -971,8 +958,8 @@ class NewCollectionTestCase(unittest.TestCase, CollectionTestMixin):
         self.assertEqual(c1.manifest_text(), c2.manifest_text())
 
     def test_conflict_keep_local_change(self):
-        c1 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
-        c2 = WritableCollection('. 5348b82a029fd9e971a811ce1f71360b+43 0:10:count2.txt\n')
+        c1 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n')
+        c2 = Collection('. 5348b82a029fd9e971a811ce1f71360b+43 0:10:count2.txt\n')
         d = c1.diff(c2)
         self.assertEqual(d, [('del', './count1.txt', c1["count1.txt"]),
                              ('add', './count2.txt', c2["count2.txt"])])
@@ -984,8 +971,8 @@ class NewCollectionTestCase(unittest.TestCase, CollectionTestMixin):
         self.assertEqual(c1.manifest_text(), ". 95ebc3c7b3b9f1d2c40fec14415d3cb8+5 5348b82a029fd9e971a811ce1f71360b+43 0:5:count1.txt 5:10:count2.txt\n")
 
     def test_conflict_mod(self):
-        c1 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt')
-        c2 = WritableCollection('. 5348b82a029fd9e971a811ce1f71360b+43 0:10:count1.txt')
+        c1 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt')
+        c2 = Collection('. 5348b82a029fd9e971a811ce1f71360b+43 0:10:count1.txt')
         d = c1.diff(c2)
         self.assertEqual(d, [('mod', './count1.txt', c1["count1.txt"], c2["count1.txt"])])
         with c1.open("count1.txt", "w") as f:
@@ -997,8 +984,8 @@ class NewCollectionTestCase(unittest.TestCase, CollectionTestMixin):
                                  c1.manifest_text()))
 
     def test_conflict_add(self):
-        c1 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n')
-        c2 = WritableCollection('. 5348b82a029fd9e971a811ce1f71360b+43 0:10:count1.txt\n')
+        c1 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count2.txt\n')
+        c2 = Collection('. 5348b82a029fd9e971a811ce1f71360b+43 0:10:count1.txt\n')
         d = c1.diff(c2)
         self.assertEqual(d, [('del', './count2.txt', c1["count2.txt"]),
                              ('add', './count1.txt', c2["count1.txt"])])
@@ -1011,8 +998,8 @@ class NewCollectionTestCase(unittest.TestCase, CollectionTestMixin):
                                  c1.manifest_text()))
 
     def test_conflict_del(self):
-        c1 = WritableCollection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt')
-        c2 = WritableCollection('. 5348b82a029fd9e971a811ce1f71360b+43 0:10:count1.txt')
+        c1 = Collection('. 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt')
+        c2 = Collection('. 5348b82a029fd9e971a811ce1f71360b+43 0:10:count1.txt')
         d = c1.diff(c2)
         self.assertEqual(d, [('mod', './count1.txt', c1["count1.txt"], c2["count1.txt"])])
         c1.remove("count1.txt")
@@ -1023,14 +1010,14 @@ class NewCollectionTestCase(unittest.TestCase, CollectionTestMixin):
                                  c1.manifest_text()))
 
     def test_notify(self):
-        c1 = WritableCollection()
+        c1 = Collection()
         events = []
         c1.subscribe(lambda event, collection, name, item: events.append((event, collection, name, item)))
         f = c1.open("foo.txt", "w")
         self.assertEqual(events[0], (arvados.collection.ADD, c1, "foo.txt", f.arvadosfile))
 
     def test_open_w(self):
-        c1 = WritableCollection(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n")
+        c1 = Collection(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count1.txt\n")
         self.assertEqual(c1["count1.txt"].size(), 10)
         c1.open("count1.txt", "w").close()
         self.assertEqual(c1["count1.txt"].size(), 0)
@@ -1040,8 +1027,12 @@ class CollectionCreateUpdateTest(run_test_server.TestCaseWithServers):
     MAIN_SERVER = {}
     KEEP_SERVER = {}
 
-    def test_create_and_save(self):
-        c = arvados.collection.createWritableCollection("hello world")
+    def create_count_txt(self):
+        # Create an empty collection, save it to the API server, then write a
+        # file, but don't save it.
+
+        c = Collection()
+        c.save_new("CollectionCreateUpdateTest", ensure_unique_name=True)
         self.assertEquals(c.portable_data_hash(), "d41d8cd98f00b204e9800998ecf8427e+0")
         self.assertEquals(c.api_response()["portable_data_hash"], "d41d8cd98f00b204e9800998ecf8427e+0" )
 
@@ -1050,39 +1041,26 @@ class CollectionCreateUpdateTest(run_test_server.TestCaseWithServers):
 
         self.assertEquals(c.manifest_text(), ". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n")
 
-        c.save()
+        return c
 
+    def test_create_and_save(self):
+        c = self.create_count_txt()
+        c.save()
         self.assertTrue(re.match(r"^\. 781e5e245d69b566979b86e28d23f2c7\+10\+A[a-f0-9]{40}@[a-f0-9]{8} 0:10:count.txt$",
                                  c.manifest_text()))
 
 
     def test_create_and_save_new(self):
-        c = arvados.collection.createWritableCollection("hello world")
-        self.assertEquals(c.portable_data_hash(), "d41d8cd98f00b204e9800998ecf8427e+0")
-        self.assertEquals(c.api_response()["portable_data_hash"], "d41d8cd98f00b204e9800998ecf8427e+0" )
-
-        with c.open("count.txt", "w") as f:
-            f.write("0123456789")
-
-        self.assertEquals(c.manifest_text(), ". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n")
-
+        c = self.create_count_txt()
         c.save_new()
-
         self.assertTrue(re.match(r"^\. 781e5e245d69b566979b86e28d23f2c7\+10\+A[a-f0-9]{40}@[a-f0-9]{8} 0:10:count.txt$",
                                  c.manifest_text()))
 
     def test_create_diff_apply(self):
-        c1 = arvados.collection.createWritableCollection("hello world")
-        self.assertEquals(c1.portable_data_hash(), "d41d8cd98f00b204e9800998ecf8427e+0")
-        self.assertEquals(c1.api_response()["portable_data_hash"], "d41d8cd98f00b204e9800998ecf8427e+0" )
-        with c1.open("count.txt", "w") as f:
-            f.write("0123456789")
-
-        self.assertEquals(c1.manifest_text(), ". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n")
-
+        c1 = self.create_count_txt()
         c1.save()
 
-        c2 = WritableCollection(c1._manifest_locator)
+        c2 = Collection(c1._manifest_locator)
         with c2.open("count.txt", "w") as f:
             f.write("abcdefg")
 
@@ -1094,9 +1072,9 @@ class CollectionCreateUpdateTest(run_test_server.TestCaseWithServers):
         self.assertEqual(c1.portable_data_hash(), c2.portable_data_hash())
 
     def test_diff_apply_with_token(self):
-        baseline = ReadOnlyCollection(". 781e5e245d69b566979b86e28d23f2c7+10+A715fd31f8111894f717eb1003c1b0216799dd9ec@54f5dd1a 0:10:count.txt\n")
-        c = WritableCollection(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n")
-        other = ReadOnlyCollection(". 7ac66c0f148de9519b8bd264312c4d64+7+A715fd31f8111894f717eb1003c1b0216799dd9ec@54f5dd1a 0:7:count.txt\n")
+        baseline = CollectionReader(". 781e5e245d69b566979b86e28d23f2c7+10+A715fd31f8111894f717eb1003c1b0216799dd9ec@54f5dd1a 0:10:count.txt\n")
+        c = Collection(". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n")
+        other = CollectionReader(". 7ac66c0f148de9519b8bd264312c4d64+7+A715fd31f8111894f717eb1003c1b0216799dd9ec@54f5dd1a 0:7:count.txt\n")
 
         diff = baseline.diff(other)
         self.assertEqual(diff, [('mod', u'./count.txt', c["count.txt"], other["count.txt"])])
@@ -1107,17 +1085,10 @@ class CollectionCreateUpdateTest(run_test_server.TestCaseWithServers):
 
 
     def test_create_and_update(self):
-        c1 = arvados.collection.createWritableCollection("hello world")
-        self.assertEquals(c1.portable_data_hash(), "d41d8cd98f00b204e9800998ecf8427e+0")
-        self.assertEquals(c1.api_response()["portable_data_hash"], "d41d8cd98f00b204e9800998ecf8427e+0" )
-        with c1.open("count.txt", "w") as f:
-            f.write("0123456789")
-
-        self.assertEquals(c1.manifest_text(), ". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n")
-
+        c1 = self.create_count_txt()
         c1.save()
 
-        c2 = arvados.collection.WritableCollection(c1._manifest_locator)
+        c2 = arvados.collection.Collection(c1._manifest_locator)
         with c2.open("count.txt", "w") as f:
             f.write("abcdefg")
 
@@ -1129,19 +1100,13 @@ class CollectionCreateUpdateTest(run_test_server.TestCaseWithServers):
 
 
     def test_create_and_update_with_conflict(self):
-        c1 = arvados.collection.createWritableCollection("hello world")
-        self.assertEquals(c1.portable_data_hash(), "d41d8cd98f00b204e9800998ecf8427e+0")
-        self.assertEquals(c1.api_response()["portable_data_hash"], "d41d8cd98f00b204e9800998ecf8427e+0" )
-        with c1.open("count.txt", "w") as f:
-            f.write("0123456789")
-
-        self.assertEquals(c1.manifest_text(), ". 781e5e245d69b566979b86e28d23f2c7+10 0:10:count.txt\n")
-
+        c1 = self.create_count_txt()
         c1.save()
+
         with c1.open("count.txt", "w") as f:
             f.write("XYZ")
 
-        c2 = arvados.collection.WritableCollection(c1._manifest_locator)
+        c2 = arvados.collection.Collection(c1._manifest_locator)
         with c2.open("count.txt", "w") as f:
             f.write("abcdefg")
 
index 3436a07a4752553fdadde6ef2163db7c11a6472f..d8b37d8a3ccb1418c7515f03a6034fb47207d6be 100644 (file)
@@ -7,7 +7,7 @@ import arvados.collection
 
 class TestSDK(unittest.TestCase):
 
-    @mock.patch('arvados.api')
+    @mock.patch('arvados.apisetup.api_from_config')
     @mock.patch('arvados.current_task')
     @mock.patch('arvados.current_job')
     def test_one_task_per_input_file_normalize(self, mock_job, mock_task, mock_api):
@@ -40,4 +40,3 @@ class TestSDK(unittest.TestCase):
         # it should now create only one job task and not three.
         arvados.job_setup.one_task_per_input_file(and_end_task=False)
         mock_api('v1').job_tasks().create().execute.assert_called_once_with()
-
index 11ee69493c771d84012a2348b8ffb1eab7b483e5..5bf82ccc5929cb211494812121ce81732675b139 100644 (file)
@@ -9,7 +9,8 @@ import unittest
 import hashlib
 
 import arvados
-from arvados import StreamReader, StreamFileReader, Range
+from arvados import StreamReader, StreamFileReader
+from arvados._ranges import Range
 
 import arvados_testutil as tutil
 import run_test_server