diff --git a/documentation/api/change_log.rst b/documentation/api/change_log.rst index db5141fec..672284232 100644 --- a/documentation/api/change_log.rst +++ b/documentation/api/change_log.rst @@ -3,12 +3,11 @@ API change log =============== -v2.0 | 2021-04-02 +v2.0-2 | 2021-04-02 """"""""""""""""" - [**Breaking change**] Switched the interpretation of horizons to rolling horizons. - [**Breaking change**] Deprecated the use of ISO 8601 repeating time intervals to denote rolling horizons. -- [**Breaking change**] Deprecated the automatic inference of horizons for *postMeterData*, *postPrognosis*, *postPriceData* and *postWeatherData* endpoints for API version below v2.0. - Introduced the "prior" field for *postMeterData*, *postPrognosis*, *postPriceData* and *postWeatherData* endpoints. - Changed the Introduction section: @@ -18,16 +17,31 @@ v2.0 | 2021-04-02 - Rewrote relevant examples using horizon and prior fields. -v2.0 | 2021-02-19 +v2.0-1 | 2021-02-19 """"""""""""""""""" - REST endpoints for managing users: `/users/` (GET), `/user/` (GET, PATCH) and `/user//password-reset` (PATCH). -v2.0 | 2020-11-14 +v2.0-0 | 2020-11-14 """"""""""""""""""" - REST endpoints for managing assets: `/assets/` (GET, POST) and `/asset/` (GET, PATCH, DELETE). + +v1.3.9 | 2021-04-XX +""""""""""""""""" + +*Affects all versions since v1.0*. + +- Fixed regression by partially reverting the breaking change of v1.3-8: Re-instantiated automatic inference of horizons for Post requests for API versions below v2.0, but changed to inference policy: now inferring the data was recorded **right after each event** took place (leading to a zero horizon for each data point) rather than **after the last event** took place (which led to a different horizon for each data point); the latter had been the inference policy before v1.3-8. + +v1.3-8 | 2020-04-02 +""""""""""""""""""" + +*Affects all versions since v1.0*. + +- [**Breaking change**, partially reverted in v1.3-9] Deprecated the automatic inference of horizons for *postMeterData*, *postPrognosis*, *postPriceData* and *postWeatherData* endpoints for API version below v2.0. + v1.3-7 | 2020-12-16 """"""""""""""""""" @@ -155,10 +169,7 @@ v1.1-2 | 2018-08-15 - Added the *postPriceData* endpoint - Added a description of the *postPrognosis* endpoint in the Aggregator section - Added a description of the *postPriceData* endpoint in the Aggregator and Supplier sections - -.. ifconfig:: FLEXMEASURES_MODE == "play" - - - Added the *restoreData* endpoint +- Added the *restoreData* endpoint for servers in play mode v1.1-1 | 2018-08-06 """"""""""""""""""" diff --git a/documentation/api/introduction.rst b/documentation/api/introduction.rst index 117113d51..6c58cfc0a 100644 --- a/documentation/api/introduction.rst +++ b/documentation/api/introduction.rst @@ -257,7 +257,9 @@ In case of a single group of connections, the message may be flattened to: Timeseries ^^^^^^^^^^ -Timestamps and durations are consistent with the ISO 8601 standard. All timestamps in requests to the API must be timezone-aware. The timezone indication "Z" indicates a zero offset from UTC. Additionally, we use the following shorthand for sequential values within a time interval: +Timestamps and durations are consistent with the ISO 8601 standard. The resolution of the data is implicit, see :ref:`resolutions`. + +All timestamps in requests to the API must be timezone-aware. The timezone indication "Z" indicates a zero offset from UTC. Additionally, we use the following shorthand for sequential values within a time interval: .. code-block:: json @@ -405,8 +407,9 @@ This denotes that the prognosed interval has 5 minutes left to be concluded. Resolutions ^^^^^^^^^^^ -Specifying a resolution is redundant for POST requests that contain both "values" and a "duration". -Also, posted data is checked against the required resolution of the assets which are posted to. +Specifying a resolution is redundant for POST requests that contain both "values" and a "duration" ― FlexMeasures computes the resolution by dividing the duration by the number of values. + +When POSTing data, FlexMeasures checks this computed resolution against the required resolution of the assets which are posted to. If these can't be matched (through upsampling), an error will occur. GET requests (such as *getMeterData*) return data in the resolution which the sensor is configured for. A "resolution" may be specified explicitly to obtain the data in downsampled form, diff --git a/documentation/changelog.rst b/documentation/changelog.rst index eeec74783..ff83f33a6 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -18,7 +18,8 @@ Bugfixes Infrastructure / Support ---------------------- * Updated dependencies, including Flask-Security-Too [see `PR #82 `_] -* Integration with `timely beliefs `_ lib: Sensor data as TimedBeliefs [see `PR #79 `_] +* Improved documentation after user feedback [see `PR #97 `_] +* Begin experimental integration with `timely beliefs `_ lib: Sensor data as TimedBeliefs [see `PR #79 `_] * Add sensors with CLI command currently meant for developers only [see `PR #83 `_] * Add data (beliefs about sensor events) with CLI command currently meant for developers only [see `PR #85 `_] diff --git a/documentation/configuration.rst b/documentation/configuration.rst index 2262aaacc..954c09e4a 100644 --- a/documentation/configuration.rst +++ b/documentation/configuration.rst @@ -26,11 +26,14 @@ Level above which log messages are added to the log file. See the ``logging`` pa Default: ``logging.WARNING`` + +.. _modes-config: + FLEXMEASURES_MODE ^^^^^^^^^^^^^^^^^ The mode in which FlexMeasures is being run, e.g. "demo" or "play". -This is used to turn on certain extra behaviours. +This is used to turn on certain extra behaviours, see :ref:`modes-dev` for details. Default: ``""`` @@ -369,6 +372,8 @@ Default: ``None`` Demonstrations -------------- +.. _demo-credentials-config: + FLEXMEASURES_PUBLIC_DEMO_CREDENTIALS ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,6 +381,8 @@ When ``FLEXMEASURES_MODE=demo``\ , this can hold login credentials (demo user em Default: ``None`` +.. _demo-year-config: + FLEXMEASURES_DEMO_YEAR ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/documentation/dev/data.rst b/documentation/dev/data.rst index 39a5ca81f..4db5635db 100644 --- a/documentation/dev/data.rst +++ b/documentation/dev/data.rst @@ -100,36 +100,35 @@ Or, from within Postgres console: CREATE DATABASE flexmeasures_test WITH OWNER = flexmeasures_test; -Log in as the postgres superuser and connect to your newly-created database: +Finally, test if you can log in as the flexmeasures user: .. code-block:: bash - sudo -u postgres psql + psql -U flexmeasures --password -h 127.0.0.1 -d flexmeasures .. code-block:: sql - \connect flexmeasures + \q + +Add Postgres Extensions to your database(s) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +To find the nearest sensors, FlexMeasures needs some extra POstgres support. Add the following extensions while logged in as the postgres superuser: +.. code-block:: bash + + sudo -u postgres psql + .. code-block:: sql + \connect flexmeasures CREATE EXTENSION cube; CREATE EXTENSION earthdistance; -Connect to the ``flexmeasures_test`` database and repeat creating these extensions there. Then ``exit``. - -Finally, try logging in as the flexmeasures user once: - -.. code-block:: bash - - psql -U flexmeasures --password -h 127.0.0.1 -d flexmeasures - -.. code-block:: sql - - \q +If you have it, connect to the ``flexmeasures_test`` database and repeat creating these extensions there. Then ``exit``. Configure FlexMeasures app for that database diff --git a/documentation/dev/modes.rst b/documentation/dev/modes.rst new file mode 100644 index 000000000..238082d0f --- /dev/null +++ b/documentation/dev/modes.rst @@ -0,0 +1,41 @@ +.. _modes-dev: + +Modes +============ + +FlexMeasures can be run in specific modes (see the :ref:`modes-config` config setting). +This is useful for certain special situations. Two are supported out of the box and we document here +how FlexMeasures behaves differently in these modes. + +Demo +------- + +In this mode, the server is assumed to be used as a demonstration tool. Most of the following adaptations therefore happen in the UI. + +- [Data] Demo data is often from an older source, and it's a hassle to change the year to the current year. FlexMeasures allows to set :ref:`demo-year-config` and when in ``demo`` mode, the current year will be translated to that year in the background. +- [UI] Logged-in users can view queues on the demo server (usually only admins can do that) +- [UI] Demo servers often display login credentials, so visitors can try out functionality. Use the :ref:`demo-credentials-config` config setting to do this. +- [UI] The dashboard shows all non-empty asset groups, instead of only the ones for the current user. +- [UI] The analytics page mocks confidence intervals around power, price and weather data, so that the demo data doesn't need to have them. +- [UI] The portfolio page mocks flexibility numbers and a mocked control action. + +Play +------ + +In this mode, the server is assumed to be used to run simulations. + +Big features +^^^^^^^^^^^^^ + +- [Data] Allows overwriting existing data when saving data to the database. +- [API] The inferred recording time of incoming data is immediately after the event took place, rather than the actual time at which the server received the data. +- [API] Posting price or weather data does not trigger forecasting jobs. +- [API] The ``restoreData`` endpoint is registered, enabling database resets through the API. +- [API] When posting weather data for a new location, a new weather sensor is automatically created, instead of returning the nearest available weather sensor to post data to. + +Small features +^^^^^^^^^^^^^^^ + +- [API] Posted UDI events are not enforced to be consecutive. +- [API] Names in ``GetConnectionResponse`` are the connections' unique database names rather than their display names (this feature is planned to be deprecated). +- [UI] The dashboard plot showing the latest power value is not enforced to lie in the past (in case of simulating future values). diff --git a/documentation/dev/plugins.rst b/documentation/dev/plugins.rst index c422b37a0..8fbf02385 100644 --- a/documentation/dev/plugins.rst +++ b/documentation/dev/plugins.rst @@ -76,4 +76,21 @@ All else that is needed for this showcase (not shown here) is ``/ou -.. note:: Plugin views can also be added to the FlexMeasures UI menu ― just name them in the config setting :ref:`menu-config`. \ No newline at end of file +.. note:: Plugin views can also be added to the FlexMeasures UI menu ― just name them in the config setting :ref:`menu-config`. + + +Using other files in your plugin +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Say you want to include other Python files in your plugin, importing them in your ``__init__.py`` file. +This can be done if you put the plugin path on the import path. Do it like this in your ``__init__.py``: + +.. code-block:: python + + import os + import sys + + HERE = os.path.dirname(os.path.abspath(__file__)) + sys.path.insert(0, HERE) + + from my_other_file import my_function \ No newline at end of file diff --git a/documentation/getting-started.rst b/documentation/getting-started.rst index ca95bc513..4bbf9d6d7 100644 --- a/documentation/getting-started.rst +++ b/documentation/getting-started.rst @@ -17,6 +17,7 @@ Install dependencies and the ``flexmeasures`` platform itself: pip install flexmeasures +.. note:: With newer Python versions and Windows, some smaller dependencies (e.g. ``tables`` or ``rq-win``) might cause issues as support is often slower. You might overcome this with a little research, by `installing from wheels `_ or `from the repo `_, respectively. Make a secret key for sessions and password salts @@ -217,7 +218,7 @@ To collect weather measurements and forecasts from the DarkSky API, there is a t flexmeasures add external-weather-forecasts --location 33.4366,126.5269 --store-in-db -.. note:: DarkSky is not handing out tokens anymore, as they have been bought by Apple (see `issue 3 `_). +.. note:: DarkSky is not handing out tokens any more, as they have been bought by Apple (see `issue 3 `_). Preparing the job queue database and start workers diff --git a/documentation/index.rst b/documentation/index.rst index d5af9d4f2..b05c75b0c 100644 --- a/documentation/index.rst +++ b/documentation/index.rst @@ -85,6 +85,7 @@ The platform operator of FlexMeasures can be an Aggregator. dev/api dev/ci dev/plugins + dev/modes .. toctree:: :caption: Integrations diff --git a/flexmeasures/api/common/responses.py b/flexmeasures/api/common/responses.py index d381fa8d5..6b2133d06 100644 --- a/flexmeasures/api/common/responses.py +++ b/flexmeasures/api/common/responses.py @@ -64,7 +64,7 @@ def invalid_domain(message: str) -> ResponseTuple: return dict(result="Rejected", status="INVALID_DOMAIN", message=message), 400 -@BaseMessage("The prognosis horizon in your request could not be parsed.") +@BaseMessage("The horizon field in your request could not be parsed.") def invalid_horizon(message: str) -> ResponseTuple: return dict(result="Rejected", status="INVALID_HORIZON", message=message), 400 @@ -86,7 +86,7 @@ def invalid_ptu_duration(message: str) -> ResponseTuple: ) -@BaseMessage("Only the following resolutions are supported:") +@BaseMessage("Only the following resolutions in the data are supported:") def unapplicable_resolution(message: str) -> ResponseTuple: return dict(result="Rejected", status="INVALID_RESOLUTION", message=message), 400 diff --git a/flexmeasures/api/common/utils/validators.py b/flexmeasures/api/common/utils/validators.py index 6fe7b318c..e41c4d80f 100644 --- a/flexmeasures/api/common/utils/validators.py +++ b/flexmeasures/api/common/utils/validators.py @@ -296,7 +296,9 @@ def decorated_service(*args, **kwargs): return wrapper -def optional_prior_accepted(ex_post: bool = False, infer_missing: bool = True): +def optional_prior_accepted( + ex_post: bool = False, infer_missing: bool = True, infer_missing_play: bool = False +): """Decorator which specifies that a GET or POST request accepts an optional prior. It parses relevant form data and sets the "prior" keyword param. @@ -304,9 +306,15 @@ def optional_prior_accepted(ex_post: bool = False, infer_missing: bool = True): - Denotes "at least before " - This results in the filter belief_time_window = (None, prior) - Optionally, an ex_post flag can be passed to the decorator to indicate that only ex-post datetimes are allowed. - As a useful setting (at least for POST requests), set infer_missing to True to have servers - (that are not in play mode) derive a prior from the server time. + Interpretation for POST requests: + - Denotes "recorded to some datetime, + - this results in the assignment belief_time = prior + + :param ex_post: if True, only ex-post datetimes are allowed. + :param infer_missing: if True, servers assume that the belief_time of posted + values is server time. This setting is meant to be used for POST requests. + :param infer_missing_play: if True, servers in play mode assume that the belief_time of posted + values is server time. This setting is meant to be used for POST requests. """ def wrapper(fn): @@ -332,11 +340,11 @@ def decorated_service(*args, **kwargs): if prior < knowledge_time: extra_info = "Meter data can only be observed after the fact." return invalid_horizon(extra_info) - elif ( - infer_missing is True - and current_app.config.get("FLEXMEASURES_MODE", "") != "play" + elif infer_missing is True or ( + infer_missing_play is True + and current_app.config.get("FLEXMEASURES_MODE", "") == "play" ): - # A missing prior is inferred by the server (if not in play mode) + # A missing prior is inferred by the server prior = server_now() else: # Otherwise, a missing prior is fine (a horizon may still be inferred by the server) @@ -353,6 +361,7 @@ def decorated_service(*args, **kwargs): def optional_horizon_accepted( # noqa C901 ex_post: bool = False, infer_missing: bool = True, + infer_missing_play: bool = False, accept_repeating_interval: bool = False, ): """Decorator which specifies that a GET or POST request accepts an optional horizon. @@ -376,11 +385,13 @@ def optional_horizon_accepted( # noqa C901 def post_meter_data(horizon): return 'Meter data posted' - :param ex_post: if True, only non-positive horizons are allowed. - :param infer_missing: if True, servers that are in play mode assume that the belief_horizon of posted - values is 0 hours. This setting is meant to be used for POST requests. - :param accept_repeating_interval: if True, the "rolling" keyword param is also set - (this was used for POST requests before v2.0) + :param ex_post: if True, only non-positive horizons are allowed. + :param infer_missing: if True, servers assume that the belief_horizon of posted + values is 0 hours. This setting is meant to be used for POST requests. + :param infer_missing_play: if True, servers in play mode assume that the belief_horizon of posted + values is 0 hours. This setting is meant to be used for POST requests. + :param accept_repeating_interval: if True, the "rolling" keyword param is also set + (this was used for POST requests before v2.0) """ def wrapper(fn): @@ -410,15 +421,12 @@ def decorated_service(*args, **kwargs): "For example: R/P1D should be replaced by P1D." ) return invalid_horizon(extra_info) - elif ( - infer_missing is True + elif infer_missing is True or ( + infer_missing_play is True and current_app.config.get("FLEXMEASURES_MODE", "") == "play" ): - # A missing horizon is set to zero for servers in play mode + # A missing horizon is set to zero horizon = timedelta(hours=0) - elif infer_missing is True and accept_repeating_interval is True: - extra_info = "Missing horizons are no longer accepted for API versions below v2.0." - return invalid_horizon(extra_info) else: # Otherwise, a missing horizon is fine (a prior may still be inferred by the server) horizon = None diff --git a/flexmeasures/api/v1/implementations.py b/flexmeasures/api/v1/implementations.py index 373677ddb..893f4c68d 100644 --- a/flexmeasures/api/v1/implementations.py +++ b/flexmeasures/api/v1/implementations.py @@ -97,7 +97,9 @@ def get_meter_data_response( @units_accepted("power", "MW") @assets_required("connection") @values_required -@optional_horizon_accepted(ex_post=True, accept_repeating_interval=True) +@optional_horizon_accepted( + ex_post=True, infer_missing=True, accept_repeating_interval=True +) @period_required @post_data_checked_for_required_resolution("connection") @as_json diff --git a/flexmeasures/api/v1_1/implementations.py b/flexmeasures/api/v1_1/implementations.py index 3efdf2ffe..5de2bb3cd 100644 --- a/flexmeasures/api/v1_1/implementations.py +++ b/flexmeasures/api/v1_1/implementations.py @@ -13,6 +13,7 @@ invalid_domain, invalid_unit, unrecognized_market, + invalid_horizon, ) from flexmeasures.api.common.utils.api_utils import ( save_to_db, @@ -62,7 +63,7 @@ def get_connection_response(): @type_accepted("PostPriceDataRequest") @units_accepted("price", "EUR/MWh", "KRW/kWh") @assets_required("market") -@optional_horizon_accepted(accept_repeating_interval=True) +@optional_horizon_accepted(infer_missing=True, accept_repeating_interval=True) @values_required @period_required @post_data_checked_for_required_resolution("market") @@ -137,7 +138,7 @@ def post_price_data_response( @type_accepted("PostWeatherDataRequest") @unit_required @assets_required("sensor") -@optional_horizon_accepted(accept_repeating_interval=True) +@optional_horizon_accepted(infer_missing=True, accept_repeating_interval=True) @values_required @period_required @post_data_checked_for_required_resolution("sensor") @@ -263,7 +264,9 @@ def get_prognosis_response( @units_accepted("power", "MW") @assets_required("connection") @values_required -@optional_horizon_accepted(ex_post=False, accept_repeating_interval=True) +@optional_horizon_accepted( + ex_post=False, infer_missing=False, accept_repeating_interval=True +) @period_required @post_data_checked_for_required_resolution("connection") @as_json @@ -281,6 +284,11 @@ def post_prognosis_response( Store the new power values for each asset. """ + if horizon is None: + # API versions before v2.0 cannot handle a missing horizon, because there is no prior + extra_info = "Please specify the horizon field using an ISO 8601 duration (such as 'PT24H')." + return invalid_horizon(extra_info) + return create_connection_and_value_groups( unit, generic_asset_name_groups, value_groups, horizon, rolling, start, duration ) diff --git a/flexmeasures/api/v2_0/implementations/sensors.py b/flexmeasures/api/v2_0/implementations/sensors.py index a4c8d6382..093a7f8b2 100644 --- a/flexmeasures/api/v2_0/implementations/sensors.py +++ b/flexmeasures/api/v2_0/implementations/sensors.py @@ -46,8 +46,8 @@ @type_accepted("PostPriceDataRequest") @units_accepted("price", "EUR/MWh", "KRW/kWh") @assets_required("market") -@optional_horizon_accepted() -@optional_prior_accepted() +@optional_horizon_accepted(infer_missing=False, infer_missing_play=True) +@optional_prior_accepted(infer_missing=True, infer_missing_play=False) @values_required @period_required @post_data_checked_for_required_resolution("market") @@ -130,8 +130,8 @@ def post_price_data_response( # noqa C901 @type_accepted("PostWeatherDataRequest") @unit_required @assets_required("sensor") -@optional_horizon_accepted() -@optional_prior_accepted() +@optional_horizon_accepted(infer_missing=False, infer_missing_play=True) +@optional_prior_accepted(infer_missing=True, infer_missing_play=False) @values_required @period_required @post_data_checked_for_required_resolution("sensor") @@ -222,8 +222,8 @@ def post_weather_data_response( # noqa: C901 @units_accepted("power", "MW") @assets_required("connection") @values_required -@optional_horizon_accepted(ex_post=True) -@optional_prior_accepted(ex_post=True) +@optional_horizon_accepted(ex_post=True, infer_missing=False, infer_missing_play=True) +@optional_prior_accepted(ex_post=True, infer_missing=True, infer_missing_play=False) @period_required @post_data_checked_for_required_resolution("connection") @as_json @@ -254,8 +254,8 @@ def post_meter_data_response( @units_accepted("power", "MW") @assets_required("connection") @values_required -@optional_horizon_accepted(ex_post=False) -@optional_prior_accepted(ex_post=False) +@optional_horizon_accepted(ex_post=False, infer_missing=False, infer_missing_play=False) +@optional_prior_accepted(ex_post=False, infer_missing=True, infer_missing_play=False) @period_required @post_data_checked_for_required_resolution("connection") @as_json diff --git a/flexmeasures/data/scripts/cli_tasks/data_add.py b/flexmeasures/data/scripts/cli_tasks/data_add.py index ab8f0a9f7..f0937d247 100644 --- a/flexmeasures/data/scripts/cli_tasks/data_add.py +++ b/flexmeasures/data/scripts/cli_tasks/data_add.py @@ -337,14 +337,14 @@ def add_beliefs( multiple=True, type=click.Choice(["1", "6", "24", "48"]), default=["1", "6", "24", "48"], - help="Forecasting horizon in hours. This argument can be given multiple times.", + help="Forecasting horizon in hours. This argument can be given multiple times. Defaults to all possible horizons.", ) @click.option( "--as-job", is_flag=True, help="Whether to queue a forecasting job instead of computing directly." " Useful to run locally and create forecasts on a remote server. In that case, just point the redis db in your" - " config settings to that of the remote server. To process the job, run a worker to process the forecasting queue.", + " config settings to that of the remote server. To process the job, run a worker to process the forecasting queue. Defaults to False.", ) def create_forecasts( asset_type: str = None, diff --git a/flexmeasures/data/services/time_series.py b/flexmeasures/data/services/time_series.py index 44fa20757..1c0af44eb 100644 --- a/flexmeasures/data/services/time_series.py +++ b/flexmeasures/data/services/time_series.py @@ -257,6 +257,9 @@ def convert_query_window_for_demo( end = (query_window[-1] + timedelta(days=1)).replace(year=demo_year) else: end = query_window[-1] + + if start >= end: + start, end = (end, start) return start, end diff --git a/flexmeasures/ui/utils/plotting_utils.py b/flexmeasures/ui/utils/plotting_utils.py index 9c407e01b..ac69d44f4 100644 --- a/flexmeasures/ui/utils/plotting_utils.py +++ b/flexmeasures/ui/utils/plotting_utils.py @@ -564,7 +564,11 @@ def get_latest_power_as_plot(asset: Asset, small: bool = False) -> Tuple[str, st First returned string is the measurement time, second string is the html string.""" if current_app.config.get("FLEXMEASURES_MODE", "") == "demo": - before = server_now().replace(year=2015) + demo_year = current_app.config.get("FLEXMEASURES_DEMO_YEAR", None) + if demo_year is None: + before = server_now() + else: + before = server_now().replace(year=demo_year) elif current_app.config.get("FLEXMEASURES_MODE", "") == "play": before = None # type:ignore else: diff --git a/flexmeasures/ui/utils/view_utils.py b/flexmeasures/ui/utils/view_utils.py index 6ee924e06..1b50a9caa 100644 --- a/flexmeasures/ui/utils/view_utils.py +++ b/flexmeasures/ui/utils/view_utils.py @@ -131,7 +131,7 @@ def set_time_range_for_session(): .astimezone(time_utils.get_timezone()) ) - # Our demo server works only with the current year's data + # Our demo server's UI should only work with the current year's data if current_app.config.get("FLEXMEASURES_MODE", "") == "demo": session["start_time"] = session["start_time"].replace(year=datetime.now().year) session["end_time"] = session["end_time"].replace(year=datetime.now().year) diff --git a/flexmeasures/utils/app_utils.py b/flexmeasures/utils/app_utils.py index a075d14b7..4065d79bd 100644 --- a/flexmeasures/utils/app_utils.py +++ b/flexmeasures/utils/app_utils.py @@ -76,7 +76,7 @@ def register_plugins(app: Flask): - Your plugin folders contains an __init__.py file. - In this init, you define a Blueprint object called _bp - We'll refer to the plugins with the name of your plugin folders (last part of tthe path). + We'll refer to the plugins with the name of your plugin folders (last part of the path). """ plugin_paths = app.config.get("FLEXMEASURES_PLUGIN_PATHS", "") if not isinstance(plugin_paths, list): diff --git a/to_pypi.sh b/to_pypi.sh index a26723733..22342682c 100755 --- a/to_pypi.sh +++ b/to_pypi.sh @@ -8,24 +8,24 @@ # The version comes from setuptools_scm. See `python setup.py --version`. # setuptools_scm works via git tags that should implement a semantic versioning scheme, e.g. v0.2.3 # -# If there were zero commits since since tag, we have a real release and the version basicaly *is* what the tag says. -# Otherwise, the version also include a .devN identifier, where N is the number of commits since the last version tag. +# If there were zero commits since since tag, we have a real release and the version basically *is* what the tag says. +# Otherwise, the version also includes a .devN identifier, where N is the number of commits since the last version tag. # # More information on creating a dev release # ------------------------------------------- # Note that the only way to create a new dev release is to add another commit on your development branch. -# It might have been convenient to not have to commit to do that (for exoerimenting with very small changes), +# It might have been convenient to not have to commit to do that (for experimenting with very small changes), # but we decided against that. Let's explore why for a bit: # # First, setuptools_scm has the ability to add a local scheme (git commit and date/time) to the version, # but we've disabled that, as that extra part isn't formatted in a way that Pypi accepts it. -# Another way would have been to add a local version identifier ("+M", not the plus sign), +# Another way would have been to add a local version identifier ("+M", note the plus sign), # which is allowed in PEP 440 but explicitly disallowed by Pypi. # Finally, if we simply add a number to .devN (-> .devNM), the ordering of dev versions would be # disturbed after the next local commit (e.g. we add 1 to .dev4, making it .dev41, and then the next version, .dev5, # is not the highest version chosen by PyPi). # -# So we'll use these tools as the experts intend us to. +# So we'll use these tools as the experts intended. # If you want, you can read more about acceptable versions in PEP 440: https://www.python.org/dev/peps/pep-0440/ @@ -35,4 +35,4 @@ pip -q install twine python setup.py egg_info sdist python setup.py egg_info bdist_wheel -twine upload dist/* \ No newline at end of file +twine upload dist/*