From 6929a6c757501da611970ce48733bd86645243d1 Mon Sep 17 00:00:00 2001
From: Andreas Kloeckner <inform@tiker.net>
Date: Fri, 5 Oct 2012 02:21:12 -0400
Subject: [PATCH] Clean up Array constructor, remove some deprecated stuff.

---
 doc/source/array.rst |  18 +++---
 doc/source/misc.rst  |   2 +
 pyopencl/array.py    | 142 ++++++++++++++++++-------------------------
 3 files changed, 70 insertions(+), 92 deletions(-)

diff --git a/doc/source/array.rst b/doc/source/array.rst
index cf0f080c..b8276109 100644
--- a/doc/source/array.rst
+++ b/doc/source/array.rst
@@ -112,23 +112,21 @@ The :class:`Array` Class
 
     An alias for :class:`pyopencl.tools.CLAllocator`.
 
-.. class:: Array(cqa, shape, dtype, order="C", *, allocator=None, base=None, data=None, queue=None)
+.. class:: Array(cqa, shape, dtype, order="C", *, allocator=None, base=None, data=None)
 
     A :class:`numpy.ndarray` work-alike that stores its data and performs its
     computations on the compute device.  *shape* and *dtype* work exactly as in
     :mod:`numpy`.  Arithmetic methods in :class:`Array` support the
     broadcasting of scalars. (e.g. `array+5`)
 
-    *cqa* can be a :class:`pyopencl.Context`, :class:`pyopencl.CommandQueue`
-    or an allocator, as described below. If it is either of the latter two, the *queue*
-    or *allocator* arguments may not be passed.
+    *cqa* must be a :class:`pyopencl.CommandQueue`. *cqa*
+    specifies the queue in which the array carries out its
+    computations by default. *cqa* will at some point be renamed *queue*,
+    so it should be considered 'positional-only'.
 
-    *queue* (or *cqa*, as the case may be) specifies the queue in which the array
-    carries out its computations by default.
-
-    *allocator* is a callable that, upon being called with an argument of the number
-    of bytes to be allocated, returns an :class:`pyopencl.Buffer` object.
-    (See :class:`DefaultAllocator`.)
+    *allocator* may be `None` or a callable that, upon being called with an
+    argument of the number of bytes to be allocated, returns an
+    :class:`pyopencl.Buffer` object.  (See :class:`DefaultAllocator`.)
 
     .. versionchanged:: 2011.1
         Renamed *context* to *cqa*, made it general-purpose.
diff --git a/doc/source/misc.rst b/doc/source/misc.rst
index f6f456a8..0d4f937e 100644
--- a/doc/source/misc.rst
+++ b/doc/source/misc.rst
@@ -89,6 +89,8 @@ Version 2012.2
   `their programming guide <http://developer.amd.com/sdks/AMDAPPSDK/assets/AMD_Accelerated_Parallel_Processing_OpenCL_Programming_Guide.pdf>`_.
 * Deprecated :func:`pyopencl.tools.register_dtype` in favor of
   :func:`pyopencl.tools.get_or_register_dtype`.
+* Clean up the :class:`pyopencl.array.Array` constructor interface. Deprecate
+  arrays with :attr:`pyopencl.array.Array.queue` equal to *None*.
 
 Version 2012.1
 --------------
diff --git a/pyopencl/array.py b/pyopencl/array.py
index fd40e16c..d03dd596 100644
--- a/pyopencl/array.py
+++ b/pyopencl/array.py
@@ -195,18 +195,6 @@ def elwise_kernel_runner(kernel_getter):
 
 DefaultAllocator = cl.CLAllocator
 
-
-
-
-def _should_be_cqa(what):
-    from warnings import warn
-    warn("'%s' should be specified as the frst"
-            "('cqa') argument, "
-            "not in the '%s' keyword argument. "
-            "This will be continue to be accepted througout "
-            "versions 2011.x of PyOpenCL." % (what, what),
-            DeprecationWarning, 3)
-
 # }}}
 
 # {{{ array class
@@ -221,7 +209,15 @@ class Array(object):
 
     def __init__(self, cqa, shape, dtype, order="C", allocator=None,
             data=None, queue=None, strides=None):
-        # {{{ backward compatibility for pre-cqa days
+        # {{{ backward compatibility
+
+        from warnings import warn
+        if queue is not None:
+            warn("Passing the queue to the array through anything but the "
+                    "first argument of the Array constructor is deprecated. "
+                    "This will be continue to be accepted throughout the 2013.[0-6] "
+                    "versions of PyOpenCL.",
+                    DeprecationWarning, 2)
 
         if isinstance(cqa, cl.CommandQueue):
             if queue is not None:
@@ -229,27 +225,37 @@ class Array(object):
                         "'queue' arguments")
             queue = cqa
 
-            if allocator is None:
-                context = queue.context
-                allocator = DefaultAllocator(context)
-
         elif isinstance(cqa, cl.Context):
-            if queue is not None:
-                _should_be_cqa("queue")
+            warn("Passing a context for the 'cqa' parameter is deprecated. "
+                    "This usage will be continue to be accepted throughout the 2013.[0-6] "
+                    "versions of PyOpenCL.",
+                    DeprecationWarning, 2)
 
+            if queue is not None:
+                raise TypeError("may not pass a context and a queue "
+                        "(just pass the queue)")
             if allocator is not None:
