From 5803f23ca8c406166724efe2f8f9eedcd2ccc93e Mon Sep 17 00:00:00 2001 From: Samuel Letellier-Duchesne Date: Fri, 25 Oct 2024 15:48:42 -0400 Subject: [PATCH] code satisfies A rules (#518) * fir TRY rules * allow pytest as function in tox * fixes an issue where p is not initialized * fix tests * fix UP rules * fix typing union on py39 * fix E rules * fix * fix SIM rules * fix C4 rules * fix A rules * fix typing * fix type to format change --- archetypal/dataportal.py | 20 ++++--- archetypal/eplus_interface/energy_plus.py | 2 +- archetypal/eplus_interface/transition.py | 8 +-- archetypal/eplus_interface/version.py | 2 +- archetypal/idfclass/outputs.py | 9 ++-- archetypal/reportdata.py | 14 ++--- archetypal/schedule.py | 4 +- archetypal/simple_glazing.py | 64 +++++++++++------------ archetypal/template/conditioning.py | 48 ++++++++--------- archetypal/template/schedule.py | 6 +-- archetypal/template/umi_base.py | 8 +-- archetypal/umi_template.py | 2 +- docs/conf.py | 4 +- pyproject.toml | 2 +- tests/test_dataportals.py | 8 +-- 15 files changed, 99 insertions(+), 102 deletions(-) diff --git a/archetypal/dataportal.py b/archetypal/dataportal.py index 063a87db..f769176f 100644 --- a/archetypal/dataportal.py +++ b/archetypal/dataportal.py @@ -530,12 +530,11 @@ def nrel_bcl_api_request(data): return response_json -def stat_can_request(type, lang="E", dguid="2016A000011124", topic=0, notes=0, stat=0): - """Send a request to the StatCan API via HTTP GET and return the JSON - response. +def stat_can_request(response_format, lang="E", dguid="2016A000011124", topic=0, notes=0, stat=0): + """Send a request to the StatCan API via HTTP GET and return the JSON response. Args: - type (str): "json" or "xml". json = json response format and xml = xml + response_format (str): "json" or "xml". json = json response format and xml = xml response format. lang (str): "E" or "F". E = English and F = French. dguid (str): Dissemination Geography Unique Identifier - DGUID. It is an @@ -560,7 +559,7 @@ def stat_can_request(type, lang="E", dguid="2016A000011124", topic=0, notes=0, s """ prepared_url = ( "https://www12.statcan.gc.ca/rest/census-recensement" - f"/CPR2016.{type}?lang={lang}&dguid={dguid}&topic=" + f"/CPR2016.{response_format}?lang={lang}&dguid={dguid}&topic=" f"{topic}¬es={notes}&stat={stat}" ) @@ -612,10 +611,11 @@ def stat_can_request(type, lang="E", dguid="2016A000011124", topic=0, notes=0, s return response_json -def stat_can_geo_request(type="json", lang="E", geos="PR", cpt="00"): - """ +def stat_can_geo_request(response_format="json", lang="E", geos="PR", cpt="00"): + """Send a request to the StatCan API via HTTP GET and return the JSON response. + Args: - type (str): "json" or "xml". json = json response format and xml = xml + response_format (str): "json" or "xml". json = json response format and xml = xml response format. lang (str): "E" or "F". where: E = English F = French. geos (str): one geographic level code (default = PR). where: CD = Census @@ -632,9 +632,7 @@ def stat_can_geo_request(type="json", lang="E", geos="PR", cpt="00"): 35 = Ontario 46 = Manitoba 47 = Saskatchewan 48 = Alberta 59 = British Columbia 60 = Yukon 61 = Northwest Territories 62 = Nunavut. """ - prepared_url = ( - f"https://www12.statcan.gc.ca/rest/census-recensement/CR2016Geo.{type}?lang={lang}&geos={geos}&cpt={cpt}" - ) + prepared_url = f"https://www12.statcan.gc.ca/rest/census-recensement/CR2016Geo.{response_format}?lang={lang}&geos={geos}&cpt={cpt}" cached_response_json = get_from_cache(prepared_url) diff --git a/archetypal/eplus_interface/energy_plus.py b/archetypal/eplus_interface/energy_plus.py index c1714daa..5b77e15d 100644 --- a/archetypal/eplus_interface/energy_plus.py +++ b/archetypal/eplus_interface/energy_plus.py @@ -45,7 +45,7 @@ def __init__( annual=False, convert=False, design_day=False, - help=False, + help=False, # noqa: A002 idd=None, epmacro=False, output_prefix="eplus", diff --git a/archetypal/eplus_interface/transition.py b/archetypal/eplus_interface/transition.py index 9207e144..ca917a42 100644 --- a/archetypal/eplus_interface/transition.py +++ b/archetypal/eplus_interface/transition.py @@ -103,8 +103,8 @@ def copytree(src, dst, symlinks=False, ignore=None): if self._trans_exec is None: copytree(self.idf.idfversionupdater_dir, self.running_directory) self._trans_exec = { - EnergyPlusVersion(re.search(r"to-V(([\d]*?)-([\d]*?)-([\d]))", exec).group(1)): exec - for exec in self.running_directory.files("Transition-V*") + EnergyPlusVersion(re.search(r"to-V(([\d]*?)-([\d]*?)-([\d]))", execution).group(1)): execution + for execution in self.running_directory.files("Transition-V*") } return self._trans_exec @@ -239,8 +239,8 @@ def stop(self): def trans_exec(self) -> dict: """Return dict of {EnergyPlusVersion, executable} for each transitions.""" return { - EnergyPlusVersion(re.search(r"to-V(([\d]*?)-([\d]*?)-([\d]))", exec).group(1)): exec - for exec in self.idf.idfversionupdater_dir.files("Transition-V*") + EnergyPlusVersion(re.search(r"to-V(([\d]*?)-([\d]*?)-([\d]))", execution).group(1)): execution + for execution in self.idf.idfversionupdater_dir.files("Transition-V*") } @property diff --git a/archetypal/eplus_interface/version.py b/archetypal/eplus_interface/version.py index 5df5d20b..e23f88e3 100644 --- a/archetypal/eplus_interface/version.py +++ b/archetypal/eplus_interface/version.py @@ -113,7 +113,7 @@ def current_install_dir(self): raise EnergyPlusVersionError(f"EnergyPlusVersion {self.dash} is not installed.") from e @property - def tuple(self) -> tuple: + def tuple(self) -> tuple: # noqa: A003 """Return the version number as a tuple: (major, minor, micro).""" return self.major, self.minor, self.micro diff --git a/archetypal/idfclass/outputs.py b/archetypal/idfclass/outputs.py index 5d44435c..1d27cbf1 100644 --- a/archetypal/idfclass/outputs.py +++ b/archetypal/idfclass/outputs.py @@ -1,4 +1,7 @@ +from __future__ import annotations + from collections.abc import Iterable +from typing import Literal from archetypal.idfclass.end_use_balance import EndUseBalance from archetypal.idfclass.extensions import get_name_attribute @@ -294,7 +297,7 @@ def add_schedules(self): self._other_outputs.append(output) return self - def add_meter_variables(self, format="IDF"): + def add_meter_variables(self, key_field: Literal["IDF", "regular"] = "IDF"): """Generate .mdd file at end of simulation. This file (from the Output:VariableDictionary, regular; and Output:VariableDictionary, IDF; commands) shows all the report meters along with their “availability” @@ -304,12 +307,12 @@ def add_meter_variables(self, format="IDF"): Output Reference) and IDF (ready to be copied and pasted into your Input File). Args: - format (str): Choices are "IDF" and "regul + key_field (str): Choices are IDF, regular Returns: Outputs: self """ - outputs = [{"key": "Output:VariableDictionary".upper(), "Key_Field": format}] + outputs = [{"key": "Output:VariableDictionary".upper(), "Key_Field": key_field}] for output in outputs: self._other_outputs.append(output) return self diff --git a/archetypal/reportdata.py b/archetypal/reportdata.py index 2cabb708..9e411f28 100644 --- a/archetypal/reportdata.py +++ b/archetypal/reportdata.py @@ -1,5 +1,7 @@ """""" +from __future__ import annotations + import functools import time @@ -177,7 +179,7 @@ def filter_report_data( reportdatadictionaryindex=None, value=None, ismeter=None, - type=None, + report_type=None, indexgroup=None, timesteptype=None, keyvalue=None, @@ -198,7 +200,7 @@ def filter_report_data( reportdatadictionaryindex (str or tuple): value (str or tuple): ismeter (str or tuple): - type (str or tuple): + report_type (str or tuple): indexgroup (str or tuple): timesteptype (str or tuple): keyvalue (str or tuple): @@ -277,11 +279,11 @@ def filter_report_data( else self[self.ISMETER] == ismeter ) c_n.append(c_6) - if type: + if report_type: c_7 = ( - conjunction(*[self[self.TYPE] == type for type in type], logical=np.logical_or) - if isinstance(type, tuple) - else self[self.TYPE] == type + conjunction(*[self[self.TYPE] == t for t in report_type], logical=np.logical_or) + if isinstance(report_type, tuple) + else self[self.TYPE] == report_type ) c_n.append(c_7) if indexgroup: diff --git a/archetypal/schedule.py b/archetypal/schedule.py index 36b3db56..660a0252 100644 --- a/archetypal/schedule.py +++ b/archetypal/schedule.py @@ -1157,12 +1157,12 @@ def all_values(self, value): self._values = validators.iterable(value, maximum_length=8760) @property - def max(self): + def max(self): # noqa: A003 """Get the maximum value of the schedule.""" return max(self.all_values) @property - def min(self): + def min(self): # noqa: A003 """Get the minimum value of the schedule.""" return min(self.all_values) diff --git a/archetypal/simple_glazing.py b/archetypal/simple_glazing.py index fdcdbd23..d31b794a 100644 --- a/archetypal/simple_glazing.py +++ b/archetypal/simple_glazing.py @@ -55,7 +55,7 @@ def calc_simple_glazing(shgc, u_factor, visible_transmittance=None): "various resistances can be negative." ) - dict = {} + glazing = {} # Step 1. Determine glass-to-glass Resistance. @@ -110,41 +110,41 @@ def calc_simple_glazing(shgc, u_factor, visible_transmittance=None): T_vis -= (T_vis + R_vis_b - 1) * 1.1 # Last Step. Saving results to dict - dict["SolarHeatGainCoefficient"] = shgc - dict["UFactor"] = u_factor - dict["Conductivity"] = Lambda_eff - dict["Thickness"] = Thickness - dict["SolarTransmittance"] = T_sol - dict["SolarReflectanceFront"] = R_s_f - dict["SolarReflectanceBack"] = R_s_b - dict["IRTransmittance"] = 0.0 - dict["VisibleTransmittance"] = T_vis - dict["VisibleReflectanceFront"] = R_vis_f - dict["VisibleReflectanceBack"] = R_vis_b - dict["IREmissivityFront"] = 0.84 - dict["IREmissivityBack"] = 0.84 - dict["DirtFactor"] = 1.0 # Clean glass - - dict["Cost"] = 0 - dict["Density"] = 2500 - dict["EmbodiedCarbon"] = 0 - dict["EmbodiedCarbonStdDev"] = 0 - dict["EmbodiedEnergy"] = 0 - dict["EmbodiedEnergyStdDev"] = 0 - dict["Life"] = 1 - dict["SubstitutionRatePattern"] = [1.0] - dict["SubstitutionTimestep"] = 0 - dict["TransportCarbon"] = 0 - dict["TransportDistance"] = 0 - dict["TransportEnergy"] = 0 - dict["Type"] = "Uncoated" # TODO Further investigation necessary - - dict["Comments"] = ( + glazing["SolarHeatGainCoefficient"] = shgc + glazing["UFactor"] = u_factor + glazing["Conductivity"] = Lambda_eff + glazing["Thickness"] = Thickness + glazing["SolarTransmittance"] = T_sol + glazing["SolarReflectanceFront"] = R_s_f + glazing["SolarReflectanceBack"] = R_s_b + glazing["IRTransmittance"] = 0.0 + glazing["VisibleTransmittance"] = T_vis + glazing["VisibleReflectanceFront"] = R_vis_f + glazing["VisibleReflectanceBack"] = R_vis_b + glazing["IREmissivityFront"] = 0.84 + glazing["IREmissivityBack"] = 0.84 + glazing["DirtFactor"] = 1.0 # Clean glass + + glazing["Cost"] = 0 + glazing["Density"] = 2500 + glazing["EmbodiedCarbon"] = 0 + glazing["EmbodiedCarbonStdDev"] = 0 + glazing["EmbodiedEnergy"] = 0 + glazing["EmbodiedEnergyStdDev"] = 0 + glazing["Life"] = 1 + glazing["SubstitutionRatePattern"] = [1.0] + glazing["SubstitutionTimestep"] = 0 + glazing["TransportCarbon"] = 0 + glazing["TransportDistance"] = 0 + glazing["TransportEnergy"] = 0 + glazing["Type"] = "Uncoated" # TODO Further investigation necessary + + glazing["Comments"] = ( "Properties calculated from Simple Glazing System with " f"SHGC={shgc:.3f}, UFactor={u_factor:.3f} and Tvis={T_vis:.3f}" ) - return dict + return glazing # region Step 1. Determine glass-to-glass Resistance diff --git a/archetypal/template/conditioning.py b/archetypal/template/conditioning.py index 9b8b7db5..ca62800b 100644 --- a/archetypal/template/conditioning.py +++ b/archetypal/template/conditioning.py @@ -737,24 +737,18 @@ def _set_economizer(self, zone: "ZoneDefinition", zone_ep: EpBunch): controllers_in_idf = zone_ep.theidf.idfobjects["Controller:OutdoorAir".upper()] self.EconomizerType = EconomizerTypes.NoEconomizer # default value - for object in controllers_in_idf: - if object.Economizer_Control_Type == "NoEconomizer": + for obj in controllers_in_idf: + if obj.Economizer_Control_Type == "NoEconomizer": self.EconomizerType = EconomizerTypes.NoEconomizer - elif object.Economizer_Control_Type == "DifferentialEnthalphy": + elif obj.Economizer_Control_Type == "DifferentialEnthalphy": self.EconomizerType = EconomizerTypes.DifferentialEnthalphy - elif ( - object.Economizer_Control_Type == "DifferentialDryBulb" - or object.Economizer_Control_Type == "FixedDryBulb" - ): + elif obj.Economizer_Control_Type == "DifferentialDryBulb" or obj.Economizer_Control_Type == "FixedDryBulb": self.EconomizerType = EconomizerTypes.DifferentialDryBulb - elif ( - object.Economizer_Control_Type == "FixedEnthalpy" - or object.Economizer_Control_Type == "ElectronicEnthalpy" - ): + elif obj.Economizer_Control_Type == "FixedEnthalpy" or obj.Economizer_Control_Type == "ElectronicEnthalpy": self.EconomizerType = EconomizerTypes.DifferentialEnthalphy - elif object.Economizer_Control_Type == "FixedDewPointAndDryBulb": + elif obj.Economizer_Control_Type == "FixedDewPointAndDryBulb": self.EconomizerType = EconomizerTypes.DifferentialDryBulb - elif object.Economizer_Control_Type == "DifferentialDryBulbAndEnthalpy": + elif obj.Economizer_Control_Type == "DifferentialDryBulbAndEnthalpy": self.EconomizerType = EconomizerTypes.DifferentialEnthalphy def _set_mechanical_ventilation(self, zone: "ZoneDefinition", zone_ep: EpBunch): @@ -1149,13 +1143,13 @@ def _set_heat_recovery(self, zone: "ZoneDefinition", zone_ep: EpBunch): comment = "" # iterate over those objects. If the list is empty, it will simply pass. - for object in heat_recovery_in_idf: - if object.key.upper() == "HeatExchanger:AirToAir:FlatPlate".upper(): + for obj in heat_recovery_in_idf: + if obj.key.upper() == "HeatExchanger:AirToAir:FlatPlate".upper(): # Do HeatExchanger:AirToAir:FlatPlate - nsaot = object.Nominal_Supply_Air_Outlet_Temperature - nsait = object.Nominal_Supply_Air_Inlet_Temperature - n2ait = object.Nominal_Secondary_Air_Inlet_Temperature + nsaot = obj.Nominal_Supply_Air_Outlet_Temperature + nsait = obj.Nominal_Supply_Air_Inlet_Temperature + n2ait = obj.Nominal_Secondary_Air_Inlet_Temperature HeatRecoveryEfficiencySensible = (nsaot - nsait) / (n2ait - nsait) # Hypotheses: HeatRecoveryEfficiencySensible - 0.05 HeatRecoveryEfficiencyLatent = HeatRecoveryEfficiencySensible - 0.05 @@ -1167,25 +1161,25 @@ def _set_heat_recovery(self, zone: "ZoneDefinition", zone_ep: EpBunch): "Supply Air Inlet T°C)" ) - elif object.key.upper() == "HeatExchanger:AirToAir:SensibleAndLatent".upper(): + elif obj.key.upper() == "HeatExchanger:AirToAir:SensibleAndLatent".upper(): # Do HeatExchanger:AirToAir:SensibleAndLatent calculation - HeatRecoveryEfficiencyLatent = object.Latent_Effectiveness_at_100_Heating_Air_Flow - HeatRecoveryEfficiencySensible = object.Sensible_Effectiveness_at_100_Heating_Air_Flow + HeatRecoveryEfficiencyLatent = obj.Latent_Effectiveness_at_100_Heating_Air_Flow + HeatRecoveryEfficiencySensible = obj.Sensible_Effectiveness_at_100_Heating_Air_Flow HeatRecoveryType = HeatRecoveryTypes.Enthalpy - elif object.key.upper() == "HeatExchanger:Desiccant:BalancedFlow".upper(): + elif obj.key.upper() == "HeatExchanger:Desiccant:BalancedFlow".upper(): # Do HeatExchanger:Dessicant:BalancedFlow # Use default values HeatRecoveryEfficiencyLatent = 0.65 HeatRecoveryEfficiencySensible = 0.7 HeatRecoveryType = HeatRecoveryTypes.Enthalpy - elif object.key.upper() == "HeatExchanger:Desiccant:BalancedFlow:PerformanceDataType1".upper(): + elif obj.key.upper() == "HeatExchanger:Desiccant:BalancedFlow:PerformanceDataType1".upper(): # This is not an actual HeatExchanger, pass pass else: - msg = f'Heat exchanger object "{object}" is not ' "implemented" + msg = f'Heat exchanger object "{obj}" is not ' "implemented" raise NotImplementedError(msg) self.HeatRecoveryEfficiencyLatent = HeatRecoveryEfficiencyLatent @@ -1194,7 +1188,7 @@ def _set_heat_recovery(self, zone: "ZoneDefinition", zone_ep: EpBunch): self.Comments += comment @staticmethod - def _get_recoverty_effectiveness(object, zone, zone_ep): + def _get_recoverty_effectiveness(obj, zone, zone_ep): rd = ReportData.from_sql_dict(zone_ep.theidf.sql()) effectiveness = ( rd.filter_report_data( @@ -1208,8 +1202,8 @@ def _get_recoverty_effectiveness(object, zone, zone_ep): .Value.mean() .unstack(level=-1) ) - HeatRecoveryEfficiencySensible = effectiveness.loc[object.Name.upper(), "Heat Exchanger Sensible Effectiveness"] - HeatRecoveryEfficiencyLatent = effectiveness.loc[object.Name.upper(), "Heat Exchanger Latent Effectiveness"] + HeatRecoveryEfficiencySensible = effectiveness.loc[obj.Name.upper(), "Heat Exchanger Sensible Effectiveness"] + HeatRecoveryEfficiencyLatent = effectiveness.loc[obj.Name.upper(), "Heat Exchanger Latent Effectiveness"] return HeatRecoveryEfficiencyLatent, HeatRecoveryEfficiencySensible @staticmethod diff --git a/archetypal/template/schedule.py b/archetypal/template/schedule.py index 7c392c0a..138c6a1a 100644 --- a/archetypal/template/schedule.py +++ b/archetypal/template/schedule.py @@ -268,13 +268,13 @@ def __repr__(self): """Return a representation of self.""" name = self.Name resample = self.series.resample("D") - min = resample.min().mean() + low = resample.min().mean() mean = resample.mean().mean() - max = resample.max().mean() + high = resample.max().mean() return ( name + ": " - + f"mean daily min:{min:.2f} mean:{mean:.2f} max:{max:.2f} " + + f"mean daily min:{low:.2f} mean:{mean:.2f} max:{high:.2f} " + (f"quantity {self.quantity}" if self.quantity is not None else "") ) diff --git a/archetypal/template/umi_base.py b/archetypal/template/umi_base.py index 7f9ca090..1c995113 100644 --- a/archetypal/template/umi_base.py +++ b/archetypal/template/umi_base.py @@ -101,12 +101,12 @@ def Name(self, value): self._name = validators.string(value, coerce_value=True) @property - def id(self): + def id(self): # noqa: A003 """Get or set the id.""" return self._id @id.setter - def id(self, value): + def id(self, value): # noqa: A003 if value is None: value = id(self) self._id = validators.string(value, coerce_value=True) @@ -353,9 +353,9 @@ def extend(self, other, allow_duplicates): if other is None: return self self._CREATED_OBJECTS.remove(self) - id = self.id + uid = self.id new_obj = self.combine(other, allow_duplicates=allow_duplicates) - new_obj.id = id + new_obj.id = uid for key in self.mapping(validate=False): setattr(self, key, getattr(new_obj, key)) return self diff --git a/archetypal/umi_template.py b/archetypal/umi_template.py index cb58edef..b83e1e9d 100644 --- a/archetypal/umi_template.py +++ b/archetypal/umi_template.py @@ -317,7 +317,7 @@ def template_complexity_reduction(idfname, epw, **kwargs): return BuildingTemplate.from_idf(idf, **kwargs) @classmethod - def open(cls, filename): + def open(cls, filename): # noqa: A003 """Initialize an UmiTemplate object from an UMI Template Library File. Args: diff --git a/docs/conf.py b/docs/conf.py index 7b27fe52..ee00cc4c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -24,7 +24,7 @@ # -- Project information ----------------------------------------------------- project = "archetypal" -copyright = f"{datetime.datetime.now().year}, Samuel Letellier-Duchesne" +legal = f"{datetime.datetime.now().year}, Samuel Letellier-Duchesne" author = "Samuel Letellier-Duchesne" # The full version, including alpha/beta/rc tags @@ -193,7 +193,7 @@ def setup(app): epub_title = project epub_author = author epub_publisher = author -epub_copyright = copyright +epub_copyright = legal # The unique identifier of the text. This can be a ISBN number # or the project homepage. diff --git a/pyproject.toml b/pyproject.toml index 5ce1862c..b5ecd0be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,7 @@ select = [ # flake8-bugbear # "B", # flake8-builtins - # "A", + "A", # flake8-comprehensions "C4", # flake8-debugger diff --git a/tests/test_dataportals.py b/tests/test_dataportals.py index 3549b2db..c5facb06 100644 --- a/tests/test_dataportals.py +++ b/tests/test_dataportals.py @@ -220,7 +220,7 @@ def test_download_and_load_bld_window(config): def test_statcan(config): - data = {"type": "json", "lang": "E", "dguid": "2016A000011124", "topic": 5, "notes": 0} + data = {"response_format": "json", "lang": "E", "dguid": "2016A000011124", "topic": 5, "notes": 0} response = dataportal.stat_can_request(**data) print(response) @@ -230,7 +230,7 @@ def test_statcan(config): def test_statcan_error(config): # Tests statcan with error in inputs - data = {"type": "json", "lang": "E", "dguid": "wrong_string", "topic": 5, "notes": 0} + data = {"response_format": "json", "lang": "E", "dguid": "wrong_string", "topic": 5, "notes": 0} response = dataportal.stat_can_request(**data) print(response) @@ -239,7 +239,7 @@ def test_statcan_error(config): def test_statcan_geo(config): - data = {"type": "json", "lang": "E", "geos": "PR", "cpt": "00"} + data = {"response_format": "json", "lang": "E", "geos": "PR", "cpt": "00"} response = dataportal.stat_can_geo_request(**data) print(response) @@ -249,7 +249,7 @@ def test_statcan_geo(config): def test_statcan_geo_error(config): # Tests statcan_geo with error in inputs - data = {"type": "json", "lang": "E", "geos": "wrong_string", "cpt": "00"} + data = {"response_format": "json", "lang": "E", "geos": "wrong_string", "cpt": "00"} response = dataportal.stat_can_geo_request(**data) print(response)