Repository: TileDB-Inc/TileDB-Py
Pull request #2025 (2024-07-31 15:02:59)

Expose `setup.py` flag to enable deprecations
In https://github.com/TileDB-Inc/TileDB-Py/pull/2023, `TILEDB_REMOVE_DEPRECATIONS` macro was defined.
It would be good to also have this functionality in `setup.py`.

Right now, the default behavior is to remove deprecations when build TileDB-Py. In core, the default is to enable them.
Should we keep the logic, or follow the core's?

kounelisagis: > I believe that you also need to call:
> 
> ```
> parser.add_argument("--enable_deprecations", action="store_true")
> ```
> 
> Also try this command out, by for example adding
> 
> ```
> message(FATAL_ERROR "I AM HERE")
> ```
> 
> into CMake's IF condition checking TILEDB_REMOVE_DEPRECATIONS and if it fails it means that you set the variable correctly

@dudoslav you are right, thanks!

Tested with:
```
if (TILEDB_REMOVE_DEPRECATIONS)
    message(FATAL_ERROR "DEPRECATIONS REMOVED")
    target_compile_definitions(
        cc
        PRIVATE
        TILEDB_REMOVE_DEPRECATIONS
    )
else()
    message(FATAL_ERROR "DEPRECATIONS NOT REMOVED")
endif()
```

Patch:
diff --git a/doc/source/python-api.rst b/doc/source/python-api.rst
index 481ab0e5..d72664a9 100644
--- a/doc/source/python-api.rst
+++ b/doc/source/python-api.rst
@@ -200,13 +200,18 @@ Fragment Info
 .. autoclass:: tiledb.FragmentInfo
    :members:
 
+Enumeration
+------------
+
+.. autoclass:: tiledb.Enumeration
+   :members:
+
 Exceptions
 ----------
 
 .. autoexception:: tiledb.TileDBError
    :members:
 
-
 VFS
 ---
 
