diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4c1644a4c..042fe6c09 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,11 +1,11 @@ repos: - repo: https://github.com/pycqa/flake8 - rev: 6.0.0 # New version tags can be found here: https://github.com/pycqa/flake8/tags + rev: 7.1.1 # New version tags can be found here: https://github.com/pycqa/flake8/tags hooks: - id: flake8 name: flake8 (code linting) - repo: https://github.com/psf/black - rev: 22.10.0 # New version tags can be found here: https://github.com/psf/black/tags + rev: 24.8.0 # New version tags can be found here: https://github.com/psf/black/tags hooks: - id: black name: black (code formatting) diff --git a/Makefile b/Makefile index f66b7d343..070096b71 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,10 @@ install-for-dev: make ensure-deps-folder pip-sync requirements/${PYV}/app.txt requirements/${PYV}/dev.txt requirements/${PYV}/test.txt make install-flexmeasures +# Locally install HiGS on macOS + if [ "$(shell uname)" = "Darwin" ]; then \ + make install-highs-macos; \ + fi install-for-test: make install-pip-tools diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 50331edf1..6fa03dede 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -9,12 +9,16 @@ v0.24.0 | October XX, 2024 New features ------------- -* The asset beliefs chart can now be configured to not combine legends, but show them per plot [see `PR #1176 `_] - +* The data chart on the asset page splits up its color-coded sensor legend when showing more than 7 sensors, becoming a legend per subplot [see `PR #1176 `_ and `PR #1193 `_ +* Speed up loading the users page, by making the pagination backend-based and adding support for that in the API [see `PR #1160 `] +* X-axis labels in CLI plots show datetime values in a readable and informative format [see `PR #1172 `_] +* Speed up loading the accounts page,by making the pagination backend-based and adding support for that in the API [see `PR #1196 `_] Infrastructure / Support ---------------------- +* For MacOS developers, install HiGHS solver automatically [see `PR #1187 `_] + Bugfixes ----------- @@ -30,7 +34,7 @@ New features * New chart type on sensor page: histogram [see `PR #1143 `_] * Add basic sensor info to sensor page [see `PR #1115 `_] * Add `Statistics` table on the sensor page and also add `api/v3_0/sensors//stats` endpoint to get sensor statistics [see `PR #1116 `_] -* Added support for adding custom titles to the graphs on the asset page. This works via an extension to the sensors_to_show format. [see `PR #1125 `_ and `PR #1177 `_] +* Support adding custom titles to the graphs on the asset page, by extending the ``sensors_to_show`` format [see `PR #1125 `_ and `PR #1177 `_] * Support zoom-in action on the asset and sensor charts [see `PR #1130 `_] * Speed up loading the assets page, by making the pagination backend-based and adding support for that in the API, and by enabling to query all accounts one can see in a single call (for admins and consultants) [see `PR #988 `_] * Added Primary and Secondary colors to account for white-labelled UI themes [see `PR #1137 `_] diff --git a/documentation/cli/change_log.rst b/documentation/cli/change_log.rst index 3a1b58fa5..72598db5c 100644 --- a/documentation/cli/change_log.rst +++ b/documentation/cli/change_log.rst @@ -4,14 +4,17 @@ FlexMeasures CLI Changelog ********************** -since v.0.22.0 | June 29, 2024 +since v0.24.0 | October XX, 2024 ================================= +* ``flexmeasures show beliefs`` shows datetime values on x-axis labels. -* Add ``--resolution`` option to ``flexmeasures show chart`` to produce charts in different time resolutions. +since v0.22.0 | June 29, 2024 +================================= +* Add ``--resolution`` option to ``flexmeasures show chart`` to produce charts in different time resolutions. -since v.0.21.0 | April 16, 2024 +since v0.21.0 | April 16, 2024 ================================= * Include started, deferred and scheduled jobs in the overview printed by the CLI command ``flexmeasures jobs show-queues``. diff --git a/flexmeasures/api/common/schemas/users.py b/flexmeasures/api/common/schemas/users.py index db50b9d1d..20c4c8a3a 100644 --- a/flexmeasures/api/common/schemas/users.py +++ b/flexmeasures/api/common/schemas/users.py @@ -38,8 +38,8 @@ class UserIdField(fields.Integer): """ def __init__(self, *args, **kwargs): - kwargs["load_default"] = ( - lambda: current_user if not current_user.is_anonymous else None + kwargs["load_default"] = lambda: ( + current_user if not current_user.is_anonymous else None ) super().__init__(*args, **kwargs) diff --git a/flexmeasures/api/v3_0/accounts.py b/flexmeasures/api/v3_0/accounts.py index 00005a33c..3e02f95ec 100644 --- a/flexmeasures/api/v3_0/accounts.py +++ b/flexmeasures/api/v3_0/accounts.py @@ -5,14 +5,22 @@ from webargs.flaskparser import use_kwargs, use_args from flask_security import current_user, auth_required from flask_json import as_json +from sqlalchemy import or_, select, func + +from marshmallow import fields +import marshmallow.validate as validate +from flask_sqlalchemy.pagination import SelectPagination + from flexmeasures.auth.policy import user_has_admin_access from flexmeasures.auth.decorators import permission_required_for_context from flexmeasures.data.models.audit_log import AuditLog -from flexmeasures.data.models.user import Account +from flexmeasures.data.models.user import Account, User +from flexmeasures.data.models.generic_assets import GenericAsset from flexmeasures.data.services.accounts import get_accounts, get_audit_log_records from flexmeasures.api.common.schemas.users import AccountIdField from flexmeasures.data.schemas.account import AccountSchema +from flexmeasures.api.common.schemas.generic_assets import SearchFilterField from flexmeasures.utils.time_utils import server_now """ @@ -34,8 +42,25 @@ class AccountAPI(FlaskView): decorators = [auth_required()] @route("", methods=["GET"]) + @use_kwargs( + { + "page": fields.Int( + required=False, validate=validate.Range(min=1), default=1 + ), + "per_page": fields.Int( + required=False, validate=validate.Range(min=1), default=10 + ), + "filter": SearchFilterField(required=False, default=None), + }, + location="query", + ) @as_json - def index(self): + def index( + self, + page: int | None = None, + per_page: int | None = None, + filter: list[str] | None = None, + ): """API endpoint to list all accounts accessible to the current user. .. :quickref: Account; Download account list @@ -43,20 +68,37 @@ def index(self): This endpoint returns all accessible accounts. Accessible accounts are your own account and accounts you are a consultant for, or all accounts for admins. + The endpoint supports pagination of the asset list using the `page` and `per_page` query parameters. + + - If the `page` parameter is not provided, all assets are returned, without pagination information. The result will be a list of assets. + - If a `page` parameter is provided, the response will be paginated, showing a specific number of assets per page as defined by `per_page` (default is 10). + - If a search 'filter' such as 'solar "ACME corp"' is provided, the response will filter out assets where each search term is either present in their name or account name. + The response schema for pagination is inspired by https://datatables.net/manual/server-side#Returned-data + **Example response** An example of one account being returned: .. sourcecode:: json - [ + { + "data" : [ { 'id': 1, 'name': 'Test Account' 'account_roles': [1, 3], 'consultancy_account_id': 2, + 'primary_color': '#1a3443' + 'secondary_color': '#f1a122' + 'logo_url': 'https://example.com/logo.png' } - ] + ], + "num-records" : 1, + "filtered-records" : 1 + + } + + If no pagination is requested, the response only consists of the list under the "data" key. :reqheader Authorization: The authentication token :reqheader Content-Type: application/json @@ -76,7 +118,48 @@ def index(self): else [] ) - return accounts_schema.dump(accounts), 200 + query = db.session.query(Account).filter( + Account.id.in_([a.id for a in accounts]) + ) + + if filter: + search_terms = filter[0].split(" ") + query = query.filter( + or_(*[Account.name.ilike(f"%{term}%") for term in search_terms]) + ) + + if page: + select_pagination: SelectPagination = db.paginate( + query, per_page=per_page, page=page + ) + + accounts_reponse: list = [] + for account in select_pagination.items: + user_count_query = select(func.count(User.id)).where( + User.account_id == account.id + ) + asset_count_query = select(func.count(GenericAsset.id)).where( + GenericAsset.account_id == account.id + ) + user_count = db.session.execute(user_count_query).scalar() + asset_count = db.session.execute(asset_count_query).scalar() + accounts_reponse.append( + { + **account_schema.dump(account), + "user_count": user_count, + "asset_count": asset_count, + } + ) + + response = { + "data": accounts_reponse, + "num-records": select_pagination.total, + "filtered-records": select_pagination.total, + } + else: + response = accounts_schema.dump(query.all(), many=True) + + return response, 200 @route("/", methods=["GET"]) @use_kwargs({"account": AccountIdField(data_key="id")}, location="path") @@ -200,13 +283,14 @@ def patch(self, account_data: dict, id: int, account: Account): "logo_url", "consultancy_account_id", ] - - # Compile modified fields string - modified_fields_str = ", ".join( - field + modified_fields = { + field: getattr(account, field) for field in fields_to_check if account_data.get(field) != getattr(account, field) - ) + } + + # Compile modified fields string + modified_fields_str = ", ".join(modified_fields.keys()) for k, v in account_data.items(): setattr(account, k, v) diff --git a/flexmeasures/api/v3_0/assets.py b/flexmeasures/api/v3_0/assets.py index 54301d029..5262f157b 100644 --- a/flexmeasures/api/v3_0/assets.py +++ b/flexmeasures/api/v3_0/assets.py @@ -1,5 +1,4 @@ from __future__ import annotations - import json from flask import current_app diff --git a/flexmeasures/api/v3_0/tests/utils.py b/flexmeasures/api/v3_0/tests/utils.py index 99e27dc06..1971dc132 100644 --- a/flexmeasures/api/v3_0/tests/utils.py +++ b/flexmeasures/api/v3_0/tests/utils.py @@ -69,9 +69,9 @@ def message_for_trigger_schedule( "duration": "PT24H", # Will be extended in case of targets that would otherwise lie beyond the schedule's end } if unknown_prices: - message[ - "start" - ] = "2040-01-01T00:00:00+01:00" # We have no beliefs in our test database about 2040 prices + message["start"] = ( + "2040-01-01T00:00:00+01:00" # We have no beliefs in our test database about 2040 prices + ) message["flex-model"] = { "soc-at-start": 12.1, # in kWh, according to soc-unit diff --git a/flexmeasures/api/v3_0/users.py b/flexmeasures/api/v3_0/users.py index 287697507..ff6ea6926 100644 --- a/flexmeasures/api/v3_0/users.py +++ b/flexmeasures/api/v3_0/users.py @@ -1,27 +1,33 @@ +from __future__ import annotations from flask_classful import FlaskView, route from marshmallow import fields +import marshmallow.validate as validate from sqlalchemy.exc import IntegrityError -from sqlalchemy import select +from sqlalchemy import and_, select, func +from flask_sqlalchemy.pagination import SelectPagination from webargs.flaskparser import use_kwargs from flask_security import current_user, auth_required from flask_security.recoverable import send_reset_password_instructions from flask_json import as_json -from werkzeug.exceptions import Forbidden, Unauthorized +from werkzeug.exceptions import Forbidden from flexmeasures.auth.policy import check_access from flexmeasures.data.models.audit_log import AuditLog from flexmeasures.data.models.user import User as UserModel, Account from flexmeasures.api.common.schemas.users import AccountIdField, UserIdField +from flexmeasures.api.common.schemas.generic_assets import SearchFilterField +from flexmeasures.api.v3_0.assets import get_accessible_accounts +from flexmeasures.data.queries.users import query_users_by_search_terms +from flexmeasures.data.schemas.account import AccountSchema from flexmeasures.data.schemas.users import UserSchema from flexmeasures.data.services.users import ( - get_users, set_random_password, remove_cookie_and_token_access, get_audit_log_records, ) from flexmeasures.auth.decorators import permission_required_for_context from flexmeasures.data import db -from flexmeasures.utils.time_utils import server_now +from flexmeasures.utils.time_utils import server_now, naturalized_datetime_str """ API endpoints to manage users. @@ -33,6 +39,7 @@ user_schema = UserSchema() users_schema = UserSchema(many=True) partial_user_schema = UserSchema(partial=True) +account_schema = AccountSchema() class UserAPI(FlaskView): @@ -45,13 +52,27 @@ class UserAPI(FlaskView): { "account": AccountIdField(data_key="account_id", load_default=None), "include_inactive": fields.Bool(load_default=False), + "page": fields.Int( + required=False, validate=validate.Range(min=1), default=1 + ), + "per_page": fields.Int( + required=False, validate=validate.Range(min=1), default=1 + ), + "filter": SearchFilterField(required=False, default=None), }, location="query", ) @as_json - def index(self, account: Account, include_inactive: bool = False): - """API endpoint to list all users. - + def index( + self, + account: Account, + include_inactive: bool = False, + page: int | None = None, + per_page: int | None = None, + filter: str | None = None, + ): + """ + API endpoint to list all users. .. :quickref: User; Download user list @@ -91,26 +112,63 @@ def index(self, account: Account, include_inactive: bool = False): :status 403: INVALID_SENDER :status 422: UNPROCESSABLE_ENTITY """ - if account is not None: check_access(account, "read") accounts = [account] else: - accounts = [] - for account in db.session.scalars(select(Account)).all(): - try: - check_access(account, "read") - accounts.append(account) - except (Forbidden, Unauthorized): - pass - - users = [] - for account in accounts: - users += get_users( - account_name=account.name, - only_active=not include_inactive, + accounts = get_accessible_accounts() + + filter_statement = UserModel.account_id.in_([a.id for a in accounts]) + + if include_inactive is False: + filter_statement = and_(filter_statement, UserModel.active.is_(True)) + + query = query_users_by_search_terms( + search_terms=filter, filter_statement=filter_statement + ) + + if page is not None: + num_records = db.session.scalar( + select(func.count(UserModel.id)).where(filter_statement) + ) + paginated_users: SelectPagination = db.paginate( + query, per_page=per_page, page=page ) - return users_schema.dump(users), 200 + + users_response: list = [ + { + **user_schema.dump(user), + "account": account_schema.dump(user.account), + "flexmeasures_roles": [ + role.name for role in user.flexmeasures_roles + ], + "last_login_at": naturalized_datetime_str(user.last_login_at), + "last_seen_at": naturalized_datetime_str(user.last_seen_at), + } + for user in paginated_users.items + ] + response: dict | list = { + "data": users_response, + "num-records": num_records, + "filtered-records": paginated_users.total, + } + else: + users = db.session.execute(query).scalars().all() + + response = [ + { + **user_schema.dump(user), + "account": account_schema.dump(user.account), + "flexmeasures_roles": [ + role.name for role in user.flexmeasures_roles + ], + "last_login_at": naturalized_datetime_str(user.last_login_at), + "last_seen_at": naturalized_datetime_str(user.last_seen_at), + } + for user in users + ] + + return response, 200 @route("/") @use_kwargs({"user": UserIdField(data_key="id")}, location="path") diff --git a/flexmeasures/auth/decorators.py b/flexmeasures/auth/decorators.py index 2655bb42a..76e51b23d 100644 --- a/flexmeasures/auth/decorators.py +++ b/flexmeasures/auth/decorators.py @@ -2,7 +2,6 @@ Auth decorators for endpoints """ - from __future__ import annotations from typing import Callable diff --git a/flexmeasures/auth/error_handling.py b/flexmeasures/auth/error_handling.py index 9d504f815..9b67337bb 100644 --- a/flexmeasures/auth/error_handling.py +++ b/flexmeasures/auth/error_handling.py @@ -5,6 +5,7 @@ Names of Responses have to be kept as they were called in original W3 protocols. See explanation below. """ + from __future__ import annotations from typing import Callable diff --git a/flexmeasures/cli/data_show.py b/flexmeasures/cli/data_show.py index 94d9da8fa..4ca91de6f 100644 --- a/flexmeasures/cli/data_show.py +++ b/flexmeasures/cli/data_show.py @@ -666,17 +666,17 @@ def plot_beliefs( title += f"\nOnly beliefs made before: {belief_time_before}." if source: title += f"\nSource: {source.description}" - title += f"\nThe time resolution (x-axis) is {naturaldelta(resolution)}." uniplot.plot( - [df[col] for col in df.columns], + ys=[df[col] for col in df.columns], + xs=[df.index for _ in df.columns], title=title, color=True, lines=True, y_unit=shared_unit, - legend_labels=df.columns - if shared_unit - else [f"{col} in {s.unit}" for col in df.columns], + legend_labels=( + df.columns if shared_unit else [f"{col} in {s.unit}" for col in df.columns] + ), ) if filepath is not None: df.columns = pd.MultiIndex.from_arrays( diff --git a/flexmeasures/cli/testing.py b/flexmeasures/cli/testing.py index f219cc76b..a444bde6f 100644 --- a/flexmeasures/cli/testing.py +++ b/flexmeasures/cli/testing.py @@ -30,6 +30,7 @@ They are not registered as app command per default, as we don't need to show them to users. """ + # un-comment to use as CLI function # @app.cli.command() def test_making_forecasts(): diff --git a/flexmeasures/cli/tests/test_data_add.py b/flexmeasures/cli/tests/test_data_add.py index da43c1785..8c65ae1d2 100644 --- a/flexmeasures/cli/tests/test_data_add.py +++ b/flexmeasures/cli/tests/test_data_add.py @@ -514,12 +514,12 @@ def test_add_storage_schedule( if storage_power_capacity is not None: if storage_power_capacity == "sensor": - cli_input_params[ - "storage-consumption-capacity" - ] = f"sensor:{power_capacity_sensor}" - cli_input_params[ - "storage-production-capacity" - ] = f"sensor:{power_capacity_sensor}" + cli_input_params["storage-consumption-capacity"] = ( + f"sensor:{power_capacity_sensor}" + ) + cli_input_params["storage-production-capacity"] = ( + f"sensor:{power_capacity_sensor}" + ) else: cli_input_params["storage-consumption-capacity"] = "700kW" @@ -527,9 +527,9 @@ def test_add_storage_schedule( if storage_efficiency is not None: if storage_efficiency == "sensor": - cli_input_params[ - "storage-efficiency" - ] = f"sensor:{storage_efficiency_sensor}" + cli_input_params["storage-efficiency"] = ( + f"sensor:{storage_efficiency_sensor}" + ) else: cli_input_params["storage-efficiency"] = "90%" diff --git a/flexmeasures/conftest.py b/flexmeasures/conftest.py index c7795ded2..b2a42bee9 100644 --- a/flexmeasures/conftest.py +++ b/flexmeasures/conftest.py @@ -504,9 +504,11 @@ def create_assets( for asset_name in ["wind-asset-1", "wind-asset-2", "solar-asset-1"]: asset = GenericAsset( name=asset_name, - generic_asset_type=setup_asset_types["wind"] - if "wind" in asset_name - else setup_asset_types["solar"], + generic_asset_type=( + setup_asset_types["wind"] + if "wind" in asset_name + else setup_asset_types["solar"] + ), owner=setup_accounts["Prosumer"], latitude=10, longitude=100, diff --git a/flexmeasures/data/config.py b/flexmeasures/data/config.py index 246c233e2..f8c98c6c8 100644 --- a/flexmeasures/data/config.py +++ b/flexmeasures/data/config.py @@ -11,7 +11,9 @@ from flexmeasures.data.models import naming_convention -db: sa = None # typed attributes unavailable in flask-sqlalchemy, see https://github.com/pallets/flask-sqlalchemy/issues/867 +db: sa = ( + None # typed attributes unavailable in flask-sqlalchemy, see https://github.com/pallets/flask-sqlalchemy/issues/867 +) Base = None # type: ignore session_options = None diff --git a/flexmeasures/data/migrations/versions/01fe99da5716_initial.py b/flexmeasures/data/migrations/versions/01fe99da5716_initial.py index 0ddd5ed5c..349973282 100644 --- a/flexmeasures/data/migrations/versions/01fe99da5716_initial.py +++ b/flexmeasures/data/migrations/versions/01fe99da5716_initial.py @@ -5,6 +5,7 @@ Create Date: 2018-03-20 10:29:28.864971 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/02ddbbff29a7_naming_conventions.py b/flexmeasures/data/migrations/versions/02ddbbff29a7_naming_conventions.py index 70e94176b..1f31f3e5d 100644 --- a/flexmeasures/data/migrations/versions/02ddbbff29a7_naming_conventions.py +++ b/flexmeasures/data/migrations/versions/02ddbbff29a7_naming_conventions.py @@ -5,6 +5,7 @@ Create Date: 2020-09-17 11:05:37.195404 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/038bab973c40_add_unique_constraint_for_sensor_names_.py b/flexmeasures/data/migrations/versions/038bab973c40_add_unique_constraint_for_sensor_names_.py index 9abe3701f..d5b229a65 100644 --- a/flexmeasures/data/migrations/versions/038bab973c40_add_unique_constraint_for_sensor_names_.py +++ b/flexmeasures/data/migrations/versions/038bab973c40_add_unique_constraint_for_sensor_names_.py @@ -7,6 +7,7 @@ Create Date: 2022-02-16 22:35:26.330950 """ + from alembic import op # revision identifiers, used by Alembic. diff --git a/flexmeasures/data/migrations/versions/04f0e2d2924a_add_source_id_as_primary_key_for_timed_beliefs.py b/flexmeasures/data/migrations/versions/04f0e2d2924a_add_source_id_as_primary_key_for_timed_beliefs.py index fe2d80d88..8e0ff78ca 100644 --- a/flexmeasures/data/migrations/versions/04f0e2d2924a_add_source_id_as_primary_key_for_timed_beliefs.py +++ b/flexmeasures/data/migrations/versions/04f0e2d2924a_add_source_id_as_primary_key_for_timed_beliefs.py @@ -5,6 +5,7 @@ Create Date: 2021-04-10 13:53:22.561718 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/11b735abebe7_create_power_table_and_drop_measurement_table.py b/flexmeasures/data/migrations/versions/11b735abebe7_create_power_table_and_drop_measurement_table.py index 9b5d70487..790294686 100644 --- a/flexmeasures/data/migrations/versions/11b735abebe7_create_power_table_and_drop_measurement_table.py +++ b/flexmeasures/data/migrations/versions/11b735abebe7_create_power_table_and_drop_measurement_table.py @@ -5,6 +5,7 @@ Create Date: 2018-05-29 14:51:30.331230 """ + from alembic import op import sqlalchemy as sa from sqlalchemy.dialects import postgresql diff --git a/flexmeasures/data/migrations/versions/126d65cbe6b4_asset_audit_log.py b/flexmeasures/data/migrations/versions/126d65cbe6b4_asset_audit_log.py index 6f20cd245..6a0a30739 100644 --- a/flexmeasures/data/migrations/versions/126d65cbe6b4_asset_audit_log.py +++ b/flexmeasures/data/migrations/versions/126d65cbe6b4_asset_audit_log.py @@ -5,6 +5,7 @@ Create Date: 2024-05-27 15:48:07.399594 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/1a4f0e5c4b86_unique_userids_in_ds.py b/flexmeasures/data/migrations/versions/1a4f0e5c4b86_unique_userids_in_ds.py index 8926d43bc..3056ef83b 100644 --- a/flexmeasures/data/migrations/versions/1a4f0e5c4b86_unique_userids_in_ds.py +++ b/flexmeasures/data/migrations/versions/1a4f0e5c4b86_unique_userids_in_ds.py @@ -5,6 +5,7 @@ Create Date: 2018-08-16 12:47:38.492823 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/1ae32ffc8c3f_rename_data_source_unique_constraint.py b/flexmeasures/data/migrations/versions/1ae32ffc8c3f_rename_data_source_unique_constraint.py index 9ab2a7387..4eebbeeac 100644 --- a/flexmeasures/data/migrations/versions/1ae32ffc8c3f_rename_data_source_unique_constraint.py +++ b/flexmeasures/data/migrations/versions/1ae32ffc8c3f_rename_data_source_unique_constraint.py @@ -5,6 +5,7 @@ Create Date: 2021-11-11 16:54:09.302274 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/1b64acf01809_forecasting_job_table.py b/flexmeasures/data/migrations/versions/1b64acf01809_forecasting_job_table.py index d7059ae62..54eef6cd5 100644 --- a/flexmeasures/data/migrations/versions/1b64acf01809_forecasting_job_table.py +++ b/flexmeasures/data/migrations/versions/1b64acf01809_forecasting_job_table.py @@ -5,6 +5,7 @@ Create Date: 2018-08-31 15:09:09.462860 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/1bcccdf0c3e1_unique_usernames.py b/flexmeasures/data/migrations/versions/1bcccdf0c3e1_unique_usernames.py index 5047dca67..9cca5c7a1 100644 --- a/flexmeasures/data/migrations/versions/1bcccdf0c3e1_unique_usernames.py +++ b/flexmeasures/data/migrations/versions/1bcccdf0c3e1_unique_usernames.py @@ -5,6 +5,7 @@ Create Date: 2018-08-08 13:39:56.732107 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/1e8d27922f56_create_price_table.py b/flexmeasures/data/migrations/versions/1e8d27922f56_create_price_table.py index 03123d67d..be0c0d0fc 100644 --- a/flexmeasures/data/migrations/versions/1e8d27922f56_create_price_table.py +++ b/flexmeasures/data/migrations/versions/1e8d27922f56_create_price_table.py @@ -5,6 +5,7 @@ Create Date: 2018-05-28 13:30:54.227839 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/202505c5cb06_assets_inflexible_sensors_table_.py b/flexmeasures/data/migrations/versions/202505c5cb06_assets_inflexible_sensors_table_.py index f5a83908d..cc8f16c8d 100644 --- a/flexmeasures/data/migrations/versions/202505c5cb06_assets_inflexible_sensors_table_.py +++ b/flexmeasures/data/migrations/versions/202505c5cb06_assets_inflexible_sensors_table_.py @@ -5,6 +5,7 @@ Create Date: 2024-05-20 22:23:05.406911 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/22ce09690d23_mix_in_timely_beliefs_sensor_with_asset_market_and_weather_sensor.py b/flexmeasures/data/migrations/versions/22ce09690d23_mix_in_timely_beliefs_sensor_with_asset_market_and_weather_sensor.py index e99ac01c2..912669c02 100644 --- a/flexmeasures/data/migrations/versions/22ce09690d23_mix_in_timely_beliefs_sensor_with_asset_market_and_weather_sensor.py +++ b/flexmeasures/data/migrations/versions/22ce09690d23_mix_in_timely_beliefs_sensor_with_asset_market_and_weather_sensor.py @@ -5,6 +5,7 @@ Create Date: 2021-01-31 14:31:16.370110 """ + from alembic import op import json import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/26373d8266db_owner_deletion_deletes_assets_and_power.py b/flexmeasures/data/migrations/versions/26373d8266db_owner_deletion_deletes_assets_and_power.py index ba6d130b2..a5c34ffa4 100644 --- a/flexmeasures/data/migrations/versions/26373d8266db_owner_deletion_deletes_assets_and_power.py +++ b/flexmeasures/data/migrations/versions/26373d8266db_owner_deletion_deletes_assets_and_power.py @@ -5,6 +5,7 @@ Create Date: 2018-08-08 13:45:19.717975 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/2ac7fb39ce0c_add_attribute_column_to_data_source.py b/flexmeasures/data/migrations/versions/2ac7fb39ce0c_add_attribute_column_to_data_source.py index 8698bc3a5..1f7459429 100644 --- a/flexmeasures/data/migrations/versions/2ac7fb39ce0c_add_attribute_column_to_data_source.py +++ b/flexmeasures/data/migrations/versions/2ac7fb39ce0c_add_attribute_column_to_data_source.py @@ -5,6 +5,7 @@ Create Date: 2023-06-05 23:41:31.788961 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/2c9a32614784_rename_data_source_columns_in_power_price_and_weather_tables.py b/flexmeasures/data/migrations/versions/2c9a32614784_rename_data_source_columns_in_power_price_and_weather_tables.py index 861bcb0f9..81087aa77 100644 --- a/flexmeasures/data/migrations/versions/2c9a32614784_rename_data_source_columns_in_power_price_and_weather_tables.py +++ b/flexmeasures/data/migrations/versions/2c9a32614784_rename_data_source_columns_in_power_price_and_weather_tables.py @@ -5,6 +5,7 @@ Create Date: 2018-07-26 15:58:07.780000 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/30f7b63069e1_delete_asset_if_sensor_is_deleted.py b/flexmeasures/data/migrations/versions/30f7b63069e1_delete_asset_if_sensor_is_deleted.py index 0d315ff38..c22d7f70e 100644 --- a/flexmeasures/data/migrations/versions/30f7b63069e1_delete_asset_if_sensor_is_deleted.py +++ b/flexmeasures/data/migrations/versions/30f7b63069e1_delete_asset_if_sensor_is_deleted.py @@ -5,6 +5,7 @@ Create Date: 2022-03-18 14:44:56.718765 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/30fe2267e7d5_add_optional_DataSource_columns_for_model_and_version.py b/flexmeasures/data/migrations/versions/30fe2267e7d5_add_optional_DataSource_columns_for_model_and_version.py index eac278c35..671097733 100644 --- a/flexmeasures/data/migrations/versions/30fe2267e7d5_add_optional_DataSource_columns_for_model_and_version.py +++ b/flexmeasures/data/migrations/versions/30fe2267e7d5_add_optional_DataSource_columns_for_model_and_version.py @@ -5,6 +5,7 @@ Create Date: 2021-10-11 10:54:24.348371 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/31f251554682_merge.py b/flexmeasures/data/migrations/versions/31f251554682_merge.py index 016048ee7..49653aa8f 100644 --- a/flexmeasures/data/migrations/versions/31f251554682_merge.py +++ b/flexmeasures/data/migrations/versions/31f251554682_merge.py @@ -6,7 +6,6 @@ """ - # revision identifiers, used by Alembic. revision = "31f251554682" down_revision = ("b2b43f0eec40", "61bfc6e45c4d") diff --git a/flexmeasures/data/migrations/versions/3d56402cde15_drop_login_columns_in_bvp_users_table.py b/flexmeasures/data/migrations/versions/3d56402cde15_drop_login_columns_in_bvp_users_table.py index ac3f56232..859b49ae8 100644 --- a/flexmeasures/data/migrations/versions/3d56402cde15_drop_login_columns_in_bvp_users_table.py +++ b/flexmeasures/data/migrations/versions/3d56402cde15_drop_login_columns_in_bvp_users_table.py @@ -5,6 +5,7 @@ Create Date: 2018-04-10 16:42:38.892648 """ + from alembic import op import sqlalchemy as sa from sqlalchemy.dialects import postgresql diff --git a/flexmeasures/data/migrations/versions/3db3e71d101d_make_datasource_a_subclass_of_timely_beliefs_beliefsource.py b/flexmeasures/data/migrations/versions/3db3e71d101d_make_datasource_a_subclass_of_timely_beliefs_beliefsource.py index dacce316f..f4df5b081 100644 --- a/flexmeasures/data/migrations/versions/3db3e71d101d_make_datasource_a_subclass_of_timely_beliefs_beliefsource.py +++ b/flexmeasures/data/migrations/versions/3db3e71d101d_make_datasource_a_subclass_of_timely_beliefs_beliefsource.py @@ -8,6 +8,7 @@ Create Date: 2020-08-10 15:31:28.391337 """ + from alembic import op # revision identifiers, used by Alembic. diff --git a/flexmeasures/data/migrations/versions/3e43d3274d16_Asset_soc_udi_event_id.py b/flexmeasures/data/migrations/versions/3e43d3274d16_Asset_soc_udi_event_id.py index b37c04a61..d63dd0631 100644 --- a/flexmeasures/data/migrations/versions/3e43d3274d16_Asset_soc_udi_event_id.py +++ b/flexmeasures/data/migrations/versions/3e43d3274d16_Asset_soc_udi_event_id.py @@ -5,6 +5,7 @@ Create Date: 2018-09-21 15:07:00.816216 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/3eb0564948ca_add_search_index_for_single_belief_.py b/flexmeasures/data/migrations/versions/3eb0564948ca_add_search_index_for_single_belief_.py index dfba65f1b..9b54c7d2a 100644 --- a/flexmeasures/data/migrations/versions/3eb0564948ca_add_search_index_for_single_belief_.py +++ b/flexmeasures/data/migrations/versions/3eb0564948ca_add_search_index_for_single_belief_.py @@ -5,6 +5,7 @@ Create Date: 2024-05-12 15:45:25.337949 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/40d6c8e4be94_add_parent_asset_id_column.py b/flexmeasures/data/migrations/versions/40d6c8e4be94_add_parent_asset_id_column.py index 62744aeff..fc190aa32 100644 --- a/flexmeasures/data/migrations/versions/40d6c8e4be94_add_parent_asset_id_column.py +++ b/flexmeasures/data/migrations/versions/40d6c8e4be94_add_parent_asset_id_column.py @@ -5,6 +5,7 @@ Create Date: 2023-09-19 17:05:00.020779 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/45d937300b0f_create_measurement_table.py b/flexmeasures/data/migrations/versions/45d937300b0f_create_measurement_table.py index b4eb9dfa2..188a5aa10 100644 --- a/flexmeasures/data/migrations/versions/45d937300b0f_create_measurement_table.py +++ b/flexmeasures/data/migrations/versions/45d937300b0f_create_measurement_table.py @@ -5,6 +5,7 @@ Create Date: 2018-05-07 18:18:59.555454 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/4b6cebbdf473_create_weather_sensor_type_and_weather_sensor_and_weather_tables.py b/flexmeasures/data/migrations/versions/4b6cebbdf473_create_weather_sensor_type_and_weather_sensor_and_weather_tables.py index 2e5f5d9ab..789f63f5b 100644 --- a/flexmeasures/data/migrations/versions/4b6cebbdf473_create_weather_sensor_type_and_weather_sensor_and_weather_tables.py +++ b/flexmeasures/data/migrations/versions/4b6cebbdf473_create_weather_sensor_type_and_weather_sensor_and_weather_tables.py @@ -5,6 +5,7 @@ Create Date: 2018-06-07 12:13:44.504308 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/50cf294e007d_complete_adding_units_to_all_generic_asset_tables_and_display_names_to_all_generic_asset_tables_and_generic_asset_type_tables.py b/flexmeasures/data/migrations/versions/50cf294e007d_complete_adding_units_to_all_generic_asset_tables_and_display_names_to_all_generic_asset_tables_and_generic_asset_type_tables.py index d32a3e7c3..1ff4a5cab 100644 --- a/flexmeasures/data/migrations/versions/50cf294e007d_complete_adding_units_to_all_generic_asset_tables_and_display_names_to_all_generic_asset_tables_and_generic_asset_type_tables.py +++ b/flexmeasures/data/migrations/versions/50cf294e007d_complete_adding_units_to_all_generic_asset_tables_and_display_names_to_all_generic_asset_tables_and_generic_asset_type_tables.py @@ -5,6 +5,7 @@ Create Date: 2018-10-12 11:12:03.525000 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/521034349543_add_consultancy_account_to_account.py b/flexmeasures/data/migrations/versions/521034349543_add_consultancy_account_to_account.py index 6d37d0308..9113efa09 100644 --- a/flexmeasures/data/migrations/versions/521034349543_add_consultancy_account_to_account.py +++ b/flexmeasures/data/migrations/versions/521034349543_add_consultancy_account_to_account.py @@ -5,6 +5,7 @@ Create Date: 2023-10-13 11:07:08.013181 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/524800c11eec_add_warning_and_error_as_annotations_.py b/flexmeasures/data/migrations/versions/524800c11eec_add_warning_and_error_as_annotations_.py index b9ea44a0b..854a5245b 100644 --- a/flexmeasures/data/migrations/versions/524800c11eec_add_warning_and_error_as_annotations_.py +++ b/flexmeasures/data/migrations/versions/524800c11eec_add_warning_and_error_as_annotations_.py @@ -5,6 +5,7 @@ Create Date: 2024-08-19 15:10:24.323594 """ + from alembic import op from sqlalchemy.sql import text diff --git a/flexmeasures/data/migrations/versions/550a9020f1bf_default_resolution_for_existing_sensors.py b/flexmeasures/data/migrations/versions/550a9020f1bf_default_resolution_for_existing_sensors.py index f22eaec47..ed660ec8a 100644 --- a/flexmeasures/data/migrations/versions/550a9020f1bf_default_resolution_for_existing_sensors.py +++ b/flexmeasures/data/migrations/versions/550a9020f1bf_default_resolution_for_existing_sensors.py @@ -5,6 +5,7 @@ Create Date: 2020-11-05 17:48:49.670289 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/564e8df4e3a9_stop_using_bvp_in_table_names.py b/flexmeasures/data/migrations/versions/564e8df4e3a9_stop_using_bvp_in_table_names.py index 61dc4129f..091601512 100644 --- a/flexmeasures/data/migrations/versions/564e8df4e3a9_stop_using_bvp_in_table_names.py +++ b/flexmeasures/data/migrations/versions/564e8df4e3a9_stop_using_bvp_in_table_names.py @@ -5,6 +5,7 @@ Create Date: 2021-01-12 21:44:43.069141 """ + from alembic import op # revision identifiers, used by Alembic. diff --git a/flexmeasures/data/migrations/versions/565e092a6c5e_introduce_the_GenericAssetType_table.py b/flexmeasures/data/migrations/versions/565e092a6c5e_introduce_the_GenericAssetType_table.py index b57af2032..481c5e19f 100644 --- a/flexmeasures/data/migrations/versions/565e092a6c5e_introduce_the_GenericAssetType_table.py +++ b/flexmeasures/data/migrations/versions/565e092a6c5e_introduce_the_GenericAssetType_table.py @@ -5,6 +5,7 @@ Create Date: 2021-07-20 16:16:50.872449 """ + import json from alembic import context, op diff --git a/flexmeasures/data/migrations/versions/5d39829d91af_create_data_sources_table.py b/flexmeasures/data/migrations/versions/5d39829d91af_create_data_sources_table.py index 0600c19ff..347eee231 100644 --- a/flexmeasures/data/migrations/versions/5d39829d91af_create_data_sources_table.py +++ b/flexmeasures/data/migrations/versions/5d39829d91af_create_data_sources_table.py @@ -5,6 +5,7 @@ Create Date: 2018-07-09 17:17:36.276000 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/61bfc6e45c4d_add_soc_columns_in_asset_table.py b/flexmeasures/data/migrations/versions/61bfc6e45c4d_add_soc_columns_in_asset_table.py index f62a855e5..bb2c1d185 100644 --- a/flexmeasures/data/migrations/versions/61bfc6e45c4d_add_soc_columns_in_asset_table.py +++ b/flexmeasures/data/migrations/versions/61bfc6e45c4d_add_soc_columns_in_asset_table.py @@ -5,6 +5,7 @@ Create Date: 2018-09-10 11:10:34.068000 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/650b085c0ad3_consolidate_data_source_after_storage_.py b/flexmeasures/data/migrations/versions/650b085c0ad3_consolidate_data_source_after_storage_.py index 26fbe36b4..3133bdc5d 100644 --- a/flexmeasures/data/migrations/versions/650b085c0ad3_consolidate_data_source_after_storage_.py +++ b/flexmeasures/data/migrations/versions/650b085c0ad3_consolidate_data_source_after_storage_.py @@ -5,6 +5,7 @@ Create Date: 2022-11-16 07:07:44.281943 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/6938f16617ab_add_search_index_for_beliefs.py b/flexmeasures/data/migrations/versions/6938f16617ab_add_search_index_for_beliefs.py index e48400929..11c1f9a95 100644 --- a/flexmeasures/data/migrations/versions/6938f16617ab_add_search_index_for_beliefs.py +++ b/flexmeasures/data/migrations/versions/6938f16617ab_add_search_index_for_beliefs.py @@ -5,6 +5,7 @@ Create Date: 2024-03-01 09:55:34.910868 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/6cf5b241b85f_copy_attributes_from_old_data_models_to_GenericAsset.py b/flexmeasures/data/migrations/versions/6cf5b241b85f_copy_attributes_from_old_data_models_to_GenericAsset.py index ba3c360f3..db70e87d9 100644 --- a/flexmeasures/data/migrations/versions/6cf5b241b85f_copy_attributes_from_old_data_models_to_GenericAsset.py +++ b/flexmeasures/data/migrations/versions/6cf5b241b85f_copy_attributes_from_old_data_models_to_GenericAsset.py @@ -5,6 +5,7 @@ Create Date: 2021-11-11 17:18:15.395915 """ + import json from datetime import datetime diff --git a/flexmeasures/data/migrations/versions/7113b0f00678_drop_forecasting_jobs_table_and_make_display_names_nullable.py b/flexmeasures/data/migrations/versions/7113b0f00678_drop_forecasting_jobs_table_and_make_display_names_nullable.py index 5c9ba2edc..7596214bd 100644 --- a/flexmeasures/data/migrations/versions/7113b0f00678_drop_forecasting_jobs_table_and_make_display_names_nullable.py +++ b/flexmeasures/data/migrations/versions/7113b0f00678_drop_forecasting_jobs_table_and_make_display_names_nullable.py @@ -5,6 +5,7 @@ Create Date: 2020-06-04 11:29:46.507095 """ + from alembic import op import sqlalchemy as sa from sqlalchemy.dialects import postgresql diff --git a/flexmeasures/data/migrations/versions/75f53d2dbfae_new_field_last_seen_in_user_model.py b/flexmeasures/data/migrations/versions/75f53d2dbfae_new_field_last_seen_in_user_model.py index 0e3ff82c2..3dee9a07b 100644 --- a/flexmeasures/data/migrations/versions/75f53d2dbfae_new_field_last_seen_in_user_model.py +++ b/flexmeasures/data/migrations/versions/75f53d2dbfae_new_field_last_seen_in_user_model.py @@ -5,6 +5,7 @@ Create Date: 2022-11-27 00:15:26.403169 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/7987667dbd43_add_asset_type_hover_label.py b/flexmeasures/data/migrations/versions/7987667dbd43_add_asset_type_hover_label.py index a4a48eb26..277e10c43 100644 --- a/flexmeasures/data/migrations/versions/7987667dbd43_add_asset_type_hover_label.py +++ b/flexmeasures/data/migrations/versions/7987667dbd43_add_asset_type_hover_label.py @@ -5,6 +5,7 @@ Create Date: 2020-06-04 11:36:42.684918 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/7f8b8920355f_create_annotation_table.py b/flexmeasures/data/migrations/versions/7f8b8920355f_create_annotation_table.py index f2b3a94f9..56db29aa5 100644 --- a/flexmeasures/data/migrations/versions/7f8b8920355f_create_annotation_table.py +++ b/flexmeasures/data/migrations/versions/7f8b8920355f_create_annotation_table.py @@ -5,6 +5,7 @@ Create Date: 2022-01-29 20:23:29.996133 """ + from alembic import op import click import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/81cbbf42357b_added_audit_log_table.py b/flexmeasures/data/migrations/versions/81cbbf42357b_added_audit_log_table.py index 0eff6190b..1611515e4 100644 --- a/flexmeasures/data/migrations/versions/81cbbf42357b_added_audit_log_table.py +++ b/flexmeasures/data/migrations/versions/81cbbf42357b_added_audit_log_table.py @@ -5,6 +5,7 @@ Create Date: 2024-04-22 12:40:20.483528 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/830e72a8b218_migrate_sensor_relationships_for_power_price_weather.py b/flexmeasures/data/migrations/versions/830e72a8b218_migrate_sensor_relationships_for_power_price_weather.py index c39390fd8..e5a828edb 100644 --- a/flexmeasures/data/migrations/versions/830e72a8b218_migrate_sensor_relationships_for_power_price_weather.py +++ b/flexmeasures/data/migrations/versions/830e72a8b218_migrate_sensor_relationships_for_power_price_weather.py @@ -5,6 +5,7 @@ Create Date: 2021-12-02 14:58:06.581092 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/8abe32ffa204_add_owner_id_column_in_asset_table.py b/flexmeasures/data/migrations/versions/8abe32ffa204_add_owner_id_column_in_asset_table.py index 3bb3ce066..01813bb28 100644 --- a/flexmeasures/data/migrations/versions/8abe32ffa204_add_owner_id_column_in_asset_table.py +++ b/flexmeasures/data/migrations/versions/8abe32ffa204_add_owner_id_column_in_asset_table.py @@ -5,6 +5,7 @@ Create Date: 2018-04-23 16:54:45.199226 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/8fcc5fec67bc_make_data_source_id_columns_primary_keys.py b/flexmeasures/data/migrations/versions/8fcc5fec67bc_make_data_source_id_columns_primary_keys.py index ae8f87e57..75684bd3f 100644 --- a/flexmeasures/data/migrations/versions/8fcc5fec67bc_make_data_source_id_columns_primary_keys.py +++ b/flexmeasures/data/migrations/versions/8fcc5fec67bc_make_data_source_id_columns_primary_keys.py @@ -5,6 +5,7 @@ Create Date: 2018-07-30 15:39:30.583000 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/919dc9f1dc1f_merge.py b/flexmeasures/data/migrations/versions/919dc9f1dc1f_merge.py index 6c555deac..d680334f1 100644 --- a/flexmeasures/data/migrations/versions/919dc9f1dc1f_merge.py +++ b/flexmeasures/data/migrations/versions/919dc9f1dc1f_merge.py @@ -6,7 +6,6 @@ """ - # revision identifiers, used by Alembic. revision = "919dc9f1dc1f" down_revision = ("db00b66be82c", "5d39829d91af") diff --git a/flexmeasures/data/migrations/versions/91a938bfa5a8_add_horizon_columns_to_power_price_and_weather_tables.py b/flexmeasures/data/migrations/versions/91a938bfa5a8_add_horizon_columns_to_power_price_and_weather_tables.py index 11c07884d..0f131668b 100644 --- a/flexmeasures/data/migrations/versions/91a938bfa5a8_add_horizon_columns_to_power_price_and_weather_tables.py +++ b/flexmeasures/data/migrations/versions/91a938bfa5a8_add_horizon_columns_to_power_price_and_weather_tables.py @@ -5,6 +5,7 @@ Create Date: 2018-06-08 15:46:28.950464 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/9254559dcac2_create_market_type_and_market_tables.py b/flexmeasures/data/migrations/versions/9254559dcac2_create_market_type_and_market_tables.py index ebc8eaf23..c3a744db6 100644 --- a/flexmeasures/data/migrations/versions/9254559dcac2_create_market_type_and_market_tables.py +++ b/flexmeasures/data/migrations/versions/9254559dcac2_create_market_type_and_market_tables.py @@ -5,6 +5,7 @@ Create Date: 2018-05-28 13:02:55.210603 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/96f2db5bed30_add_account_roles.py b/flexmeasures/data/migrations/versions/96f2db5bed30_add_account_roles.py index 2abef020e..944be2ee6 100644 --- a/flexmeasures/data/migrations/versions/96f2db5bed30_add_account_roles.py +++ b/flexmeasures/data/migrations/versions/96f2db5bed30_add_account_roles.py @@ -5,6 +5,7 @@ Create Date: 2021-08-30 11:33:40.481140 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/994170c26bc6_add_account_table.py b/flexmeasures/data/migrations/versions/994170c26bc6_add_account_table.py index c36c90be8..57c7bb3fa 100644 --- a/flexmeasures/data/migrations/versions/994170c26bc6_add_account_table.py +++ b/flexmeasures/data/migrations/versions/994170c26bc6_add_account_table.py @@ -5,6 +5,7 @@ Create Date: 2021-08-11 19:21:07.083253 """ + from typing import List, Tuple, Optional import os import json diff --git a/flexmeasures/data/migrations/versions/9b2b90ee5dbf_add_ondelete_cascade_to_foreign_keys_in_account_sensor_and_asset_relationships.py b/flexmeasures/data/migrations/versions/9b2b90ee5dbf_add_ondelete_cascade_to_foreign_keys_in_account_sensor_and_asset_relationships.py index 6388e8ffd..264785082 100644 --- a/flexmeasures/data/migrations/versions/9b2b90ee5dbf_add_ondelete_cascade_to_foreign_keys_in_account_sensor_and_asset_relationships.py +++ b/flexmeasures/data/migrations/versions/9b2b90ee5dbf_add_ondelete_cascade_to_foreign_keys_in_account_sensor_and_asset_relationships.py @@ -5,6 +5,7 @@ Create Date: 2024-08-22 12:22:45.240872 """ + from alembic import op # revision identifiers, used by Alembic. diff --git a/flexmeasures/data/migrations/versions/9c7fc8e46f1e_add_location_columns_to_weather_sensor_table.py b/flexmeasures/data/migrations/versions/9c7fc8e46f1e_add_location_columns_to_weather_sensor_table.py index ae6cc0089..38afe3390 100644 --- a/flexmeasures/data/migrations/versions/9c7fc8e46f1e_add_location_columns_to_weather_sensor_table.py +++ b/flexmeasures/data/migrations/versions/9c7fc8e46f1e_add_location_columns_to_weather_sensor_table.py @@ -5,6 +5,7 @@ Create Date: 2018-07-27 12:38:27.006000 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/a328412b4623_add_timezone_column_in_bvp_users_table.py b/flexmeasures/data/migrations/versions/a328412b4623_add_timezone_column_in_bvp_users_table.py index 075626fd6..59dde1977 100644 --- a/flexmeasures/data/migrations/versions/a328412b4623_add_timezone_column_in_bvp_users_table.py +++ b/flexmeasures/data/migrations/versions/a328412b4623_add_timezone_column_in_bvp_users_table.py @@ -5,6 +5,7 @@ Create Date: 2018-04-24 15:31:18.190845 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/a528c3c81506_unique_generic_sensor_ids.py b/flexmeasures/data/migrations/versions/a528c3c81506_unique_generic_sensor_ids.py index 5b51ddf37..7ac335dee 100644 --- a/flexmeasures/data/migrations/versions/a528c3c81506_unique_generic_sensor_ids.py +++ b/flexmeasures/data/migrations/versions/a528c3c81506_unique_generic_sensor_ids.py @@ -52,6 +52,7 @@ (downgrade) a 1,2,6 <- 1,2,6 m 3,4,8 <- 9,10,14 w 1,6,7 <- 15,20,21 (- max_market_id) """ + from alembic import op import sqlalchemy as sa from sqlalchemy import orm diff --git a/flexmeasures/data/migrations/versions/a5b970eadb3b_time_series_indexes.py b/flexmeasures/data/migrations/versions/a5b970eadb3b_time_series_indexes.py index 1f6e82efe..8f132fa30 100644 --- a/flexmeasures/data/migrations/versions/a5b970eadb3b_time_series_indexes.py +++ b/flexmeasures/data/migrations/versions/a5b970eadb3b_time_series_indexes.py @@ -5,6 +5,7 @@ Create Date: 2020-11-05 17:15:31.767627 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/a60cc43aef5e_delete_children_assets_on_cascade_when_.py b/flexmeasures/data/migrations/versions/a60cc43aef5e_delete_children_assets_on_cascade_when_.py index 3668deb6b..56725c36c 100644 --- a/flexmeasures/data/migrations/versions/a60cc43aef5e_delete_children_assets_on_cascade_when_.py +++ b/flexmeasures/data/migrations/versions/a60cc43aef5e_delete_children_assets_on_cascade_when_.py @@ -5,6 +5,7 @@ Create Date: 2023-10-11 14:04:19.447773 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/a918360f7d63_add_unique_contraints_on_.py b/flexmeasures/data/migrations/versions/a918360f7d63_add_unique_contraints_on_.py index 8f0414819..8ff6d230b 100644 --- a/flexmeasures/data/migrations/versions/a918360f7d63_add_unique_contraints_on_.py +++ b/flexmeasures/data/migrations/versions/a918360f7d63_add_unique_contraints_on_.py @@ -5,6 +5,7 @@ Create Date: 2022-01-01 22:08:50.163734 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/ac2613fffc74_add_market_id_column_to_asset_table.py b/flexmeasures/data/migrations/versions/ac2613fffc74_add_market_id_column_to_asset_table.py index 42595db0e..6ad644cbd 100644 --- a/flexmeasures/data/migrations/versions/ac2613fffc74_add_market_id_column_to_asset_table.py +++ b/flexmeasures/data/migrations/versions/ac2613fffc74_add_market_id_column_to_asset_table.py @@ -5,6 +5,7 @@ Create Date: 2018-10-23 15:49:36.312000 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/ac5e340cccea_change_scope_of_name_account_id_unique_constraint.py b/flexmeasures/data/migrations/versions/ac5e340cccea_change_scope_of_name_account_id_unique_constraint.py index 0539feeb6..950240cca 100644 --- a/flexmeasures/data/migrations/versions/ac5e340cccea_change_scope_of_name_account_id_unique_constraint.py +++ b/flexmeasures/data/migrations/versions/ac5e340cccea_change_scope_of_name_account_id_unique_constraint.py @@ -8,6 +8,7 @@ Create Date: 2023-10-05 15:13:36.641051 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/ad98460751d9_remove_obsolete_tables.py b/flexmeasures/data/migrations/versions/ad98460751d9_remove_obsolete_tables.py index 818907cd0..417beb932 100644 --- a/flexmeasures/data/migrations/versions/ad98460751d9_remove_obsolete_tables.py +++ b/flexmeasures/data/migrations/versions/ad98460751d9_remove_obsolete_tables.py @@ -5,6 +5,7 @@ Create Date: 2023-11-30 10:31:46.125670 """ + from alembic import op import sqlalchemy as sa from sqlalchemy.dialects import postgresql diff --git a/flexmeasures/data/migrations/versions/b087ce8b529f_create_latest_task_run_table.py b/flexmeasures/data/migrations/versions/b087ce8b529f_create_latest_task_run_table.py index 6a94ec732..620f2516b 100644 --- a/flexmeasures/data/migrations/versions/b087ce8b529f_create_latest_task_run_table.py +++ b/flexmeasures/data/migrations/versions/b087ce8b529f_create_latest_task_run_table.py @@ -5,6 +5,7 @@ Create Date: 2018-06-14 12:06:05.037547 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/b2b43f0eec40_weathersensors_unique_type_location.py b/flexmeasures/data/migrations/versions/b2b43f0eec40_weathersensors_unique_type_location.py index 968019fb1..bfe6bfb37 100644 --- a/flexmeasures/data/migrations/versions/b2b43f0eec40_weathersensors_unique_type_location.py +++ b/flexmeasures/data/migrations/versions/b2b43f0eec40_weathersensors_unique_type_location.py @@ -5,6 +5,7 @@ Create Date: 2018-09-12 11:14:46.486640 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/b6d49ed7cceb_introduce_the_GenericAsset_table.py b/flexmeasures/data/migrations/versions/b6d49ed7cceb_introduce_the_GenericAsset_table.py index 3adf80079..e3b019438 100644 --- a/flexmeasures/data/migrations/versions/b6d49ed7cceb_introduce_the_GenericAsset_table.py +++ b/flexmeasures/data/migrations/versions/b6d49ed7cceb_introduce_the_GenericAsset_table.py @@ -5,6 +5,7 @@ Create Date: 2021-07-20 20:15:28.019102 """ + import json from alembic import context, op diff --git a/flexmeasures/data/migrations/versions/b797328ac32d_add_user_fs_uniquifier_for_faster_auth_.py b/flexmeasures/data/migrations/versions/b797328ac32d_add_user_fs_uniquifier_for_faster_auth_.py index 31e11f5be..946e53e14 100644 --- a/flexmeasures/data/migrations/versions/b797328ac32d_add_user_fs_uniquifier_for_faster_auth_.py +++ b/flexmeasures/data/migrations/versions/b797328ac32d_add_user_fs_uniquifier_for_faster_auth_.py @@ -5,6 +5,7 @@ Create Date: 2020-08-24 19:01:04.337956 """ + import uuid from alembic import op diff --git a/flexmeasures/data/migrations/versions/bddc5e9f72a3_add_event_resolution_field_to_asset_.py b/flexmeasures/data/migrations/versions/bddc5e9f72a3_add_event_resolution_field_to_asset_.py index 1b114b4d3..1ba0a52b1 100644 --- a/flexmeasures/data/migrations/versions/bddc5e9f72a3_add_event_resolution_field_to_asset_.py +++ b/flexmeasures/data/migrations/versions/bddc5e9f72a3_add_event_resolution_field_to_asset_.py @@ -5,6 +5,7 @@ Create Date: 2020-10-07 14:12:45.761789 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/c1d316c60985_merge.py b/flexmeasures/data/migrations/versions/c1d316c60985_merge.py index 6eb97c690..f404eaf7b 100644 --- a/flexmeasures/data/migrations/versions/c1d316c60985_merge.py +++ b/flexmeasures/data/migrations/versions/c1d316c60985_merge.py @@ -6,7 +6,6 @@ """ - # revision identifiers, used by Alembic. revision = "c1d316c60985" down_revision = ("a918360f7d63", "e690d373a3d9") diff --git a/flexmeasures/data/migrations/versions/c349f52c700d_update_data_sources.py b/flexmeasures/data/migrations/versions/c349f52c700d_update_data_sources.py index 499a0e9cb..e652349a8 100644 --- a/flexmeasures/data/migrations/versions/c349f52c700d_update_data_sources.py +++ b/flexmeasures/data/migrations/versions/c349f52c700d_update_data_sources.py @@ -5,6 +5,7 @@ Create Date: 2023-12-14 10:31:02.612590 """ + from alembic import op import sqlalchemy as sa from sqlalchemy.dialects import postgresql diff --git a/flexmeasures/data/migrations/versions/c41beee0c904_rename_DataSource_type_for_forecasters_and_schedulers.py b/flexmeasures/data/migrations/versions/c41beee0c904_rename_DataSource_type_for_forecasters_and_schedulers.py index 4510f7294..9a5e9cdf8 100644 --- a/flexmeasures/data/migrations/versions/c41beee0c904_rename_DataSource_type_for_forecasters_and_schedulers.py +++ b/flexmeasures/data/migrations/versions/c41beee0c904_rename_DataSource_type_for_forecasters_and_schedulers.py @@ -5,6 +5,7 @@ Create Date: 2022-11-30 21:33:09.046751 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/d3440de27ab9_create_bvp_roles_and_bvp_users_and_bvp_roles_users_tables.py b/flexmeasures/data/migrations/versions/d3440de27ab9_create_bvp_roles_and_bvp_users_and_bvp_roles_users_tables.py index ee2133a2c..0e445abfd 100644 --- a/flexmeasures/data/migrations/versions/d3440de27ab9_create_bvp_roles_and_bvp_users_and_bvp_roles_users_tables.py +++ b/flexmeasures/data/migrations/versions/d3440de27ab9_create_bvp_roles_and_bvp_users_and_bvp_roles_users_tables.py @@ -5,6 +5,7 @@ Create Date: 2018-03-27 16:50:13.265722 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/d814c0688ae0_merge.py b/flexmeasures/data/migrations/versions/d814c0688ae0_merge.py index ff3204329..f43f6446b 100644 --- a/flexmeasures/data/migrations/versions/d814c0688ae0_merge.py +++ b/flexmeasures/data/migrations/versions/d814c0688ae0_merge.py @@ -6,7 +6,6 @@ """ - # revision identifiers, used by Alembic. revision = "d814c0688ae0" down_revision = ("75f53d2dbfae", "c41beee0c904") diff --git a/flexmeasures/data/migrations/versions/db00b66be82c_add_horizon_columns_as_primary_keys.py b/flexmeasures/data/migrations/versions/db00b66be82c_add_horizon_columns_as_primary_keys.py index 411757599..9ad669bd5 100644 --- a/flexmeasures/data/migrations/versions/db00b66be82c_add_horizon_columns_as_primary_keys.py +++ b/flexmeasures/data/migrations/versions/db00b66be82c_add_horizon_columns_as_primary_keys.py @@ -5,6 +5,7 @@ Create Date: 2018-07-10 10:31:58.915035 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/db1f67336324_add_price_unit_and_display_name_columns_to_market_table.py b/flexmeasures/data/migrations/versions/db1f67336324_add_price_unit_and_display_name_columns_to_market_table.py index 4e0145d3e..3f2943ffa 100644 --- a/flexmeasures/data/migrations/versions/db1f67336324_add_price_unit_and_display_name_columns_to_market_table.py +++ b/flexmeasures/data/migrations/versions/db1f67336324_add_price_unit_and_display_name_columns_to_market_table.py @@ -5,6 +5,7 @@ Create Date: 2018-10-07 13:50:23.690000 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/e0c2f9aff251_rename_source_id_column_in_data_sources_table.py b/flexmeasures/data/migrations/versions/e0c2f9aff251_rename_source_id_column_in_data_sources_table.py index 03b8fbbf6..4c228a018 100644 --- a/flexmeasures/data/migrations/versions/e0c2f9aff251_rename_source_id_column_in_data_sources_table.py +++ b/flexmeasures/data/migrations/versions/e0c2f9aff251_rename_source_id_column_in_data_sources_table.py @@ -5,6 +5,7 @@ Create Date: 2018-07-20 16:08:50.641000 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/e4c9cf837311_sensor_generic_asset_id_should_not_be_.py b/flexmeasures/data/migrations/versions/e4c9cf837311_sensor_generic_asset_id_should_not_be_.py index 08bb98702..38cc795a2 100644 --- a/flexmeasures/data/migrations/versions/e4c9cf837311_sensor_generic_asset_id_should_not_be_.py +++ b/flexmeasures/data/migrations/versions/e4c9cf837311_sensor_generic_asset_id_should_not_be_.py @@ -5,6 +5,7 @@ Create Date: 2021-08-15 20:42:29.729532 """ + from alembic import op diff --git a/flexmeasures/data/migrations/versions/e62ac5f519d7_create_table_for_timed_beliefs.py b/flexmeasures/data/migrations/versions/e62ac5f519d7_create_table_for_timed_beliefs.py index 95fb2ddb3..550e6b46f 100644 --- a/flexmeasures/data/migrations/versions/e62ac5f519d7_create_table_for_timed_beliefs.py +++ b/flexmeasures/data/migrations/versions/e62ac5f519d7_create_table_for_timed_beliefs.py @@ -5,6 +5,7 @@ Create Date: 2021-03-28 16:26:45.025994 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/migrations/versions/e690d373a3d9_copy_Power_Price_Weather_time_series_data_to_TimedBeliefs_table.py b/flexmeasures/data/migrations/versions/e690d373a3d9_copy_Power_Price_Weather_time_series_data_to_TimedBeliefs_table.py index cdb055b7e..c470c7b93 100644 --- a/flexmeasures/data/migrations/versions/e690d373a3d9_copy_Power_Price_Weather_time_series_data_to_TimedBeliefs_table.py +++ b/flexmeasures/data/migrations/versions/e690d373a3d9_copy_Power_Price_Weather_time_series_data_to_TimedBeliefs_table.py @@ -8,6 +8,7 @@ Create Date: 2021-12-27 15:01:38.967237 """ + from alembic import op import sqlalchemy as sa diff --git a/flexmeasures/data/models/forecasting/model_spec_factory.py b/flexmeasures/data/models/forecasting/model_spec_factory.py index a2b19863e..bce0b259f 100644 --- a/flexmeasures/data/models/forecasting/model_spec_factory.py +++ b/flexmeasures/data/models/forecasting/model_spec_factory.py @@ -90,7 +90,8 @@ def _load_series(self) -> pd.Series: def check_data(self, df: pd.DataFrame): """Raise error if data is empty or contains nan values. - Here, other than in load_series, we can show the query, which is quite helpful.""" + Here, other than in load_series, we can show the query, which is quite helpful. + """ if df.empty: raise MissingData( "No values found in database for the requested %s data. It's no use to continue I'm afraid." @@ -120,8 +121,9 @@ def create_initial_model_specs( # noqa: C901 transform_to_normal: bool = True, use_regressors: bool = True, # If false, do not create regressor specs use_periodicity: bool = True, # If false, do not create lags given the asset's periodicity - custom_model_params: dict - | None = None, # overwrite model params, most useful for tests or experiments + custom_model_params: ( + dict | None + ) = None, # overwrite model params, most useful for tests or experiments time_series_class: type | None = TimedBelief, ) -> ModelSpecs: """ @@ -221,9 +223,9 @@ def _parameterise_forecasting_by_asset_and_asset_type( params["resolution"] = sensor.event_resolution if transform_to_normal: - params[ - "outcome_var_transformation" - ] = get_normalization_transformation_from_sensor_attributes(sensor) + params["outcome_var_transformation"] = ( + get_normalization_transformation_from_sensor_attributes(sensor) + ) return params diff --git a/flexmeasures/data/models/forecasting/model_specs/naive.py b/flexmeasures/data/models/forecasting/model_specs/naive.py index 3bc285128..e572cb408 100644 --- a/flexmeasures/data/models/forecasting/model_specs/naive.py +++ b/flexmeasures/data/models/forecasting/model_specs/naive.py @@ -24,7 +24,8 @@ class Naive(OLS): """Naive prediction model for a single input feature that simply throws back the given feature. - Under the hood, it uses linear regression by ordinary least squares, trained with points (0,0) and (1,1).""" + Under the hood, it uses linear regression by ordinary least squares, trained with points (0,0) and (1,1). + """ def __init__(self, *args, **kwargs): super().__init__([0, 1], [0, 1]) diff --git a/flexmeasures/data/models/generic_assets.py b/flexmeasures/data/models/generic_assets.py index e688b8bd3..74b001079 100644 --- a/flexmeasures/data/models/generic_assets.py +++ b/flexmeasures/data/models/generic_assets.py @@ -148,9 +148,11 @@ def __acl__(self): """ return { "create-children": f"account:{self.account_id}", - "read": self.owner.__acl__()["read"] - if self.account_id is not None - else EVERY_LOGGED_IN_USER, + "read": ( + self.owner.__acl__()["read"] + if self.account_id is not None + else EVERY_LOGGED_IN_USER + ), "update": f"account:{self.account_id}", "delete": (f"account:{self.account_id}", "role:account-admin"), } @@ -347,13 +349,9 @@ def search_annotations( self, annotations_after: datetime | None = None, annotations_before: datetime | None = None, - source: DataSource - | list[DataSource] - | int - | list[int] - | str - | list[str] - | None = None, + source: ( + DataSource | list[DataSource] | int | list[int] | str | list[str] | None + ) = None, annotation_type: str = None, include_account_annotations: bool = False, as_frame: bool = False, @@ -390,13 +388,9 @@ def count_annotations( annotations_after: datetime | None = None, annotation_ends_before: datetime | None = None, # deprecated annotations_before: datetime | None = None, - source: DataSource - | list[DataSource] - | int - | list[int] - | str - | list[str] - | None = None, + source: ( + DataSource | list[DataSource] | int | list[int] | str | list[str] | None + ) = None, annotation_type: str = None, ) -> int: """Count the number of annotations assigned to this asset.""" @@ -436,13 +430,9 @@ def chart( beliefs_after: datetime | None = None, beliefs_before: datetime | None = None, combine_legend: bool = True, - source: DataSource - | list[DataSource] - | int - | list[int] - | str - | list[str] - | None = None, + source: ( + DataSource | list[DataSource] | int | list[int] | str | list[str] | None + ) = None, include_data: bool = False, dataset_name: str | None = None, resolution: str | timedelta | None = None, @@ -510,13 +500,9 @@ def search_beliefs( beliefs_before: datetime | None = None, horizons_at_least: timedelta | None = None, horizons_at_most: timedelta | None = None, - source: DataSource - | list[DataSource] - | int - | list[int] - | str - | list[str] - | None = None, + source: ( + DataSource | list[DataSource] | int | list[int] | str | list[str] | None + ) = None, most_recent_beliefs_only: bool = True, most_recent_events_only: bool = False, as_json: bool = False, @@ -572,13 +558,17 @@ def search_beliefs( bdf["belief_horizon"] = bdf.belief_horizons.to_numpy() df = simplify_index( bdf, - index_levels_to_columns=["source"] - if most_recent_beliefs_only - else ["belief_time", "source"], + index_levels_to_columns=( + ["source"] + if most_recent_beliefs_only + else ["belief_time", "source"] + ), ).set_index( - ["source"] - if most_recent_beliefs_only - else ["belief_time", "source"], + ( + ["source"] + if most_recent_beliefs_only + else ["belief_time", "source"] + ), append=True, ) df["sensor"] = sensor # or some JSONifiable representation @@ -588,13 +578,17 @@ def search_beliefs( else: df = simplify_index( BeliefsDataFrame(), - index_levels_to_columns=["source"] - if most_recent_beliefs_only - else ["belief_time", "source"], + index_levels_to_columns=( + ["source"] + if most_recent_beliefs_only + else ["belief_time", "source"] + ), ).set_index( - ["source"] - if most_recent_beliefs_only - else ["belief_time", "source"], + ( + ["source"] + if most_recent_beliefs_only + else ["belief_time", "source"] + ), append=True, ) df["sensor"] = {} # ensure the same columns as a non-empty frame diff --git a/flexmeasures/data/models/legacy_migration_utils.py b/flexmeasures/data/models/legacy_migration_utils.py index 926155997..e0d355726 100644 --- a/flexmeasures/data/models/legacy_migration_utils.py +++ b/flexmeasures/data/models/legacy_migration_utils.py @@ -2,6 +2,7 @@ This module is part of our data model migration (see https://github.com/SeitaBV/flexmeasures/projects/9). It will become obsolete when Assets, Markets and WeatherSensors can no longer be initialized. """ + from __future__ import annotations from datetime import datetime @@ -26,9 +27,11 @@ def copy_old_sensor_attributes( a: getattr(old_sensor_type, a) for a in old_sensor_type_attributes } new_model_attributes_from_old_sensor = { - a: getattr(old_sensor, a) - if not isinstance(getattr(old_sensor, a), datetime) - else getattr(old_sensor, a).isoformat() + a: ( + getattr(old_sensor, a) + if not isinstance(getattr(old_sensor, a), datetime) + else getattr(old_sensor, a).isoformat() + ) for a in old_sensor_attributes } return dict( diff --git a/flexmeasures/data/models/parsing_utils.py b/flexmeasures/data/models/parsing_utils.py index f36914559..df58f70f0 100644 --- a/flexmeasures/data/models/parsing_utils.py +++ b/flexmeasures/data/models/parsing_utils.py @@ -10,13 +10,15 @@ def parse_source_arg( - source: DataSource - | int - | str - | Sequence[DataSource] - | Sequence[int] - | Sequence[str] - | None, + source: ( + DataSource + | int + | str + | Sequence[DataSource] + | Sequence[int] + | Sequence[str] + | None + ), ) -> list[DataSource] | None: """Parse the "source" argument by looking up DataSources corresponding to any given ids or names. diff --git a/flexmeasures/data/models/planning/storage.py b/flexmeasures/data/models/planning/storage.py index 7bfe547b7..dc2c84f7c 100644 --- a/flexmeasures/data/models/planning/storage.py +++ b/flexmeasures/data/models/planning/storage.py @@ -132,9 +132,11 @@ def _prepare(self, skip_validation: bool = False) -> tuple: # noqa: C901 up_deviation_prices = get_continuous_series_sensor_or_quantity( variable_quantity=consumption_price, actuator=sensor, - unit=consumption_price.unit - if isinstance(consumption_price, Sensor) - else str(consumption_price.units), + unit=( + consumption_price.unit + if isinstance(consumption_price, Sensor) + else str(consumption_price.units) + ), query_window=(start, end), resolution=resolution, beliefs_before=belief_time, @@ -153,9 +155,11 @@ def _prepare(self, skip_validation: bool = False) -> tuple: # noqa: C901 down_deviation_prices = get_continuous_series_sensor_or_quantity( variable_quantity=production_price, actuator=sensor, - unit=production_price.unit - if isinstance(production_price, Sensor) - else str(production_price.units), + unit=( + production_price.unit + if isinstance(production_price, Sensor) + else str(production_price.units) + ), query_window=(start, end), resolution=resolution, beliefs_before=belief_time, @@ -276,17 +280,17 @@ def _prepare(self, skip_validation: bool = False) -> tuple: # noqa: C901 if sensor.get_attribute("is_strictly_non_negative"): device_constraints[0]["derivative max"] = 0 else: - device_constraints[0][ - "derivative max" - ] = get_continuous_series_sensor_or_quantity( - variable_quantity=consumption_capacity, - actuator=sensor, - unit="MW", - query_window=(start, end), - resolution=resolution, - beliefs_before=belief_time, - fallback_attribute="consumption_capacity", - max_value=power_capacity_in_mw, + device_constraints[0]["derivative max"] = ( + get_continuous_series_sensor_or_quantity( + variable_quantity=consumption_capacity, + actuator=sensor, + unit="MW", + query_window=(start, end), + resolution=resolution, + beliefs_before=belief_time, + fallback_attribute="consumption_capacity", + max_value=power_capacity_in_mw, + ) ) soc_gain = self.flex_model.get("soc_gain", []) diff --git a/flexmeasures/data/models/planning/tests/test_solver.py b/flexmeasures/data/models/planning/tests/test_solver.py index 115f317b1..4345c0672 100644 --- a/flexmeasures/data/models/planning/tests/test_solver.py +++ b/flexmeasures/data/models/planning/tests/test_solver.py @@ -86,11 +86,11 @@ def test_battery_solver_day_1( resolution, flex_model={"soc-at-start": soc_at_start}, flex_context={ - "inflexible-device-sensors": [ - s.id for s in add_inflexible_device_forecasts.keys() - ] - if use_inflexible_device - else [], + "inflexible-device-sensors": ( + [s.id for s in add_inflexible_device_forecasts.keys()] + if use_inflexible_device + else [] + ), "site-power-capacity": "2 MW", }, ) @@ -614,9 +614,9 @@ def test_building_solver_day_2( capacity["battery consumption headroom"] = capacity["consumption headroom"].clip( upper=battery.get_attribute("capacity_in_mw") ) - capacity[ - "schedule" - ] = schedule.values # consumption is positive, production is negative + capacity["schedule"] = ( + schedule.values + ) # consumption is positive, production is negative with pd.option_context( "display.max_rows", None, "display.max_columns", None, "display.width", 2000 ): diff --git a/flexmeasures/data/models/time_series.py b/flexmeasures/data/models/time_series.py index 2a33b95d0..38b1e0a69 100644 --- a/flexmeasures/data/models/time_series.py +++ b/flexmeasures/data/models/time_series.py @@ -201,13 +201,9 @@ def check_required_attributes( def latest_state( self, - source: DataSource - | list[DataSource] - | int - | list[int] - | str - | list[str] - | None = None, + source: ( + DataSource | list[DataSource] | int | list[int] | str | list[str] | None + ) = None, ) -> tb.BeliefsDataFrame: """Search the most recent event for this sensor, and return the most recent ex-post belief. @@ -227,13 +223,9 @@ def search_annotations( annotations_after: datetime_type | None = None, annotation_ends_before: datetime_type | None = None, # deprecated annotations_before: datetime_type | None = None, - source: DataSource - | list[DataSource] - | int - | list[int] - | str - | list[str] - | None = None, + source: ( + DataSource | list[DataSource] | int | list[int] | str | list[str] | None + ) = None, include_asset_annotations: bool = False, include_account_annotations: bool = False, as_frame: bool = False, @@ -307,13 +299,9 @@ def search_beliefs( beliefs_before: datetime_type | None = None, horizons_at_least: timedelta | None = None, horizons_at_most: timedelta | None = None, - source: DataSource - | list[DataSource] - | int - | list[int] - | str - | list[str] - | None = None, + source: ( + DataSource | list[DataSource] | int | list[int] | str | list[str] | None + ) = None, most_recent_beliefs_only: bool = True, most_recent_events_only: bool = False, most_recent_only: bool = False, @@ -373,13 +361,9 @@ def chart( event_ends_before: datetime_type | None = None, beliefs_after: datetime_type | None = None, beliefs_before: datetime_type | None = None, - source: DataSource - | list[DataSource] - | int - | list[int] - | str - | list[str] - | None = None, + source: ( + DataSource | list[DataSource] | int | list[int] | str | list[str] | None + ) = None, most_recent_beliefs_only: bool = True, include_data: bool = False, include_sensor_annotations: bool = False, @@ -650,13 +634,9 @@ def search( beliefs_before: datetime_type | None = None, horizons_at_least: timedelta | None = None, horizons_at_most: timedelta | None = None, - source: DataSource - | list[DataSource] - | int - | list[int] - | str - | list[str] - | None = None, + source: ( + DataSource | list[DataSource] | int | list[int] | str | list[str] | None + ) = None, user_source_ids: int | list[int] | None = None, source_types: list[str] | None = None, exclude_source_types: list[str] | None = None, diff --git a/flexmeasures/data/queries/users.py b/flexmeasures/data/queries/users.py new file mode 100644 index 000000000..84b0e04f6 --- /dev/null +++ b/flexmeasures/data/queries/users.py @@ -0,0 +1,27 @@ +from __future__ import annotations + +from sqlalchemy import select, Select, or_, and_ + +from flexmeasures.data.models.user import User as UserModel, Account + + +def query_users_by_search_terms( + search_terms: list[str] | None, + filter_statement: bool = True, +) -> Select: + select_statement = select(UserModel) + if search_terms is not None: + filter_statement = filter_statement & and_( + *( + or_( + UserModel.email.ilike(f"%{term}%"), + UserModel.username.ilike(f"%{term}%"), + UserModel.account.has(Account.name.ilike(f"%{term}%")), + ) + for term in search_terms + ) + ) + query = select_statement.where(filter_statement).order_by(UserModel.id) + else: + query = select_statement.where(filter_statement).order_by(UserModel.id) + return query diff --git a/flexmeasures/data/scripts/data_gen.py b/flexmeasures/data/scripts/data_gen.py index ebf1d451f..27f9ddc6b 100644 --- a/flexmeasures/data/scripts/data_gen.py +++ b/flexmeasures/data/scripts/data_gen.py @@ -1,6 +1,7 @@ """ Populate the database with data we know or read in. """ + from __future__ import annotations from pathlib import Path diff --git a/flexmeasures/data/services/asset_grouping.py b/flexmeasures/data/services/asset_grouping.py index c1688183e..c6b02dee4 100644 --- a/flexmeasures/data/services/asset_grouping.py +++ b/flexmeasures/data/services/asset_grouping.py @@ -2,6 +2,7 @@ Convenience functions and class for accessing generic assets in groups. For example, group by asset type or by location. """ + from __future__ import annotations import inflect diff --git a/flexmeasures/data/services/users.py b/flexmeasures/data/services/users.py index d483eba1d..c00e1f8e5 100644 --- a/flexmeasures/data/services/users.py +++ b/flexmeasures/data/services/users.py @@ -35,43 +35,6 @@ def get_user(id: str) -> User: return user -def get_users( - account_name: str | None = None, - role_name: str | None = None, - account_role_name: str | None = None, - only_active: bool = True, -) -> list[User]: - """Return a list of User objects. - The role_name parameter allows to filter by role. - Set only_active to False if you also want non-active users. - """ - user_query = select(User) - - if account_name is not None: - account = db.session.execute( - select(Account).filter_by(name=account_name) - ).scalar_one_or_none() - if not account: - raise NotFound(f"There is no account named {account_name}!") - user_query = user_query.filter_by(account=account) - - if only_active: - user_query = user_query.filter(User.active.is_(True)) - - if role_name is not None: - role = db.session.execute( - select(Role).filter_by(name=role_name) - ).scalar_one_or_none() - if role: - user_query = user_query.filter(User.flexmeasures_roles.contains(role)) - - users = db.session.scalars(user_query).all() - if account_role_name is not None: - users = [u for u in users if u.account.has_role(account_role_name)] - - return users - - def find_user_by_email(user_email: str, keep_in_session: bool = True) -> User: user_datastore = SQLAlchemySessionUserDatastore(db.session, User, Role) user = user_datastore.find_user(email=user_email) diff --git a/flexmeasures/data/transactional.py b/flexmeasures/data/transactional.py index 315f3e5b3..9cf003298 100644 --- a/flexmeasures/data/transactional.py +++ b/flexmeasures/data/transactional.py @@ -2,6 +2,7 @@ These, and only these, functions should help you with treating your own code in the context of one database transaction. Which makes our lives easier. """ + from __future__ import annotations import sys @@ -84,7 +85,8 @@ def task_with_status_report(task_function, task_name: str | None = None): still needs to add to the session). If the task wants to commit partial results, and at the same time report that some things did not run well, it can raise a PartialTaskCompletionException and we recommend to use save-points (db.session.being_nested) to - do partial rollbacks (see https://docs.sqlalchemy.org/en/latest/orm/session_transaction.html#using-savepoint).""" + do partial rollbacks (see https://docs.sqlalchemy.org/en/latest/orm/session_transaction.html#using-savepoint). + """ task_name_to_report = ( task_name # store this closure var somewhere else before we might assign to it diff --git a/flexmeasures/ui/__init__.py b/flexmeasures/ui/__init__.py index 44fc8f070..c5eae31af 100644 --- a/flexmeasures/ui/__init__.py +++ b/flexmeasures/ui/__init__.py @@ -151,12 +151,12 @@ def add_jinja_filters(app): app.jinja_env.filters["asset_icon"] = asset_icon_name app.jinja_env.filters["username"] = username app.jinja_env.filters["accountname"] = accountname - app.jinja_env.filters[ - "parse_config_entry_by_account_roles" - ] = parse_config_entry_by_account_roles - app.jinja_env.filters[ - "find_first_applicable_config_entry" - ] = find_first_applicable_config_entry + app.jinja_env.filters["parse_config_entry_by_account_roles"] = ( + parse_config_entry_by_account_roles + ) + app.jinja_env.filters["find_first_applicable_config_entry"] = ( + find_first_applicable_config_entry + ) def add_jinja_variables(app): diff --git a/flexmeasures/ui/crud/accounts.py b/flexmeasures/ui/crud/accounts.py index 6130ca937..f6a64f2c1 100644 --- a/flexmeasures/ui/crud/accounts.py +++ b/flexmeasures/ui/crud/accounts.py @@ -4,10 +4,13 @@ from flask import request, url_for from flask_classful import FlaskView from flask_security import login_required +from flask_security.core import current_user + +from flexmeasures.auth.policy import user_has_admin_access + from flexmeasures.ui.crud.api_wrapper import InternalApi from flexmeasures.ui.utils.view_utils import render_flexmeasures_template from flexmeasures.ui.crud.assets import get_assets_by_account -from flexmeasures.ui.crud.users import get_users_by_account from flexmeasures.data.models.user import Account from flexmeasures.data import db @@ -34,15 +37,9 @@ class AccountCrudUI(FlaskView): @login_required def index(self): """/accounts""" - accounts = get_accounts() - for account in accounts: - account_obj = db.session.get(Account, account["id"]) - account["asset_count"] = account_obj.number_of_assets - account["user_count"] = account_obj.number_of_users return render_flexmeasures_template( "crud/accounts.html", - accounts=accounts, ) @login_required @@ -58,14 +55,12 @@ def get(self, account_id: str): account["consultancy_account_name"] = consultancy_account.name assets = get_assets_by_account(account_id) assets += get_assets_by_account(account_id=None) - users = get_users_by_account(account_id, include_inactive=include_inactive) - accounts = get_accounts() + accounts = get_accounts() if user_has_admin_access(current_user, "read") else [] return render_flexmeasures_template( "crud/account.html", account=account, accounts=accounts, assets=assets, - users=users, include_inactive=include_inactive, ) diff --git a/flexmeasures/ui/crud/users.py b/flexmeasures/ui/crud/users.py index 9da810c71..bfb0764b4 100644 --- a/flexmeasures/ui/crud/users.py +++ b/flexmeasures/ui/crud/users.py @@ -74,23 +74,6 @@ def process_internal_api_response( return user_data -def get_users_by_account( - account_id: int | str, include_inactive: bool = False -) -> list[User]: - get_users_response = InternalApi().get( - url_for( - "UserAPI:index", - account_id=account_id, - include_inactive=include_inactive, - ) - ) - users = [ - process_internal_api_response(user, make_obj=True) - for user in get_users_response.json() - ] - return users - - def get_all_users(include_inactive: bool = False) -> list[User]: get_users_response = InternalApi().get( url_for( @@ -98,10 +81,7 @@ def get_all_users(include_inactive: bool = False) -> list[User]: include_inactive=include_inactive, ) ) - users = [ - process_internal_api_response(user, make_obj=True) - for user in get_users_response.json() - ] + users = [user for user in get_users_response.json()] return users @@ -113,10 +93,8 @@ class UserCrudUI(FlaskView): def index(self): """/users""" include_inactive = request.args.get("include_inactive", "0") != "0" - users = get_all_users(include_inactive) - return render_flexmeasures_template( - "crud/users.html", users=users, include_inactive=include_inactive + "crud/users.html", include_inactive=include_inactive ) @login_required diff --git a/flexmeasures/ui/templates/admin/logged_in_user.html b/flexmeasures/ui/templates/admin/logged_in_user.html index bd78a2900..9395c9255 100644 --- a/flexmeasures/ui/templates/admin/logged_in_user.html +++ b/flexmeasures/ui/templates/admin/logged_in_user.html @@ -24,7 +24,7 @@

