diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7570788..7b03ca1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,41 +15,13 @@ repos: - id: debug-statements - id: detect-private-key # python code formatting/linting - - repo: https://github.com/PyCQA/pydocstyle - rev: 6.1.1 + - repo: https://github.com/charliermarsh/ruff-pre-commit + # Ruff version. + rev: "v0.0.236" hooks: - - id: pydocstyle - args: [--convention=google, "--add-ignore=D200,D202,D210,D212,D415"] + - id: ruff files: sdk/python/pvsite_datamodel - exclude: __version__.py - - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 - hooks: - - id: flake8 - args: - [ - "--max-line-length", - "100", - "--extend-ignore=E203", - "--per-file-ignores", - "__init__.py:F401", - "sdk/python/pvsite_datamodel", - - ] - - repo: https://github.com/PyCQA/isort - rev: 5.11.4 - hooks: - - id: isort - args: ["--profile", "black", "--line-length", "100"] - files: sdk/python/pvsite_datamodel - exclude: __version__.py - - repo: https://github.com/psf/black - rev: 22.12.0 - hooks: - - id: black - args: ["--line-length", "100"] - files: sdk/python/pvsite_datamodel - exclude: __version__.py + args: [--fix, -v] # yaml formatting - repo: https://github.com/pre-commit/mirrors-prettier rev: v3.0.0-alpha.4 diff --git a/gen/pvsite.py b/gen/pvsite.py index 7fcc804..503ebf5 100644 --- a/gen/pvsite.py +++ b/gen/pvsite.py @@ -28,7 +28,7 @@ class Sites(Base): ml_id = sa.Column(sa.Integer(), autoincrement=True) __table_args__ = ( - + UniqueConstraint("client_site_id",client_uuid, name='idx_client') ) diff --git a/gen/pvsite.sql b/gen/pvsite.sql index 8d40d37..0726153 100644 --- a/gen/pvsite.sql +++ b/gen/pvsite.sql @@ -83,7 +83,7 @@ COMMENT ON TABLE "sites" IS 'Each site row specifies a single panel or cluster o found on a residential house or commercial building. Their data is provided by a client. -*Approximate size: * +*Approximate size: * 4 clients * ~1000 sites each = ~4000 rows'; COMMENT ON COLUMN "sites"."client_uuid" IS 'The internal ID of the client providing the site data'; @@ -109,7 +109,7 @@ COMMENT ON COLUMN "sites"."ml_id" IS 'Auto-incrementing integer ID of the site f COMMENT ON TABLE "generation" IS 'Each yield row specifies a generated power output over a given time range for a site. -*Approximate size: * +*Approximate size: * Generation populated every 5 minutes per site * 4000 sites = ~1,125,000 rows per day'; COMMENT ON COLUMN "generation"."site_uuid" IS 'The site for which this geenration yield belongs to'; @@ -119,9 +119,9 @@ COMMENT ON COLUMN "generation"."power_kw" IS 'The actual generated power in kW a COMMENT ON COLUMN "generation"."datetime_interval_uuid" IS 'The time interval over which this generated power value applies'; COMMENT ON TABLE "forecasts" IS 'Each forecast row refers to a sequence of predicted solar generation values -over a set of target times for a site. +over a set of target times for a site. -*Approximate size: * +*Approximate size: * One forecast per site every 5 minutes = ~1,125,000 rows per day'; COMMENT ON COLUMN "forecasts"."site_uuid" IS 'The site for which the forecast sequence was generated'; @@ -130,11 +130,11 @@ COMMENT ON COLUMN "forecasts"."created_utc" IS 'The creation time of the forecas COMMENT ON COLUMN "forecasts"."forecast_version" IS 'The semantic version of the model used to generate the forecast'; -COMMENT ON TABLE "forecast_values" IS 'Each forecast_value row is a prediction for the power output +COMMENT ON TABLE "forecast_values" IS 'Each forecast_value row is a prediction for the power output of a site over a target datetime interval. Many predictions are made for each site at each target interval. -*Approximate size: * +*Approximate size: * One forecast value every 5 minutes per site per forecast. Each forecast"s prediction sequence covers 24 hours of target intervals = ~324,000,000 rows per day'; @@ -145,12 +145,12 @@ COMMENT ON COLUMN "forecast_values"."forecast_generation_kw" IS 'The predicted p COMMENT ON COLUMN "forecast_values"."forecast_uuid" IS 'The forecast sequence this forcast value belongs to'; -COMMENT ON TABLE "latest_forecast_values" IS 'Each forecast_value row is a prediction for the power output -of a site over a target datetime interval. Only the most recent +COMMENT ON TABLE "latest_forecast_values" IS 'Each forecast_value row is a prediction for the power output +of a site over a target datetime interval. Only the most recent prediction for each target time interval is stored in this table per site. -*Approximate size: * +*Approximate size: * One forecast value every 5 minutes per site per forecast sequence = ~1,125,000 rows per day'; @@ -166,18 +166,18 @@ COMMENT ON COLUMN "latest_forecast_values"."forecast_version" IS 'The semantic v COMMENT ON TABLE "clients" IS 'Each client row defines a provider of site data -*Approximate size: * +*Approximate size: * One row per client = ~4 rows'; COMMENT ON TABLE "datetime_intervals" IS 'Each datetime_interval row defines a timespan between a start and end time -*Approximate size: * +*Approximate size: * One interval every 5 minutes per day = ~288 rows per day'; COMMENT ON TABLE "status" IS 'Each status row defines a message reporting on the status of the services within the nowcasting domain -*Approximate size: * +*Approximate size: * ~1 row per day'; ALTER TABLE "sites" ADD FOREIGN KEY ("client_uuid") REFERENCES "clients" ("client_uuid"); diff --git a/pvsite.dbml b/pvsite.dbml index 3d57b1b..5c36f84 100644 --- a/pvsite.dbml +++ b/pvsite.dbml @@ -1,6 +1,6 @@ Project pvsite { database_type: 'PostgreSQL' - + Note: ''' Datamodel for PV site-level data. To be surfaced via the to-be built nowcasting site-level API and frontend. @@ -23,17 +23,17 @@ Table sites { created_utc timestamp [not null] updated_utc timestamp [not null] ml_id serial [note: 'Auto-incrementing integer ID of the site for use in ML training'] - + Indexes { (client_uuid, client_site_id) [unique, name: 'idx_client'] } - + Note: ''' Each site row specifies a single panel or cluster of panels found on a residential house or commercial building. Their data is provided by a client. - - *Approximate size: * + + *Approximate size: * 4 clients * ~1000 sites each = ~4000 rows ''' } @@ -44,12 +44,12 @@ Table generation { power_kw real [not null, note: 'The actual generated power in kW at this site for this datetime interval'] datetime_interval_uuid uuid [not null, note: 'The time interval over which this generated power value applies'] created_utc timestamp [not null] - + Note: ''' Each yield row specifies a generated power output over a given time range for a site. - - *Approximate size: * + + *Approximate size: * Generation populated every 5 minutes per site * 4000 sites = ~1,125,000 rows per day ''' } @@ -59,12 +59,12 @@ Table forecasts { site_uuid uuid [not null, note: 'The site for which the forecast sequence was generated'] created_utc timestamp [not null, note: 'The creation time of the forecast sequence'] forecast_version varchar(32) [not null, note: 'The semantic version of the model used to generate the forecast'] - + Note: ''' Each forecast row refers to a sequence of predicted solar generation values - over a set of target times for a site. - - *Approximate size: * + over a set of target times for a site. + + *Approximate size: * One forecast per site every 5 minutes = ~1,125,000 rows per day ''' } @@ -75,13 +75,13 @@ Table forecast_values { forecast_generation_kw real [not null, note: 'The predicted power generation of this site for the given time interval'] created_utc timestamp [not null] forecast_uuid uuid [not null, note: 'The forecast sequence this forcast value belongs to'] - + Note: ''' - Each forecast_value row is a prediction for the power output + Each forecast_value row is a prediction for the power output of a site over a target datetime interval. Many predictions are made for each site at each target interval. - - *Approximate size: * + + *Approximate size: * One forecast value every 5 minutes per site per forecast. Each forecast's prediction sequence covers 24 hours of target intervals = ~324,000,000 rows per day @@ -96,14 +96,14 @@ Table latest_forecast_values { forecast_uuid uuid [not null, note: 'The forecast sequence this forcast value belongs to'] site_uuid uuid [not null, note: 'The site for which the forecast sequence was generated'] forecast_version varchar(32) [not null, note: 'The semantic version of the model used to generate the forecast'] - + Note: ''' - Each forecast_value row is a prediction for the power output - of a site over a target datetime interval. Only the most recent + Each forecast_value row is a prediction for the power output + of a site over a target datetime interval. Only the most recent prediction for each target time interval is stored in this table per site. - - *Approximate size: * + + *Approximate size: * One forecast value every 5 minutes per site per forecast sequence = ~1,125,000 rows per day ''' @@ -113,11 +113,11 @@ Table clients { client_uuid uuid [primary key, not null] client_name varchar(255) [not null] created_utc timestamp [not null] - + Note: ''' Each client row defines a provider of site data - - *Approximate size: * + + *Approximate size: * One row per client = ~4 rows ''' } @@ -127,16 +127,16 @@ Table datetime_intervals { start_utc timestamp [not null] end_utc timestamp [not null] created_utc timestamp [not null] - + Indexes { start_utc end_utc } - + Note: ''' Each datetime_interval row defines a timespan between a start and end time - - *Approximate size: * + + *Approximate size: * One interval every 5 minutes per day = ~288 rows per day ''' } @@ -150,8 +150,8 @@ Table status { Note: ''' Each status row defines a message reporting on the status of the services within the nowcasting domain - - *Approximate size: * + + *Approximate size: * ~1 row per day ''' } diff --git a/sdk/python/pvsite_datamodel/__init__.py b/sdk/python/pvsite_datamodel/__init__.py index 858a543..0489767 100644 --- a/sdk/python/pvsite_datamodel/__init__.py +++ b/sdk/python/pvsite_datamodel/__init__.py @@ -1,6 +1,4 @@ -""" -Python SDK for reading/writing to/from pvsite database -""" +"""Python SDK for reading/writing to/from pvsite database.""" from .connection import DatabaseConnection from .sqlmodels import ( diff --git a/sdk/python/pvsite_datamodel/connection.py b/sdk/python/pvsite_datamodel/connection.py index 638754d..7fa614a 100644 --- a/sdk/python/pvsite_datamodel/connection.py +++ b/sdk/python/pvsite_datamodel/connection.py @@ -1,4 +1,4 @@ -""" Database Connection class""" +"""Database Connection class.""" import logging from sqlalchemy import create_engine @@ -10,19 +10,20 @@ class DatabaseConnection: - """Database connection class""" + """Database connection class.""" def __init__(self, url: URL | str, echo: bool = True): - """ - Set up database connection + """Set up database connection. - url: the database url, used for connecting + :param url: the database url, used for connecting + :param echo: whether to echo """ self.url = url self.engine = create_engine(self.url, echo=echo) self.Session = sessionmaker(bind=self.engine) - assert self.url is not None, Exception("Need to set url for database connection") + if self.url is None: + raise Exception("Need to set url for database connection") def get_session(self) -> Session: - """Get sqlalamcy session""" + """Get sqlalchemy session.""" return self.Session() diff --git a/sdk/python/pvsite_datamodel/read/generation.py b/sdk/python/pvsite_datamodel/read/generation.py index 3c0ea91..dd685a2 100644 --- a/sdk/python/pvsite_datamodel/read/generation.py +++ b/sdk/python/pvsite_datamodel/read/generation.py @@ -1,12 +1,13 @@ -""" Read pv generation functions """ +"""Read pv generation functions.""" import logging import uuid from datetime import datetime from typing import List, Optional -from pvsite_datamodel.sqlmodels import ClientSQL, DatetimeIntervalSQL, GenerationSQL, SiteSQL from sqlalchemy.orm import Session +from pvsite_datamodel.sqlmodels import ClientSQL, DatetimeIntervalSQL, GenerationSQL, SiteSQL + from .utils import filter_query_by_datetime_interval logger = logging.getLogger(__name__) @@ -18,16 +19,14 @@ def get_pv_generation_by_client( end_utc: Optional[datetime] = None, client_names: Optional[List[str]] = None, ) -> List[GenerationSQL]: - """ - Get the generation data by client + """Get the generation data by client. :param session: database session :param end_utc: search filters < on 'datetime_utc'. Can be None :param start_utc: search filters >= on 'datetime_utc'. Can be None :param client_names: optional list of provider names - :return:list of pv yields + :return:list of pv yields. """ - # start main query query = session.query(GenerationSQL) query = query.join(SiteSQL) @@ -58,8 +57,7 @@ def get_pv_generation_by_sites( end_utc: Optional[datetime] = None, site_uuids: Optional[List[uuid.UUID]] = None, ) -> List[GenerationSQL]: - """ - Get the generation data by site + """Get the generation data by site. :param session: database session :param start_utc: search filters >= on 'datetime_utc' @@ -67,7 +65,6 @@ def get_pv_generation_by_sites( :param site_uuids: optional list of site uuids :return: list of pv yields """ - # start main query query = session.query(GenerationSQL) query = query.join(SiteSQL) diff --git a/sdk/python/pvsite_datamodel/read/latest_forecast_values.py b/sdk/python/pvsite_datamodel/read/latest_forecast_values.py index 93b96a0..1e678b5 100644 --- a/sdk/python/pvsite_datamodel/read/latest_forecast_values.py +++ b/sdk/python/pvsite_datamodel/read/latest_forecast_values.py @@ -1,27 +1,24 @@ -""" -Functions for reading from latest_forecast_values table -""" +"""Functions for reading from latest_forecast_values table.""" import datetime as dt import uuid from typing import Dict, List, Optional -from pvsite_datamodel.sqlmodels import DatetimeIntervalSQL, LatestForecastValueSQL from sqlalchemy.orm import Query, Session +from pvsite_datamodel.sqlmodels import DatetimeIntervalSQL, LatestForecastValueSQL + def get_latest_forecast_values_by_site( session: Session, site_uuids: List[uuid.UUID], start_utc: Optional[dt.datetime] = None ) -> Dict[uuid.UUID, List[LatestForecastValueSQL]]: - """ - Get the latest forecast values by input sites + """Get the latest forecast values by input sites. :param session: The sqlalchemy database session :param site_uuids: list of site_uuids for which to fetch latest forecast values :param start_utc: filters on forecast values target_time >= start_utc :return: dict containing {site_uuid1: List[LatestForecastValueSQL], site_uuid2: ...} """ - # start main query query: Query = session.query(LatestForecastValueSQL) query = query.join(DatetimeIntervalSQL) diff --git a/sdk/python/pvsite_datamodel/read/site.py b/sdk/python/pvsite_datamodel/read/site.py index 16ad944..a00a701 100644 --- a/sdk/python/pvsite_datamodel/read/site.py +++ b/sdk/python/pvsite_datamodel/read/site.py @@ -1,22 +1,19 @@ -""" -Functions for reading to pvsite db -""" +"""Functions for reading to pvsite db.""" import logging from typing import List, Optional -from pvsite_datamodel.sqlmodels import ClientSQL, SiteSQL from sqlalchemy.orm import Session +from pvsite_datamodel.sqlmodels import ClientSQL, SiteSQL + logger = logging.getLogger(__name__) def get_site_by_uuid(session: Session, site_uuid: str) -> SiteSQL: - """ - Get site object from uuid. - - Raise error if site does not exist + """Get site object from uuid. + Raise error if site does not exist. :param session: database sessions :param site_uuid: the site uuid :return: the site object @@ -31,15 +28,13 @@ def get_site_by_uuid(session: Session, site_uuid: str) -> SiteSQL: def get_site_by_client_site_id(session: Session, client_name: str, client_site_id: int) -> SiteSQL: - """ - Get site from client name and client site id + """Get site from client name and client site id. :param session: database sessions :param client_name: client name :param client_site_id: client's id of site :return: site object, or None """ - logger.debug(f"Getting {client_name}'s site {client_site_id}") # start main query @@ -64,15 +59,13 @@ def get_site_by_client_site_id(session: Session, client_name: str, client_site_i def get_site_by_client_site_name( session: Session, client_name: str, client_site_name: str ) -> SiteSQL: - """ - Get site from client name and client site id + """Get site from client name and client site id. :param session: database sessions :param client_name: client name :param client_site_name: client's name of site :return: site object, or None """ - logger.debug(f"Getting {client_name}'s site {client_site_name}") # start main query @@ -95,13 +88,11 @@ def get_site_by_client_site_name( def get_all_sites(session: Session) -> List[SiteSQL]: - """ - Gets all sites from sites table + """Get all sites from the sites table. :param session: database sessions :return: site object """ - logger.debug("Getting all sites") # start main query diff --git a/sdk/python/pvsite_datamodel/read/status.py b/sdk/python/pvsite_datamodel/read/status.py index b2bde4e..a0dc4c5 100644 --- a/sdk/python/pvsite_datamodel/read/status.py +++ b/sdk/python/pvsite_datamodel/read/status.py @@ -1,21 +1,19 @@ -""" -Functions to read from the Status table -""" +"""Functions to read from the Status table.""" from typing import Optional -from pvsite_datamodel.sqlmodels import StatusSQL from sqlalchemy.orm import Session +from pvsite_datamodel.sqlmodels import StatusSQL + def get_latest_status(session: Session) -> Optional[StatusSQL]: - """ - Gets the latest entry in the status table. Returns None if there are no entries + """Get the latest entry in the status table. + Return None if there are no entries. :param session: database session - return: Latest StatusSQL object, or None + :return: Latest StatusSQL object, or None """ - # Query status table, ordered by created time query = session.query(StatusSQL) query = query.order_by(StatusSQL.created_utc.desc()) diff --git a/sdk/python/pvsite_datamodel/read/utils.py b/sdk/python/pvsite_datamodel/read/utils.py index 74fd384..71f0f4b 100644 --- a/sdk/python/pvsite_datamodel/read/utils.py +++ b/sdk/python/pvsite_datamodel/read/utils.py @@ -1,19 +1,17 @@ -""" -Cross-package functions -""" +"""Cross-package functions.""" from datetime import datetime from typing import Optional -from pvsite_datamodel.sqlmodels import DatetimeIntervalSQL from sqlalchemy.orm import Query +from pvsite_datamodel.sqlmodels import DatetimeIntervalSQL + def filter_query_by_datetime_interval( query: Query, start_utc: Optional[datetime] = None, end_utc: Optional[datetime] = None ) -> Query: - """ - Applies a filter on the input query according to the Datetime Interval table. + """Apply a filter on the input query according to the Datetime Interval table. Ensure DatetimeIntervalSQL has been joined to query already :param query: The sqlalchemy query @@ -21,7 +19,6 @@ def filter_query_by_datetime_interval( :param end_utc: search filters < on 'end_utc'. Can be None :return: The sqlalchemy query """ - # filter on start time if start_utc is not None: query = query.filter(DatetimeIntervalSQL.start_utc >= start_utc) diff --git a/sdk/python/pvsite_datamodel/schema.py b/sdk/python/pvsite_datamodel/schema.py index e153e0a..6dd5b10 100644 --- a/sdk/python/pvsite_datamodel/schema.py +++ b/sdk/python/pvsite_datamodel/schema.py @@ -1,6 +1,4 @@ -""" -Schemas and validation for dataframes used in the package -""" +"""Schemas and validation for dataframes used in the package.""" import uuid @@ -10,15 +8,15 @@ class InputForecastValuesSchema(pa.SchemaModel): - """Schema defining the makeup of the input forecast values dataframe""" + """Schema defining the makeup of the input forecast values dataframe.""" target_datetime_utc: Series[DateTime] = pa.Field() forecast_kw: Series[Float] = pa.Field(ge=0) pv_uuid: Series[String] = pa.Field(le=32) @pa.check("pv_uuid") - def pv_uuid_check(cls, series: Series[String]) -> Series[Bool]: - """Check that pv_uuid column values are valid uuids""" + def pv_uuid_check(self, series: Series[String]) -> Series[Bool]: + """Check that pv_uuid column values are valid uuids.""" try: uuid.UUID(series.str, version=4) except ValueError: diff --git a/sdk/python/pvsite_datamodel/sqlmodels.py b/sdk/python/pvsite_datamodel/sqlmodels.py index 148b698..e287fe6 100644 --- a/sdk/python/pvsite_datamodel/sqlmodels.py +++ b/sdk/python/pvsite_datamodel/sqlmodels.py @@ -1,6 +1,5 @@ -""" -SQLAlchemy definition of the pvsite database schema -""" +"""SQLAlchemy definition of the pvsite database schema.""" + from __future__ import annotations # This means we can use Typing of objects that have jet to be defined @@ -20,14 +19,13 @@ class CreatedMixin: - """Mixin to add created datetime to model""" + """Mixin to add created datetime to model.""" created_utc = Column(DateTime(timezone=True), default=lambda: datetime.utcnow()) class SiteSQL(Base, CreatedMixin): - """ - Class representing the sites table. + """Class representing the sites table. Each site row specifies a single panel or cluster of panels found on a residential house or commercial building. Their @@ -64,8 +62,7 @@ class SiteSQL(Base, CreatedMixin): class GenerationSQL(Base, CreatedMixin): - """ - Class representing the generation table. + """Class representing the generation table. Each generation row specifies a generated power output over a given time range for a site. @@ -94,8 +91,7 @@ class GenerationSQL(Base, CreatedMixin): class ForecastSQL(Base, CreatedMixin): - """ - Class representing the forecasts table. + """Class representing the forecasts table. Each forecast row refers to a sequence of predicted solar generation values over a set of target times for a site. @@ -118,8 +114,7 @@ class ForecastSQL(Base, CreatedMixin): class ForecastValueSQL(Base, CreatedMixin): - """ - Class representing the forecast_values table. + """Class representing the forecast_values table. Each forecast_value row is a prediction for the power output of a site over a target datetime interval. Many predictions @@ -151,8 +146,7 @@ class ForecastValueSQL(Base, CreatedMixin): class LatestForecastValueSQL(Base, CreatedMixin): - """ - Class representing the latest_forecast_values table. + """Class representing the latest_forecast_values table. Each latest_forecast_value row is a prediction for the power output of a site over a target datetime interval. Only the most recent @@ -188,8 +182,7 @@ class LatestForecastValueSQL(Base, CreatedMixin): class ClientSQL(Base, CreatedMixin): - """ - Class representing the clients table. + """Class representing the clients table. Each client row defines a provider of site data @@ -206,8 +199,7 @@ class ClientSQL(Base, CreatedMixin): class DatetimeIntervalSQL(Base, CreatedMixin): - """ - Class representing the datetime_intervals table. + """Class representing the datetime_intervals table. Each datetime_interval row defines a timespan between a start and end time @@ -227,8 +219,7 @@ class DatetimeIntervalSQL(Base, CreatedMixin): class StatusSQL(Base, CreatedMixin): - """ - Class representing the status table: + """Class representing the status table. Each status row defines a message reporting on the status of the services within the nowcasting domain diff --git a/sdk/python/pvsite_datamodel/write/datetime_intervals.py b/sdk/python/pvsite_datamodel/write/datetime_intervals.py index eaf0fd5..557ef68 100644 --- a/sdk/python/pvsite_datamodel/write/datetime_intervals.py +++ b/sdk/python/pvsite_datamodel/write/datetime_intervals.py @@ -1,21 +1,19 @@ -""" -Functions for wiritng datetime intervals -""" +"""Functions for wiritng datetime intervals.""" import datetime as dt import uuid +from sqlalchemy import orm as sa_orm + from pvsite_datamodel.sqlmodels import DatetimeIntervalSQL from pvsite_datamodel.write.upsert import upsert from pvsite_datamodel.write.utils import FORECAST_TIMESPAN, WrittenRow -from sqlalchemy import orm as sa_orm def get_or_else_create_datetime_interval( session: sa_orm.Session, start_time: dt.datetime, end_time: dt.datetime | None = None ) -> tuple[DatetimeIntervalSQL, list[WrittenRow]]: - """ - Gets a DatetimeInterval from the DB by start time if it exists, otherwise it creates a new entry + """Gets/creates a DatetimeInterval from the DB depending on existence. :param session: The SQLAlchemy session used for performing db updates :param start_time: The start time of the datetime interval @@ -25,7 +23,6 @@ def get_or_else_create_datetime_interval( or created DatetimeIntervalSQL object, and a list of WrittenRow objects dictating what was written to the DB """ - # End time defaults to the start time + FORECAST_TIMESPAN timedelta if end_time is None: end_time = start_time + FORECAST_TIMESPAN diff --git a/sdk/python/pvsite_datamodel/write/forecast.py b/sdk/python/pvsite_datamodel/write/forecast.py index 549d1c9..64c4282 100644 --- a/sdk/python/pvsite_datamodel/write/forecast.py +++ b/sdk/python/pvsite_datamodel/write/forecast.py @@ -1,6 +1,4 @@ -""" -Functions for writing to pvsite db -""" +"""Functions for writing to pvsite db.""" import datetime as dt import logging @@ -10,6 +8,7 @@ import numpy.typing as npt import pandas as pd import sqlalchemy.orm as sa_orm + from pvsite_datamodel.read.site import get_site_by_uuid from pvsite_datamodel.sqlmodels import ForecastSQL, ForecastValueSQL from pvsite_datamodel.write.datetime_intervals import get_or_else_create_datetime_interval @@ -20,8 +19,7 @@ def insert_forecast_values( session: sa_orm.Session, df_forecast_values: pd.DataFrame, forecast_version: str = "0.0.0" ) -> list[WrittenRow]: - """ - Inserts a dataframe of forecast values into the database. + """Insert a dataframe of forecast values into the database. :param session: sqlalchemy session for interacting with the database :param df_forecast_values: pandas dataframe with columns @@ -29,7 +27,6 @@ def insert_forecast_values( :param forecast_version: the version of the model used to create the forecast :return list[WrittenRow]: list of added rows to DB """ - # Track rows added to DB written_rows: list[WrittenRow] = [] diff --git a/sdk/python/pvsite_datamodel/write/generation.py b/sdk/python/pvsite_datamodel/write/generation.py index 6cfa2ec..d64c4cb 100644 --- a/sdk/python/pvsite_datamodel/write/generation.py +++ b/sdk/python/pvsite_datamodel/write/generation.py @@ -1,6 +1,4 @@ -""" -Functions for writing to pvsite db -""" +"""Functions for writing to pvsite db.""" import datetime as dt import logging import uuid @@ -8,6 +6,7 @@ import numpy.typing as npt import pandas as pd import sqlalchemy.orm as sa_orm + from pvsite_datamodel.read.site import get_site_by_uuid from pvsite_datamodel.sqlmodels import GenerationSQL @@ -21,15 +20,13 @@ def insert_generation_values( session: sa_orm.Session, generation_values_df: pd.DataFrame, ) -> list[WrittenRow]: - """ - Inserts a dataframe of forecast values into the database. + """Insert a dataframe of forecast values into the database. :param session: sqlalchemy session for interacting with the database :param generation_values_df: pandas dataframe with columns ["start_datetime_utc", "power_kw", "pv_uuid"] :return list[WrittenRow]: list of added rows to DB """ - # Track rows added to DB written_rows: list[WrittenRow] = [] diff --git a/sdk/python/pvsite_datamodel/write/upsert.py b/sdk/python/pvsite_datamodel/write/upsert.py index 971f348..5915fdb 100644 --- a/sdk/python/pvsite_datamodel/write/upsert.py +++ b/sdk/python/pvsite_datamodel/write/upsert.py @@ -1,17 +1,15 @@ -""" -Generic DB rows writer -""" +"""Generic DB rows writer.""" import sqlalchemy as sa -from pvsite_datamodel.sqlmodels import Base -from pvsite_datamodel.write.utils import WrittenRow from sqlalchemy import orm as sa_orm from sqlalchemy.dialects import postgresql as sa_psql +from pvsite_datamodel.sqlmodels import Base +from pvsite_datamodel.write.utils import WrittenRow + def upsert(session: sa_orm.Session, table: Base, rows: list[dict]) -> list[WrittenRow]: - """ - Upsert rows into table + """Upserts rows into table. This functions checks the primary keys, and if present, updates the row. :param session: sqlalchemy Session @@ -21,7 +19,6 @@ def upsert(session: sa_orm.Session, table: Base, rows: list[dict]) -> list[Writt key values that have been written """ - # Input type validation in case user passes in a dict, not a list of dicts if type(rows) != list: if type(rows) == dict: diff --git a/sdk/python/pvsite_datamodel/write/utils.py b/sdk/python/pvsite_datamodel/write/utils.py index a1b971a..99e5dff 100644 --- a/sdk/python/pvsite_datamodel/write/utils.py +++ b/sdk/python/pvsite_datamodel/write/utils.py @@ -1,6 +1,4 @@ -""" -Cross-package functions -""" +"""Cross-package functions.""" import datetime as dt import typing @@ -9,9 +7,7 @@ class WrittenRow(typing.NamedTuple): - """ - Defines a write to the Database - """ + """Defines a write to the Database.""" table: Base pk_value: str diff --git a/sdk/python/pyproject.toml b/sdk/python/pyproject.toml index 00b09e3..c5e5c99 100644 --- a/sdk/python/pyproject.toml +++ b/sdk/python/pyproject.toml @@ -44,6 +44,26 @@ exclude = [ "^gen/*$", # TOML basic string (double-quotes, backslash and other characters need escaping) ] +[tool.ruff] +select = [ + "E", # pycodestyle + "W", # newline at end of files + "F", # pyflakes + "N", # pep8 naming + "B", # flake8-bugbear + "I", # isosort + "D", # pydocstyle + "S", # flake8-bandit + "T20", # flake8-print + "PT" # flake8-print +] +line-length = 100 +ignore = ["D203", "D213"] +exclude = ["__init__.py"] + +[tool.ruff.per-file-ignores] +"__init__.py" = ["E402"] + [tool.pytest.ini_options] addopts = [ "--import-mode=importlib",