-                _should_be_cqa("allocator")
-            else:
-                allocator = DefaultAllocator(cqa)
+                raise TypeError("may not pass a context and an allocator "
+                        "(just pass the queue)")
 
         else:
             # cqa is assumed to be an allocator
+            warn("Passing an allocator for the 'cqa' parameter is deprecated. "
+                    "This usage will be continue to be accepted throughout the 2013.[0-6] "
+                    "versions of PyOpenCL.",
+                    DeprecationWarning, 2)
             if allocator is not None:
                 raise TypeError("can't specify allocator in 'cqa' and "
                         "'allocator' arguments")
 
             allocator = cqa
 
+        if queue is None:
+            warn("Queue-less arrays are deprecated. "
+                    "They will continue to work throughout the 2013.[0-6] "
+                    "versions of PyOpenCL.",
+                    DeprecationWarning, 2)
+
         # }}}
 
         # invariant here: allocator, queue set
@@ -298,12 +304,20 @@ class Array(object):
         self.strides = strides
 
         self.size = s
-        self.nbytes = self.dtype.itemsize * self.size
+        nbytes = self.nbytes = self.dtype.itemsize * self.size
 
         self.allocator = allocator
+
         if data is None:
             if self.size:
-                self.data = self.allocator(self.size * self.dtype.itemsize)
+                if allocator is None:
+                    # FIXME remove me when queues become required
+                    if queue is not None:
+                        context = queue.context
+
+                    self.data = cl.Buffer(context, cl.mem_flags.READ_WRITE, nbytes)
+                else:
+                    self.data = self.allocator(self.size * self.dtype.itemsize)
             else:
                 self.data = None
         else:
@@ -858,52 +872,30 @@ def as_strided(ary, shape=None, strides=None):
 
 # {{{ creation helpers
 
-def to_device(*args, **kwargs):
+def to_device(queue, ary, allocator=None, async=False):
     """Converts a numpy array to a :class:`Array`."""
 
-    def _to_device(queue, ary, allocator=None, async=False):
-        if ary.dtype == object:
-            raise RuntimeError("to_device does not work on object arrays.")
-
-        result = Array(queue, ary.shape, ary.dtype,
-                        allocator=allocator, strides=ary.strides)
-        result.set(ary, async=async)
-        return result
-
-    if isinstance(args[0], cl.Context):
-        from warnings import warn
-        warn("Passing a context as first argument is deprecated. "
-            "This will be continue to be accepted througout "
-            "versions 2011.x of PyOpenCL.",
-            DeprecationWarning, 2)
-        args = args[1:]
+    if ary.dtype == object:
+        raise RuntimeError("to_device does not work on object arrays.")
 
-    return _to_device(*args, **kwargs)
+    result = Array(queue, ary.shape, ary.dtype,
+                    allocator=allocator, strides=ary.strides)
+    result.set(ary, async=async)
+    return result
 
 
 
 
 empty = Array
 
-def zeros(*args, **kwargs):
+def zeros(queue, shape, dtype, order="C", allocator=None):
     """Returns an array of the given shape and dtype filled with 0's."""
 
-    def _zeros(queue, shape, dtype, order="C", allocator=None):
-        result = Array(queue, shape, dtype,
-                order=order, allocator=allocator)
-        zero = np.zeros((), dtype)
-        result.fill(zero)
-        return result
-
-    if isinstance(args[0], cl.Context):
-        from warnings import warn
-        warn("Passing a context as first argument is deprecated. "
-            "This will be continue to be accepted througout "
-            "versions 2011.x of PyOpenCL.",
-            DeprecationWarning, 2)
-        args = args[1:]
-
-    return _zeros(*args, **kwargs)
+    result = Array(queue, shape, dtype,
+            order=order, allocator=allocator)
+    zero = np.zeros((), dtype)
+    result.fill(zero)
+    return result
 
 def empty_like(ary):
     return ary._new_with_changes(data=None)
@@ -920,7 +912,15 @@ def _arange_knl(result, start, step):
     return elementwise.get_arange_kernel(
             result.context, result.dtype)
 
-def _arange(queue, *args, **kwargs):
+def arange(queue, *args, **kwargs):
+    """Create an array filled with numbers spaced `step` apart,
+    starting from `start` and ending at `stop`.
+
+    For floating point arguments, the length of the result is
+    `ceil((stop - start)/step)`.  This rule may result in the last
+    element of the result being greater than stop.
+    """
+
     # argument processing -----------------------------------------------------
 
     # Yuck. Thanks, numpy developers. ;)
@@ -992,28 +992,6 @@ def _arange(queue, *args, **kwargs):
     _arange_knl(result, start, step, queue=queue)
     return result
 
-
-
-
-def arange(*args, **kwargs):
-    """Create an array filled with numbers spaced `step` apart,
-    starting from `start` and ending at `stop`.
-
-    For floating point arguments, the length of the result is
-    `ceil((stop - start)/step)`.  This rule may result in the last
-    element of the result being greater than stop.
-    """
-
-    if isinstance(args[0], cl.Context):
-        from warnings import warn
-        warn("Passing a context as first argument is deprecated. "
-            "This will be continue to be accepted througout "
-            "versions 2011.x of PyOpenCL.",
-            DeprecationWarning, 2)
-        args = args[1:]
-
-    return _arange(*args, **kwargs)
-
 # }}}
 
 # {{{ take/put
-- 
GitLab