User Overview

Logged-in user: {{ logged_in_user.username }}
- +
diff --git a/flexmeasures/ui/templates/base.html b/flexmeasures/ui/templates/base.html index 7c5a776a4..85817594f 100644 --- a/flexmeasures/ui/templates/base.html +++ b/flexmeasures/ui/templates/base.html @@ -319,7 +319,6 @@ } async function embedAndLoad(chartSpecsPath, elementId, datasetName, previousResult, startDate, endDate) { - var combineLegend = 'true'; await vegaEmbed('#'+elementId, chartSpecsPath + 'dataset_name=' + datasetName + '&combine_legend='+ combineLegend + '&width=container&include_sensor_annotations=false&include_asset_annotations=false&chart_type=' + chartType, {{ chart_options | safe }}) .then(function (result) { @@ -358,10 +357,15 @@ }); } + var combineLegend = 'true'; {% if active_page == "assets" %} var dataPath = '/api/v3_0/assets/' + {{ asset.id }}; var dataDevPath = '/api/dev/asset/' + {{ asset.id }}; var datasetName = 'asset_' + {{ asset.id }}; + {% set total_sensors = asset.sensors_to_show | map(attribute='sensors') | map('length') | sum %} + {% if total_sensors > 7 %} + combineLegend = 'false'; + {% endif %} {% elif active_page == "sensors" %} var dataPath = '/api/dev/sensor/' + {{ sensor.id }}; var dataDevPath = '/api/dev/sensor/' + {{ sensor.id }}; @@ -805,6 +809,113 @@ } + diff --git a/flexmeasures/ui/templates/crud/account.html b/flexmeasures/ui/templates/crud/account.html index 735ebcc15..93a717a31 100644 --- a/flexmeasures/ui/templates/crud/account.html +++ b/flexmeasures/ui/templates/crud/account.html @@ -188,7 +188,7 @@

