From 301e86c297a2770a35f600bc5e95ef0cac2ef910 Mon Sep 17 00:00:00 2001 From: freol35241 Date: Sat, 25 Feb 2023 22:06:06 +0100 Subject: [PATCH] Updating codebase for breaking changes introduced by bumping the sqlalchemy version --- README.md | 2 ++ custom_components/ltss/__init__.py | 11 ++++++----- custom_components/ltss/manifest.json | 28 ++++++++++++++-------------- custom_components/ltss/models.py | 3 +-- info.md | 2 ++ tests/requirements.txt | 5 +++-- tests/test_databases.py | 6 +++--- 7 files changed, 31 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index f8fe5cc..cfc0f17 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ Long time state storage (LTSS) custom component for Home Assistant ======================================== +**NOTE:** From version 2.0 LTSS requires at least Home Assistant 2023.3 + **NOTE:** Starting 2020-09-13 attributes are stored with type JSONB instead of as a plain string, in addition a GIN index is created on this column by default. At first startup after updating of LTSS, migration of your DB happens automatically. Note that this can take a couple of minutes and HASS will not finish starting (i.e. frontend will not be available) until migration is done. **WARNING:** I take no responsibility for any data loss that may happen as a result of this. Please make sure to backup your data before upgrading! diff --git a/custom_components/ltss/__init__.py b/custom_components/ltss/__init__.py index bbc37cb..abf66ad 100644 --- a/custom_components/ltss/__init__.py +++ b/custom_components/ltss/__init__.py @@ -279,7 +279,8 @@ def _setup_connection(self): inspector = inspect(self.engine) with self.engine.connect() as con: - available_extensions = {row['name']: row['installed_version'] for row in + con = con.execution_options(isolation_level="AUTOCOMMIT") + available_extensions = {row.name: row.installed_version for row in con.execute(text("SELECT name, installed_version FROM pg_available_extensions"))} # create table if necessary @@ -291,7 +292,6 @@ def _setup_connection(self): try: con.execute( text(f"SELECT set_chunk_time_interval('{LTSS.__tablename__}', {self.chunk_time_interval})") - .execution_options(autocommit=True) ) except exc.ProgrammingError as exception: if isinstance(exception.orig, psycopg2.errors.UndefinedTable): @@ -314,11 +314,12 @@ def _setup_connection(self): def _create_table(self, available_extensions): _LOGGER.info("Creating LTSS table") with self.engine.connect() as con: + con = con.execution_options(isolation_level="AUTOCOMMIT") if 'postgis' in available_extensions: _LOGGER.info("PostGIS extension is available, activating location extraction...") con.execute( text("CREATE EXTENSION IF NOT EXISTS postgis CASCADE" - ).execution_options(autocommit=True)) + )) # activate location extraction in model/ORM to add necessary column when calling create_all() LTSS.activate_location_extraction() @@ -329,13 +330,13 @@ def _create_table(self, available_extensions): _LOGGER.info("TimescaleDB extension is available, creating hypertable...") con.execute( text("CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE" - ).execution_options(autocommit=True)) + )) # Create hypertable con.execute(text(f"""SELECT create_hypertable( '{LTSS.__tablename__}', 'time', - if_not_exists => TRUE);""").execution_options(autocommit=True)) + if_not_exists => TRUE);""")) def _close_connection(self): """Close the connection.""" diff --git a/custom_components/ltss/manifest.json b/custom_components/ltss/manifest.json index 69c7e00..07c6a34 100644 --- a/custom_components/ltss/manifest.json +++ b/custom_components/ltss/manifest.json @@ -1,15 +1,15 @@ { - "domain": "ltss", - "version": "1.1.0", - "name": "Long Time State Storage (LTSS)", - "documentation": "https://github.com/freol35241/ltss", - "requirements": [ - "sqlalchemy>=1.0,<2.0", - "psycopg2>=2.8,<3.0", - "geoalchemy2>=0.8,<0.9" - ], - "dependencies": [], - "codeowners": [ - "@freol35241" - ] - } + "domain": "ltss", + "version": "2.0.0", + "name": "Long Time State Storage (LTSS)", + "documentation": "https://github.com/freol35241/ltss", + "requirements": [ + "sqlalchemy>=2.0,<3.0", + "psycopg2>=2.8,<3.0", + "geoalchemy2>=0.8,<1.0" + ], + "dependencies": [], + "codeowners": [ + "@freol35241" + ] +} \ No newline at end of file diff --git a/custom_components/ltss/models.py b/custom_components/ltss/models.py index 9a1b28a..3fccf29 100644 --- a/custom_components/ltss/models.py +++ b/custom_components/ltss/models.py @@ -14,8 +14,7 @@ from sqlalchemy.schema import Index from sqlalchemy.dialects.postgresql import JSONB from geoalchemy2 import Geometry -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import column_property +from sqlalchemy.orm import column_property, declarative_base # SQLAlchemy Schema # pylint: disable=invalid-name diff --git a/info.md b/info.md index 3539ed6..1cc1a9b 100644 --- a/info.md +++ b/info.md @@ -1,3 +1,5 @@ +**NOTE:** From version 2.0 LTSS requires at least Home Assistant 2023.3 + **NOTE:** Starting 2020-09-13 attributes are stored with type JSONB instead of as a plain string, in addition a GIN index is created on this column by default. At first startup after updating of LTSS, migration of your DB happens automatically. Note that this can take a couple of minutes and HASS will not finish starting (i.e. frontend will not be available) until migration is done. **WARNING:** I take no responsibility for any data loss that may happen as a result of this. Please make sure to backup your data before upgrading! diff --git a/tests/requirements.txt b/tests/requirements.txt index ec0fcd3..49a2436 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,7 +1,8 @@ docker==5.0.3 GeoAlchemy2==0.11.1 -homeassistant==2021.9.7 psycopg2==2.9.3 +SQLAlchemy==2.0.4 +homeassistant==2021.9.7 + pytest-docker==0.11.0 pytest==7.1.1 -SQLAlchemy==1.4.32 diff --git a/tests/test_databases.py b/tests/test_databases.py index 9a0ac3d..a0d2be0 100644 --- a/tests/test_databases.py +++ b/tests/test_databases.py @@ -88,9 +88,9 @@ def test_default_db(self): @staticmethod def _is_hypertable(con): - timescaledb_version = con.execute("SELECT installed_version " + timescaledb_version = con.execute(text("SELECT installed_version " "FROM pg_available_extensions " - "WHERE name = 'timescaledb'").scalar() + "WHERE name = 'timescaledb'")).scalar() # timescaledb's table/column name changed with v2 if int(timescaledb_version.split('.')[0]) >= 2: @@ -100,7 +100,7 @@ def _is_hypertable(con): query = f"SELECT 1 FROM timescaledb_information.hypertable " f"WHERE table_name = '{LTSS.__tablename__}'" - return 1 == con.execute(query).rowcount + return 1 == con.execute(text(query)).rowcount @staticmethod def _has_columns(con):