-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
Describe the bug
When you configure an ExpectationStore with a DatabaseStoreBackend and try to delete a suite, a TypeException
is raised.
To Reproduce
I've got a very small project which demonstrates this in action at https://github.com/smcl/gx-dbstore-delete-issue - you just need to ensure you have great-expectations 1.5.x and sqlalchemy installed.
But basically the code looks like the below
import great_expectations as gx
context = gx.get_context(mode="file")
context.suites.add(gx.core.expectation_suite.ExpectationSuite(name="test_suite"))
context.suites.delete("test_suite")
With a very "vanilla" great_expectations.yml with an expectations_store configured as follows:
expectations_store:
# class_name: ExpectationsStore
# store_backend:
# class_name: TupleFilesystemStoreBackend
# base_directory: expectations/
class_name: ExpectationsStore
store_backend:
class_name: DatabaseStoreBackend
credentials:
drivername: sqlite
database: ./gx.db
When you run the script you'll encounter the following Exception:
for key_col, val in zip(self.key_columns, key)
^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'ExpectationSuiteIdentifier' object is not iterable
Expected behavior
The provided app.py
script should terminate without any errors.
Environment (please complete the following information):
- Operating System: Windows
- Great Expectations Version: 1.5.6
- Data Source: n/a
- Cloud environment: n/a
Additional context
I looked into the GX sources to see if I was doing something stupid. The TypeError
is raised inside DatabaseStoreBackend.remove_key
which reports that "'ExpectationSuiteIdentifier' object is not iterable" (code is here) - object in question is the key
parameter below which we pass into zip(...)
:
def remove_key(self, key): # type: ignore[explicit-override] # FIXME
delete_statement = self._table.delete().where(
sa.and_(
*(
getattr(self._table.columns, key_col) == val
for key_col, val in zip(self.key_columns, key)
)
)
)
# ... removed
There is no type annotation for key
here, but this code appears to believe that key
is a collection that can be iterated over ... but in this case it is called indirectly from SuiteFactory.delete
here:
key = self._store.get_key(name=suite.name, id=suite.id)
self._store.remove_key(key=key)
That get_key
method has a type annotation indicating that it returns either GXCloudIdentifier | ExpectationSuiteIdentifier
- neither of these types are iterable so it will obviously cause an exception when it is then passed as an argument into zip()
.