Edit {{ account.name }}

Account

Account: {{ account.name }}
-
Email address
+
@@ -251,90 +251,30 @@

Account

-

Users

- -
-
- -
- +

All users

+
+ +
ID
- - - - - - - - - - - - - - {% for user in users %} - - - - - - - - - - - {% endfor %} - - + class="table table-striped paginate nav-on-click" + title="View this asset" + id="usersTable" + >

Assets

@@ -400,11 +340,15 @@

Assets

{% block paginate_tables_script %} {{ super() }} {% endblock %} + {% block paginate_tables_script %} {{ super() }} {% endblock %} {% endblock%} \ No newline at end of file diff --git a/flexmeasures/ui/templates/crud/asset_audit_log.html b/flexmeasures/ui/templates/crud/asset_audit_log.html index 212ccd318..6ca5a8a1d 100644 --- a/flexmeasures/ui/templates/crud/asset_audit_log.html +++ b/flexmeasures/ui/templates/crud/asset_audit_log.html @@ -10,7 +10,7 @@

History of actions for asset {{ asset.name }}

-
+ diff --git a/flexmeasures/ui/templates/crud/user_audit_log.html b/flexmeasures/ui/templates/crud/user_audit_log.html index caf7076af..7cb66314e 100644 --- a/flexmeasures/ui/templates/crud/user_audit_log.html +++ b/flexmeasures/ui/templates/crud/user_audit_log.html @@ -11,7 +11,7 @@