diff --git a/pyproject.toml b/pyproject.toml
index ea0ffae7..34cee5d5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -2,7 +2,7 @@
 requires = [
     "scikit-build-core",
     "pybind11",
-    "Cython",
+    "Cython>=3",
     "numpy==1.17.* ; python_version == '3.8' and platform_machine not in 'arm64|aarch64'",
     "numpy==1.19.* ; python_version == '3.8' and platform_machine == 'aarch64'",
     "numpy==1.21.* ; python_version == '3.8' and platform_machine == 'arm64'",
diff --git a/setup.py b/setup.py
index fe2b090e..4e67a292 100644
--- a/setup.py
+++ b/setup.py
@@ -8,6 +8,7 @@ def main():
     parser.add_argument("command", choices=["install", "develop"])
     parser.add_argument("--tiledb", type=str, required=False)
     parser.add_argument("--debug", action="store_true")
+    parser.add_argument("--enable-deprecations", action="store_true", required=False)
     parser.add_argument("-v", action="store_true")
     args = parser.parse_args()
 
@@ -29,6 +30,9 @@ def main():
     if args.debug:
         cmd.append(f"-Cskbuild.cmake.build-type=Debug")
 
+    if args.enable_deprecations:
+        cmd.append(f"-Cskbuild.cmake.define.TILEDB_REMOVE_DEPRECATIONS=OFF")
+
     if args.v:
         cmd.append("-v")
 
diff --git a/tiledb/ctx.py b/tiledb/ctx.py
index 05d2b85b..b4898f37 100644
--- a/tiledb/ctx.py
+++ b/tiledb/ctx.py
@@ -136,10 +136,36 @@ class Config(lt.Config):
                 return False
         return True
 
+    unserialized_params_ = {
+        "vfs.azure.storage_account_name",
+        "vfs.azure.storage_account_key",
+        "vfs.azure.storage_sas_token",
+        "vfs.s3.proxy_username",
+        "vfs.s3.proxy_password",
+        "vfs.s3.aws_access_key_id",
+        "vfs.s3.aws_secret_access_key",
+        "vfs.s3.aws_session_token",
+        "vfs.s3.aws_role_arn",
+        "vfs.s3.aws_external_id",
+        "vfs.s3.aws_load_frequency",
+        "vfs.s3.aws_session_name",
+        "vfs.gcs.service_account_key",
+        "vfs.gcs.workload_identity_configuration",
+        "vfs.gcs.impersonate_service_account",
+        "rest.username",
+        "rest.password",
+        "rest.token",
+    }
+
     def __repr__(self):
         colnames = ["Parameter", "Value"]
         params = list(self.keys())
         values = list(map(repr, self.values()))
+        # for unserialized params, we don't want to print their values
+        values = [
+            "*" * 10 if p in self.unserialized_params_ and v != "''" else v
+            for i, (p, v) in enumerate(zip(params, values))
+        ]
         colsizes = [
             max(len(colnames[0]), *map(len, (p for p in params))),
             max(len(colnames[1]), *map(len, (v for v in values))),
@@ -163,6 +189,11 @@ class Config(lt.Config):
 
         params = list(self.keys())
         values = list(map(repr, self.values()))
+        # for unserialized params, we don't want to print their values
+        values = [
+            "*" * 10 if p in self.unserialized_params_ and v != "''" else v
+            for i, (p, v) in enumerate(zip(params, values))
+        ]
 
         for p, v in zip(params, values):
             output.write("<tr>")
diff --git a/tiledb/enumeration.py b/tiledb/enumeration.py
index 5cafbd48..2bd7e930 100644
--- a/tiledb/enumeration.py
+++ b/tiledb/enumeration.py
@@ -101,6 +101,7 @@ class Enumeration(CtxMixin, lt.Enumeration):
     def extend(self, values: Sequence[Any]) -> Enumeration:
         """Add additional values to the enumeration.
 
+        :param values: The values to add to the enumeration
         :rtype: Enumeration
         """
         values = np.array(values)


Test patch:
diff --git a/tiledb/tests/test_context_and_config.py b/tiledb/tests/test_context_and_config.py
index db4d6b86..05433899 100644
--- a/tiledb/tests/test_context_and_config.py
+++ b/tiledb/tests/test_context_and_config.py
@@ -187,6 +187,72 @@ class TestConfig(DiskTestCase):
         assert issubclass(type(config), tiledb.libtiledb.Config)
         self.assertEqual(config["sm.memory_budget"], "100")
 
+    def test_config_repr_sensitive_params_hidden(self):
+        # checks that the sensitive parameters set are not printed,
+        # sensitive parameters not set are printed as '',
+        # non-sensitive parameters set are printed as is, and
+        # non-sensitive parameters not set are not hidden (some are empty, some are default)
+
+        unserialized_params_ = {
+            "vfs.azure.storage_account_name",
+            "vfs.azure.storage_account_key",
+            "vfs.azure.storage_sas_token",
+            "vfs.s3.proxy_username",
+            "vfs.s3.proxy_password",
+            "vfs.s3.aws_access_key_id",
+            "vfs.s3.aws_secret_access_key",
+            "vfs.s3.aws_session_token",
+            "vfs.s3.aws_role_arn",
+            "vfs.s3.aws_external_id",
+            "vfs.s3.aws_load_frequency",
+            "vfs.s3.aws_session_name",
+            "vfs.gcs.service_account_key",
+            "vfs.gcs.workload_identity_configuration",
+            "vfs.gcs.impersonate_service_account",
+            "rest.username",
+            "rest.password",
+            "rest.token",
+        }
+
+        random_sensitive_params = {
+            "vfs.azure.storage_account_name": "myaccount",
+            "vfs.s3.aws_access_key_id": "myaccesskey",
+            "vfs.gcs.service_account_key": "myserviceaccountkey",
+            "rest.username": "myusername",
+        }
+
+        random_non_sensitive_params = {
+            "rest.use_refactored_array_open": "false",
+            "rest.use_refactored_array_open_and_query_submit": "true",
+            "sm.allow_separate_attribute_writes": "true",
+            "sm.allow_updates_experimental": "false",
+        }
+
+        config = tiledb.Config()
+
+        for param, value in random_sensitive_params.items():
+            config[param] = value
+
+        for param, value in random_non_sensitive_params.items():
+            config[param] = value
+
+        # skip first two lines
+        for line in repr(config).split("\n")[2:]:
+            param, value = line.split("|")
+            # remove leading and trailing spaces
+            param = param.strip()
+            value = value.strip()
+            if param in unserialized_params_:
+                if param in random_sensitive_params:
+                    self.assertEqual(value, "*" * 10)
+                else:
+                    self.assertEqual(value, "''")
+            else:
+                if param in random_non_sensitive_params:
+                    self.assertEqual(value, f"'{random_non_sensitive_params[param]}'")
+                else:
+                    self.assertNotEqual(value, "*" * 10)
+
     def test_config_repr_html(self):
         config = tiledb.Config()
         try: