We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
tiledb.open doesn't accept an optional ctx
it accepts a config which creates a ctx, would it make sense to have both?

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `tiledb/highlevel.py`
Content:
```
1 import tiledb
2 from tiledb.libtiledb import *
3 
4 import numpy as np
5 
6 def open(uri, key=None, attr=None, mode='r', config=None):
7     """
8     Open a TileDB array at the given URI
9 
10     :param uri: any TileDB supported URI
11     :param key: encryption key, str or None
12     :param str mode: (default 'r') Open the array object in read 'r' or write 'w' mode
13     :param attr: attribute name to select from a multi-attribute array, str or None
14     :param config: TileDB config dictionary, dict or None
15     :return:
16     """
17     if config:
18         cfg = tiledb.Config(config)
19         ctx = tiledb.Ctx(cfg)
20     else:
21         ctx = default_ctx()
22 
23     schema = ArraySchema.load(uri, ctx=ctx)
24     if not schema:
25         raise Exception("Unable to load tiledb ArraySchema from URI: '{}'".format(uri))
26 
27     if schema.sparse:
28         return tiledb.SparseArray(uri, mode=mode, key=key, attr=attr, ctx=ctx)
29     elif not schema.sparse:
30         return tiledb.DenseArray(uri, mode=mode, key=key, attr=attr, ctx=ctx)
31     else:
32         raise Exception("Unknown TileDB array type")
33 
34 
35 def save(uri, array, config=None, **kw):
36     """
37     Save array-like object at the given URI.
38 
39     :param uri: str or None
40     :param array: array-like object convertible to NumPy
41     :param config: TileDB config dictionary, dict or None
42     :param kw: optional keyword args will be forwarded to tiledb.Array constructor
43     :return:
44     """
45     if not isinstance(array, np.ndarray):
46         raise ValueError("expected NumPy ndarray, not '{}'".format(type(array)))
47     if config:
48         cfg = Config(config)
49         ctx = tiledb.Ctx(cfg)
50     else:
51         ctx = default_ctx()
52 
53     return tiledb.from_numpy(uri, array, ctx=ctx)
54 
55 
56 def empty_like(uri, arr, config=None, key=None, tile=None):
57     """
58     Create and return an empty, writeable DenseArray with schema based on
59     a NumPy-array like object.
60 
61     :param uri:
62     :param arr: NumPy ndarray, or shape tuple
63     :param ctx:
64     :param kw:
65     :return:
66     """
67     if config:
68         cfg = tiledb.Config(config)
69         ctx = tiledb.Ctx(cfg)
70     else:
71         ctx = default_ctx()
72 
73     if arr is ArraySchema:
74         schema = arr
75     else:
76         schema = schema_like(arr, tile=tile, ctx=ctx)
77 
78     tiledb.DenseArray.create(uri, key=key, schema=schema)
79     return tiledb.DenseArray(uri, mode='w', key=key, ctx=ctx)
80 
81 
82 def from_numpy(uri, array, ctx=default_ctx(), **kw):
83     """
84     Convenience method, see `tiledb.DenseArray.from_numpy`
85     """
86     if not isinstance(array, np.ndarray):
87         raise Exception("from_numpy is only currently supported for numpy.ndarray")
88 
89     return DenseArray.from_numpy(uri, array, ctx=ctx, **kw)
90 
91
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/tiledb/highlevel.py b/tiledb/highlevel.py
--- a/tiledb/highlevel.py
+++ b/tiledb/highlevel.py
@@ -3,7 +3,7 @@
 
 import numpy as np
 
-def open(uri, key=None, attr=None, mode='r', config=None):
+def open(uri, key=None, attr=None, mode='r', config=None, ctx=None):
     """
     Open a TileDB array at the given URI
 
@@ -14,10 +14,14 @@
     :param config: TileDB config dictionary, dict or None
     :return:
     """
+    if ctx and config:
+      raise ValueError("Received extra Ctx or Config argument: either one may be provided, but not both")
+
     if config:
         cfg = tiledb.Config(config)
         ctx = tiledb.Ctx(cfg)
-    else:
+
+    if ctx is None:
         ctx = default_ctx()
 
     schema = ArraySchema.load(uri, ctx=ctx)
@@ -88,3 +92,23 @@
 
     return DenseArray.from_numpy(uri, array, ctx=ctx, **kw)
 
+def array_exists(uri, isdense=False, issparse=False):
+    """
+    Check if arrays exists and is open-able at the given URI
+
+    Optionally restrict to `isdense` or `issparse` array types.
+    """
+    try:
+        a = tiledb.open(uri)
+    except TileDBError as exc:
+        return False
+
+    if isdense:
+        rval = not a.schema.sparse
+    elif issparse:
+        rval = a.schema.sparse
+    else:
+        rval = True
+
+    a.close()
+    return rval

{"golden_diff": "diff --git a/tiledb/highlevel.py b/tiledb/highlevel.py\n--- a/tiledb/highlevel.py\n+++ b/tiledb/highlevel.py\n@@ -3,7 +3,7 @@\n \n import numpy as np\n \n-def open(uri, key=None, attr=None, mode='r', config=None):\n+def open(uri, key=None, attr=None, mode='r', config=None, ctx=None):\n     \"\"\"\n     Open a TileDB array at the given URI\n \n@@ -14,10 +14,14 @@\n     :param config: TileDB config dictionary, dict or None\n     :return:\n     \"\"\"\n+    if ctx and config:\n+      raise ValueError(\"Received extra Ctx or Config argument: either one may be provided, but not both\")\n+\n     if config:\n         cfg = tiledb.Config(config)\n         ctx = tiledb.Ctx(cfg)\n-    else:\n+\n+    if ctx is None:\n         ctx = default_ctx()\n \n     schema = ArraySchema.load(uri, ctx=ctx)\n@@ -88,3 +92,23 @@\n \n     return DenseArray.from_numpy(uri, array, ctx=ctx, **kw)\n \n+def array_exists(uri, isdense=False, issparse=False):\n+    \"\"\"\n+    Check if arrays exists and is open-able at the given URI\n+\n+    Optionally restrict to `isdense` or `issparse` array types.\n+    \"\"\"\n+    try:\n+        a = tiledb.open(uri)\n+    except TileDBError as exc:\n+        return False\n+\n+    if isdense:\n+        rval = not a.schema.sparse\n+    elif issparse:\n+        rval = a.schema.sparse\n+    else:\n+        rval = True\n+\n+    a.close()\n+    return rval\n", "issue": "tiledb.open doesn't accept an optional ctx\nit accepts a config which creates a ctx, would it make sense to have both?\n", "before_files": [{"content": "import tiledb\nfrom tiledb.libtiledb import *\n\nimport numpy as np\n\ndef open(uri, key=None, attr=None, mode='r', config=None):\n    \"\"\"\n    Open a TileDB array at the given URI\n\n    :param uri: any TileDB supported URI\n    :param key: encryption key, str or None\n    :param str mode: (default 'r') Open the array object in read 'r' or write 'w' mode\n    :param attr: attribute name to select from a multi-attribute array, str or None\n    :param config: TileDB config dictionary, dict or None\n    :return:\n    \"\"\"\n    if config:\n        cfg = tiledb.Config(config)\n        ctx = tiledb.Ctx(cfg)\n    else:\n        ctx = default_ctx()\n\n    schema = ArraySchema.load(uri, ctx=ctx)\n    if not schema:\n        raise Exception(\"Unable to load tiledb ArraySchema from URI: '{}'\".format(uri))\n\n    if schema.sparse:\n        return tiledb.SparseArray(uri, mode=mode, key=key, attr=attr, ctx=ctx)\n    elif not schema.sparse:\n        return tiledb.DenseArray(uri, mode=mode, key=key, attr=attr, ctx=ctx)\n    else:\n        raise Exception(\"Unknown TileDB array type\")\n\n\ndef save(uri, array, config=None, **kw):\n    \"\"\"\n    Save array-like object at the given URI.\n\n    :param uri: str or None\n    :param array: array-like object convertible to NumPy\n    :param config: TileDB config dictionary, dict or None\n    :param kw: optional keyword args will be forwarded to tiledb.Array constructor\n    :return:\n    \"\"\"\n    if not isinstance(array, np.ndarray):\n        raise ValueError(\"expected NumPy ndarray, not '{}'\".format(type(array)))\n    if config:\n        cfg = Config(config)\n        ctx = tiledb.Ctx(cfg)\n    else:\n        ctx = default_ctx()\n\n    return tiledb.from_numpy(uri, array, ctx=ctx)\n\n\ndef empty_like(uri, arr, config=None, key=None, tile=None):\n    \"\"\"\n    Create and return an empty, writeable DenseArray with schema based on\n    a NumPy-array like object.\n\n    :param uri:\n    :param arr: NumPy ndarray, or shape tuple\n    :param ctx:\n    :param kw:\n    :return:\n    \"\"\"\n    if config:\n        cfg = tiledb.Config(config)\n        ctx = tiledb.Ctx(cfg)\n    else:\n        ctx = default_ctx()\n\n    if arr is ArraySchema:\n        schema = arr\n    else:\n        schema = schema_like(arr, tile=tile, ctx=ctx)\n\n    tiledb.DenseArray.create(uri, key=key, schema=schema)\n    return tiledb.DenseArray(uri, mode='w', key=key, ctx=ctx)\n\n\ndef from_numpy(uri, array, ctx=default_ctx(), **kw):\n    \"\"\"\n    Convenience method, see `tiledb.DenseArray.from_numpy`\n    \"\"\"\n    if not isinstance(array, np.ndarray):\n        raise Exception(\"from_numpy is only currently supported for numpy.ndarray\")\n\n    return DenseArray.from_numpy(uri, array, ctx=ctx, **kw)\n\n", "path": "tiledb/highlevel.py"}], "after_files": [{"content": "import tiledb\nfrom tiledb.libtiledb import *\n\nimport numpy as np\n\ndef open(uri, key=None, attr=None, mode='r', config=None, ctx=None):\n    \"\"\"\n    Open a TileDB array at the given URI\n\n    :param uri: any TileDB supported URI\n    :param key: encryption key, str or None\n    :param str mode: (default 'r') Open the array object in read 'r' or write 'w' mode\n    :param attr: attribute name to select from a multi-attribute array, str or None\n    :param config: TileDB config dictionary, dict or None\n    :return:\n    \"\"\"\n    if ctx and config:\n      raise ValueError(\"Received extra Ctx or Config argument: either one may be provided, but not both\")\n\n    if config:\n        cfg = tiledb.Config(config)\n        ctx = tiledb.Ctx(cfg)\n\n    if ctx is None:\n        ctx = default_ctx()\n\n    schema = ArraySchema.load(uri, ctx=ctx)\n    if not schema:\n        raise Exception(\"Unable to load tiledb ArraySchema from URI: '{}'\".format(uri))\n\n    if schema.sparse:\n        return tiledb.SparseArray(uri, mode=mode, key=key, attr=attr, ctx=ctx)\n    elif not schema.sparse:\n        return tiledb.DenseArray(uri, mode=mode, key=key, attr=attr, ctx=ctx)\n    else:\n        raise Exception(\"Unknown TileDB array type\")\n\n\ndef save(uri, array, config=None, **kw):\n    \"\"\"\n    Save array-like object at the given URI.\n\n    :param uri: str or None\n    :param array: array-like object convertible to NumPy\n    :param config: TileDB config dictionary, dict or None\n    :param kw: optional keyword args will be forwarded to tiledb.Array constructor\n    :return:\n    \"\"\"\n    if not isinstance(array, np.ndarray):\n        raise ValueError(\"expected NumPy ndarray, not '{}'\".format(type(array)))\n    if config:\n        cfg = Config(config)\n        ctx = tiledb.Ctx(cfg)\n    else:\n        ctx = default_ctx()\n\n    return tiledb.from_numpy(uri, array, ctx=ctx)\n\n\ndef empty_like(uri, arr, config=None, key=None, tile=None):\n    \"\"\"\n    Create and return an empty, writeable DenseArray with schema based on\n    a NumPy-array like object.\n\n    :param uri:\n    :param arr: NumPy ndarray, or shape tuple\n    :param ctx:\n    :param kw:\n    :return:\n    \"\"\"\n    if config:\n        cfg = tiledb.Config(config)\n        ctx = tiledb.Ctx(cfg)\n    else:\n        ctx = default_ctx()\n\n    if arr is ArraySchema:\n        schema = arr\n    else:\n        schema = schema_like(arr, tile=tile, ctx=ctx)\n\n    tiledb.DenseArray.create(uri, key=key, schema=schema)\n    return tiledb.DenseArray(uri, mode='w', key=key, ctx=ctx)\n\n\ndef from_numpy(uri, array, ctx=default_ctx(), **kw):\n    \"\"\"\n    Convenience method, see `tiledb.DenseArray.from_numpy`\n    \"\"\"\n    if not isinstance(array, np.ndarray):\n        raise Exception(\"from_numpy is only currently supported for numpy.ndarray\")\n\n    return DenseArray.from_numpy(uri, array, ctx=ctx, **kw)\n\ndef array_exists(uri, isdense=False, issparse=False):\n    \"\"\"\n    Check if arrays exists and is open-able at the given URI\n\n    Optionally restrict to `isdense` or `issparse` array types.\n    \"\"\"\n    try:\n        a = tiledb.open(uri)\n    except TileDBError as exc:\n        return False\n\n    if isdense:\n        rval = not a.schema.sparse\n    elif issparse:\n        rval = a.schema.sparse\n    else:\n        rval = True\n\n    a.close()\n    return rval\n", "path": "tiledb/highlevel.py"}]}