History of actions for user {{ user.username }}

-
+ diff --git a/flexmeasures/ui/templates/crud/users.html b/flexmeasures/ui/templates/crud/users.html index 529d77f34..6bc6aca09 100644 --- a/flexmeasures/ui/templates/crud/users.html +++ b/flexmeasures/ui/templates/crud/users.html @@ -1,82 +1,36 @@ -{% extends "base.html" %} - -{% set active_page = "users" %} - -{% block title %} User listing {% endblock %} - +{% extends "base.html" %} +{% set active_page = "users" %} +{% block title %} User listing {% endblock %} {% block divs %}
-
-
+
+
-

All {% if not include_inactive %}active {% endif %}users

-
-
- -
- +

All users

+ +
+ +
-
- - - - - - - - - - - - - - - {% for user in users %} - - - - - - - - - - - - {% endfor %} - - +
+
-
-{% block paginate_tables_script %} {{ super() }} {% endblock %} - -{% endblock%} +{% block paginate_tables_script %} {{ super() }} {% endblock %} {% endblock%} diff --git a/flexmeasures/ui/templates/views/status.html b/flexmeasures/ui/templates/views/status.html index 677bd501d..edc0fb3f8 100644 --- a/flexmeasures/ui/templates/views/status.html +++ b/flexmeasures/ui/templates/views/status.html @@ -20,7 +20,7 @@

Data connectivity for sensors of {{ asset.name }}

- + @@ -62,7 +62,7 @@

Data connectivity for sensors of {{ asset.name }}

Latest jobs of {{ asset.name }}

- + diff --git a/flexmeasures/ui/tests/test_user_crud.py b/flexmeasures/ui/tests/test_user_crud.py index e3823581c..1a27a7de0 100644 --- a/flexmeasures/ui/tests/test_user_crud.py +++ b/flexmeasures/ui/tests/test_user_crud.py @@ -1,10 +1,8 @@ import pytest from flask import url_for -from flask_login import current_user from flexmeasures.data.services.users import find_user_by_email from flexmeasures.ui.tests.utils import mock_user_response -from flexmeasures.ui.crud.users import get_users_by_account """ @@ -13,15 +11,6 @@ """ -def test_get_users_by_account(client, requests_mock, as_prosumer_user1): - requests_mock.get( - "http://localhost//api/v3_0/users", - status_code=200, - json=mock_user_response(multiple=True), - ) - assert get_users_by_account(current_user.account.id)[0].username == "Alex" - - def test_user_list(client, as_admin, requests_mock): requests_mock.get( "http://localhost//api/v3_0/users", @@ -31,8 +20,6 @@ def test_user_list(client, as_admin, requests_mock): user_index = client.get(url_for("UserCrudUI:index"), follow_redirects=True) assert user_index.status_code == 200 assert b"All active users" in user_index.data - assert b"alex@seita.nl" in user_index.data - assert b"bert@seita.nl" in user_index.data @pytest.mark.parametrize("view", ["get", "toggle_active"]) diff --git a/flexmeasures/ui/utils/view_utils.py b/flexmeasures/ui/utils/view_utils.py index dfde591cf..61a025ea6 100644 --- a/flexmeasures/ui/utils/view_utils.py +++ b/flexmeasures/ui/utils/view_utils.py @@ -70,9 +70,9 @@ def render_flexmeasures_template(html_filename: str, **variables): variables["user_has_admin_reader_rights"] = user_has_admin_access( current_user, "read" ) - variables[ - "user_is_anonymous" - ] = current_user.is_authenticated and current_user.has_role("anonymous") + variables["user_is_anonymous"] = ( + current_user.is_authenticated and current_user.has_role("anonymous") + ) variables["user_email"] = current_user.is_authenticated and current_user.email or "" variables["user_name"] = ( current_user.is_authenticated and current_user.username or "" diff --git a/flexmeasures/utils/calculations.py b/flexmeasures/utils/calculations.py index 993fc6cc6..c5760c635 100644 --- a/flexmeasures/utils/calculations.py +++ b/flexmeasures/utils/calculations.py @@ -1,4 +1,5 @@ """ Various calculations """ + from __future__ import annotations from datetime import timedelta diff --git a/flexmeasures/utils/coding_utils.py b/flexmeasures/utils/coding_utils.py index 11404b4c9..d5f26a4a3 100644 --- a/flexmeasures/utils/coding_utils.py +++ b/flexmeasures/utils/coding_utils.py @@ -1,4 +1,5 @@ """ Various coding utils (e.g. around function decoration) """ + from __future__ import annotations import functools diff --git a/flexmeasures/utils/config_defaults.py b/flexmeasures/utils/config_defaults.py index c7f4248f4..1e92d0ba5 100644 --- a/flexmeasures/utils/config_defaults.py +++ b/flexmeasures/utils/config_defaults.py @@ -110,12 +110,16 @@ class Config(object): FLEXMEASURES_LP_SOLVER: str = "appsi_highs" FLEXMEASURES_JOB_TTL: timedelta = timedelta(days=1) FLEXMEASURES_PLANNING_HORIZON: timedelta = timedelta(days=2) - FLEXMEASURES_MAX_PLANNING_HORIZON: timedelta | int | None = 2520 # smallest number divisible by 1-10, which yields pleasant-looking durations for common sensor resolutions + FLEXMEASURES_MAX_PLANNING_HORIZON: timedelta | int | None = ( + 2520 # smallest number divisible by 1-10, which yields pleasant-looking durations for common sensor resolutions + ) FLEXMEASURES_PLANNING_TTL: timedelta = timedelta( days=7 ) # Time to live for UDI event ids of successful scheduling jobs. Set a negative timedelta to persist forever. FLEXMEASURES_DEFAULT_DATASOURCE: str = "FlexMeasures" - FLEXMEASURES_JOB_CACHE_TTL: int = 3600 # Time to live for the job caching keys in seconds. Set a negative timedelta to persist forever. + FLEXMEASURES_JOB_CACHE_TTL: int = ( + 3600 # Time to live for the job caching keys in seconds. Set a negative timedelta to persist forever. + ) FLEXMEASURES_TASK_CHECK_AUTH_TOKEN: str | None = None FLEXMEASURES_REDIS_URL: str = "localhost" FLEXMEASURES_REDIS_PORT: int = 6379 @@ -133,9 +137,13 @@ class Config(object): FLEXMEASURES_FALLBACK_REDIRECT: bool = False # Custom sunset switches - FLEXMEASURES_API_SUNSET_ACTIVE: bool = False # if True, sunset endpoints return 410 (Gone) responses; if False, they return 404 (Not Found) responses or will work as before, depending on whether the current FlexMeasures version still contains the endpoint logic + FLEXMEASURES_API_SUNSET_ACTIVE: bool = ( + False # if True, sunset endpoints return 410 (Gone) responses; if False, they return 404 (Not Found) responses or will work as before, depending on whether the current FlexMeasures version still contains the endpoint logic + ) FLEXMEASURES_API_SUNSET_DATE: str | None = None # e.g. 2023-05-01 - FLEXMEASURES_API_SUNSET_LINK: str | None = None # e.g. https://flexmeasures.readthedocs.io/en/latest/api/introduction.html#deprecation-and-sunset + FLEXMEASURES_API_SUNSET_LINK: str | None = ( + None # e.g. https://flexmeasures.readthedocs.io/en/latest/api/introduction.html#deprecation-and-sunset + ) # if True, all requests are forced to be via HTTPS. FLEXMEASURES_FORCE_HTTPS: bool = False diff --git a/flexmeasures/utils/error_utils.py b/flexmeasures/utils/error_utils.py index 131d970af..2bdcad889 100644 --- a/flexmeasures/utils/error_utils.py +++ b/flexmeasures/utils/error_utils.py @@ -18,7 +18,8 @@ def log_error(exc: Exception, error_msg: str): """Collect meta data about the exception and log it. - error_msg comes in as an extra attribute because Exception implementations differ here.""" + error_msg comes in as an extra attribute because Exception implementations differ here. + """ exc_info = sys.exc_info() last_traceback = exc_info[2] diff --git a/flexmeasures/utils/unit_utils.py b/flexmeasures/utils/unit_utils.py index 806ae38f0..b70bf5e75 100644 --- a/flexmeasures/utils/unit_utils.py +++ b/flexmeasures/utils/unit_utils.py @@ -8,6 +8,7 @@ Time series with fixed resolution can be converted from units of flow to units of stock (such as 'kW' to 'kWh'), and vice versa. Percentages can be converted to units of some physical capacity if a capacity is known (such as '%' to 'kWh'). """ + from __future__ import annotations from datetime import timedelta @@ -273,9 +274,7 @@ def convert_units( from_magnitudes = ( data.to_numpy() if isinstance(data, pd.Series) - else np.asarray(data) - if isinstance(data, list) - else np.array([data]) + else np.asarray(data) if isinstance(data, list) else np.array([data]) ) try: from_quantities = ur.Quantity(from_magnitudes, from_unit) diff --git a/requirements.txt b/requirements.txt index 38040051e..485504b4f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -341,7 +341,7 @@ typing-extensions==4.11.0 # sqlalchemy tzdata==2024.1 # via pandas -uniplot==0.12.5 +uniplot==0.14.1 # via -r requirements/app.in urllib3==2.2.1 # via diff --git a/requirements/3.10/dev.txt b/requirements/3.10/dev.txt index 70187d283..54c12824b 100644 --- a/requirements/3.10/dev.txt +++ b/requirements/3.10/dev.txt @@ -4,7 +4,7 @@ # # pip-compile --constraint=requirements/3.10/app.txt --constraint=requirements/3.10/test.txt --output-file=requirements/3.10/dev.txt requirements/dev.in # -black==22.10.0 +black==24.8.0 # via -r requirements/dev.in cfgv==3.4.0 # via pre-commit @@ -19,7 +19,7 @@ filelock==3.16.1 # via # -c requirements/3.10/app.txt # virtualenv -flake8==6.0.0 +flake8==7.1.1 # via -r requirements/dev.in flake8-blind-except==0.2.1 # via -r requirements/dev.in @@ -39,6 +39,7 @@ packaging==24.1 # via # -c requirements/3.10/app.txt # -c requirements/3.10/test.txt + # black # setuptools-scm pathspec==0.12.1 # via black @@ -48,9 +49,9 @@ platformdirs==4.3.6 # virtualenv pre-commit==3.8.0 # via -r requirements/dev.in -pycodestyle==2.10.0 +pycodestyle==2.12.1 # via flake8 -pyflakes==3.0.1 +pyflakes==3.2.0 # via flake8 pyinstrument==4.7.3 # via -r requirements/dev.in @@ -72,6 +73,7 @@ typing-extensions==4.12.2 # via # -c requirements/3.10/app.txt # -c requirements/3.10/test.txt + # black # mypy virtualenv==20.26.5 # via pre-commit diff --git a/requirements/3.11/dev.txt b/requirements/3.11/dev.txt index f563977b6..3405483c7 100644 --- a/requirements/3.11/dev.txt +++ b/requirements/3.11/dev.txt @@ -4,7 +4,7 @@ # # pip-compile --constraint=requirements/3.11/app.txt --constraint=requirements/3.11/test.txt --output-file=requirements/3.11/dev.txt requirements/dev.in # -black==22.10.0 +black==24.8.0 # via -r requirements/dev.in cfgv==3.4.0 # via pre-commit @@ -19,7 +19,7 @@ filelock==3.16.1 # via # -c requirements/3.11/app.txt # virtualenv -flake8==6.0.0 +flake8==7.1.1 # via -r requirements/dev.in flake8-blind-except==0.2.1 # via -r requirements/dev.in @@ -39,6 +39,7 @@ packaging==24.1 # via # -c requirements/3.11/app.txt # -c requirements/3.11/test.txt + # black # setuptools-scm pathspec==0.12.1 # via black @@ -48,9 +49,9 @@ platformdirs==4.3.6 # virtualenv pre-commit==3.8.0 # via -r requirements/dev.in -pycodestyle==2.10.0 +pycodestyle==2.12.1 # via flake8 -pyflakes==3.0.1 +pyflakes==3.2.0 # via flake8 pyinstrument==4.7.3 # via -r requirements/dev.in diff --git a/requirements/3.8/dev.txt b/requirements/3.8/dev.txt index bba6d3012..a1320af90 100644 --- a/requirements/3.8/dev.txt +++ b/requirements/3.8/dev.txt @@ -4,7 +4,7 @@ # # pip-compile --constraint=requirements/3.8/app.txt --constraint=requirements/3.8/test.txt --output-file=requirements/3.8/dev.txt requirements/dev.in # -black==22.10.0 +black==24.8.0 # via -r requirements/dev.in cfgv==3.4.0 # via pre-commit @@ -19,7 +19,7 @@ filelock==3.16.1 # via # -c requirements/3.8/app.txt # virtualenv -flake8==6.0.0 +flake8==7.1.1 # via -r requirements/dev.in flake8-blind-except==0.2.1 # via -r requirements/dev.in @@ -39,6 +39,7 @@ packaging==24.1 # via # -c requirements/3.8/app.txt # -c requirements/3.8/test.txt + # black # setuptools-scm pathspec==0.12.1 # via black @@ -48,9 +49,9 @@ platformdirs==4.3.6 # virtualenv pre-commit==3.5.0 # via -r requirements/dev.in -pycodestyle==2.10.0 +pycodestyle==2.12.1 # via flake8 -pyflakes==3.0.1 +pyflakes==3.2.0 # via flake8 pyinstrument==4.7.3 # via -r requirements/dev.in diff --git a/requirements/3.9/dev.txt b/requirements/3.9/dev.txt index 6fc8a47c4..f94b1e95d 100644 --- a/requirements/3.9/dev.txt +++ b/requirements/3.9/dev.txt @@ -4,7 +4,7 @@ # # pip-compile --constraint=requirements/3.9/app.txt --constraint=requirements/3.9/test.txt --output-file=requirements/3.9/dev.txt requirements/dev.in # -black==22.10.0 +black==24.8.0 # via -r requirements/dev.in cfgv==3.4.0 # via pre-commit @@ -19,7 +19,7 @@ filelock==3.16.1 # via # -c requirements/3.9/app.txt # virtualenv -flake8==6.0.0 +flake8==7.1.1 # via -r requirements/dev.in flake8-blind-except==0.2.1 # via -r requirements/dev.in @@ -39,6 +39,7 @@ packaging==24.1 # via # -c requirements/3.9/app.txt # -c requirements/3.9/test.txt + # black # setuptools-scm pathspec==0.12.1 # via black @@ -48,9 +49,9 @@ platformdirs==4.3.6 # virtualenv pre-commit==3.8.0 # via -r requirements/dev.in -pycodestyle==2.10.0 +pycodestyle==2.12.1 # via flake8 -pyflakes==3.0.1 +pyflakes==3.2.0 # via flake8 pyinstrument==4.7.3 # via -r requirements/dev.in diff --git a/requirements/app.in b/requirements/app.in index 9c1a068b6..0a11ef773 100644 --- a/requirements/app.in +++ b/requirements/app.in @@ -56,8 +56,8 @@ marshmallow>=3 marshmallow-polyfield marshmallow-sqlalchemy>=0.23.1 webargs -# Minimum version that correctly aligns time series that include NaN values -uniplot>=0.7.0 +# Minimum version that supports datetimes on the (x-)axis. +uniplot>=0.12.1 # >=2.5.2: https://github.com/marshmallow-code/flask-marshmallow/issues/262 Flask-SQLAlchemy>=2.5.2 # flask should be after all the flask plugins, because setup might find they ARE flask diff --git a/requirements/dev.in b/requirements/dev.in index 66f5fbe2d..bf58d1171 100644 --- a/requirements/dev.in +++ b/requirements/dev.in @@ -1,7 +1,7 @@ pre-commit # we're pinning the following two to what .pre-commit-config.yaml says -black==22.10.0 -flake8==6.0.0 +black==24.8.0 +flake8==7.1.1 flake8-blind-except mypy pytest-runner