Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable all pycodestyle and isort rules in Ruff and fix violations #1463

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ markers = ["group2", "slow"]
target-version = "py311"
line-length = 120

[tool.ruff.lint]
select = ["E", "F", "I", "W"]
per-file-ignores = {"src/scripts/**" = ["E501", "W"]}

[tool.setuptools.packages.find]
where = ["src"]

Expand Down
1 change: 0 additions & 1 deletion src/scripts/hiv/projections_jan2023/analysis_full_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import datetime
import pickle
# import random
from pathlib import Path

from tlo import Date, Simulation, logging
Expand Down
2 changes: 1 addition & 1 deletion src/scripts/profiling/run_profiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ def run_profiling(
print(f"Writing {output_ipysession_file}", end="...", flush=True)
scale_run_session.save(output_ipysession_file)
print("done")

if write_flat_html:
output_html_file = output_dir / f"{output_name}.flat.html"
console_renderer = ConsoleRenderer(
Expand Down
6 changes: 3 additions & 3 deletions src/scripts/profiling/scale_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ def save_arguments_to_json(arguments_dict: dict, output_path: Path):
with open(output_path, "w") as f:
json.dump(
{
k: str(v) if isinstance(v, Path) else v
k: str(v) if isinstance(v, Path) else v
for k, v in arguments_dict.items()
},
f,
},
f,
indent=4
)

Expand Down
4 changes: 2 additions & 2 deletions src/scripts/task_runner/generate_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ def get_html_for_commit(commit_dir: Path) -> str:
<body>
<h1>$title</h1>
<p style="font-size: small;">
This page was generated on $generated_time. The
<a href="https://github.com/UCL/TLOmodel/actions/workflows/calibration.yaml">calibration workflow</a> runs every
This page was generated on $generated_time. The
<a href="https://github.com/UCL/TLOmodel/actions/workflows/calibration.yaml">calibration workflow</a> runs every
night on the latest new commit on the master branch. <a href="#" id="toggleIncomplete">toggle incomplete</a>
</p>
$body
Expand Down
2 changes: 1 addition & 1 deletion src/tlo/analysis/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1131,7 +1131,7 @@ def get_parameters_for_status_quo() -> Dict:
"equip_availability": "all", # <--- NB. Existing calibration is assuming all equipment is available
},
}

def get_parameters_for_standard_mode2_runs() -> Dict:
"""
Returns a dictionary of parameters and their updated values to indicate
Expand Down
6 changes: 3 additions & 3 deletions src/tlo/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def _default_value(self) -> Any:
"""
Default value for this property, which will be used to fill the respective columns
of the population dataframe, for example.

If not explicitly set, it will fall back on the ``PANDAS_TYPE_DEFAULT_TYPE_MAP``.
If a value is provided, it must:

Expand Down Expand Up @@ -386,8 +386,8 @@ def initialise_population(self, population: Population) -> None:

Modules that wish to implement this behaviour do not need to implement this method,
it will be inherited automatically. Modules that wish to perform additional steps
during the initialise_population stage should reimplement this method and call
during the initialise_population stage should reimplement this method and call

```python
super().initialise_population(population=population)
```
Expand Down
4 changes: 2 additions & 2 deletions src/tlo/logging/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ def get_dataframe_row_as_dict_for_logging(
columns: Optional[Iterable[str]] = None,
) -> dict:
"""Get row of a pandas dataframe in a format suitable for logging.

Retrieves entries for all or a subset of columns for a particular row in a dataframe
and returns a dict keyed by column name, with values NumPy or pandas extension types
which should be the same for all rows in dataframe.

:param dataframe: Population properties dataframe to get properties from.
:param row_label: Unique index label identifying row in dataframe.
:param columns: Set of column names to extract - if ``None``, the default, all
Expand Down
3 changes: 2 additions & 1 deletion src/tlo/methods/alri.py
Original file line number Diff line number Diff line change
Expand Up @@ -3040,7 +3040,8 @@ def apply(self, person_id):

assert 'fast_breathing_pneumonia' == \
self.module.get_imci_classification_based_on_symptoms(
child_is_younger_than_2_months=False, symptoms=self.sim.modules['SymptomManager'].has_what(person_id=person_id)
child_is_younger_than_2_months=False,
symptoms=self.sim.modules['SymptomManager'].has_what(person_id=person_id)
)


Expand Down
4 changes: 2 additions & 2 deletions src/tlo/methods/consumables.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,12 +267,12 @@ def _lookup_availability_of_consumables(self,

def on_simulation_end(self):
"""Do tasks at the end of the simulation.

Raise warnings and enter to log about item_codes not recognised.
"""
if len(self._not_recognised_item_codes) > 0:
not_recognised_item_codes = {
treatment_id if treatment_id is not None else "": sorted(codes)
treatment_id if treatment_id is not None else "": sorted(codes)
for treatment_id, codes in self._not_recognised_item_codes.items()
}
warnings.warn(
Expand Down
4 changes: 3 additions & 1 deletion src/tlo/methods/contraception.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@ def read_parameters(self, data_folder):
"""Import the relevant sheets from the ResourceFile (excel workbook) and declare values for other parameters
(CSV ResourceFile).
"""
workbook = pd.read_excel(Path(self.resourcefilepath) / 'contraception' / 'ResourceFile_Contraception.xlsx', sheet_name=None)
workbook = pd.read_excel(
Path(self.resourcefilepath) / 'contraception' / 'ResourceFile_Contraception.xlsx', sheet_name=None
)

# Import selected sheets from the workbook as the parameters
sheet_names = [
Expand Down
2 changes: 1 addition & 1 deletion src/tlo/methods/demography.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def __init__(self, name=None, resourcefilepath=None, equal_allocation_by_distric
),

'district_num_of_residence': Property(
Types.CATEGORICAL,
Types.CATEGORICAL,
'The district number in which the person is resident',
categories=['SET_AT_RUNTIME']
),
Expand Down
88 changes: 46 additions & 42 deletions src/tlo/methods/equipment.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,53 +12,55 @@


class Equipment:
"""This is the equipment class. It maintains a current record of the availability of equipment in the
health system. It is expected that this is instantiated by the :py:class:`~.HealthSystem` module.

The basic paradigm is that an :py:class:`~.HSI_Event` can declare equipment that is required for delivering the healthcare
service that the ``HSI_Event`` represents. The ``HSI_Event`` uses :py:meth:`HSI_event.add_equipment` to make these declarations,
with reference to the items of equipment that are defined in ``ResourceFile_EquipmentCatalogue.csv``. (These
declaration can be in the form of the descriptor or the equipment item code). These declarations can be used when
the ``HSI_Event`` is created but before it is run (in ``__init__``), or during execution of the ``HSI_Event`` (in :py:meth:`.HSI_Event.apply`).

As the ``HSI_Event`` can declare equipment that is required before it is run, the HealthSystem *can* use this to
prevent an ``HSI_Event`` running if the equipment declared is not available. Note that for equipment that is declared
whilst the ``HSI_Event`` is running, there are no checks on availability, and the ``HSI_Event`` is allowed to continue
running even if equipment is declared is not available. For this reason, the ``HSI_Event`` should declare equipment
that is *essential* for the healthcare service in its ``__init__`` method. If the logic inside the ``apply`` method
of the ``HSI_Event`` depends on the availability of equipment, then it can find the probability with which
item(s) will be available using :py:meth:`.HSI_Event.probability_equipment_available`.

The data on the availability of equipment data refers to the proportion of facilities in a district of a
particular level (i.e., the ``Facility_ID``) that do have that piece of equipment. In the model, we do not know
which actual facility the person is attending (there are many actual facilities grouped together into one
``Facility_ID`` in the model). Therefore, the determination of whether equipment is available is made
probabilistically for the ``HSI_Event`` (i.e., the probability that the actual facility being attended by the
person has the equipment is represented by the proportion of such facilities that do have that equipment). It is
assumed that the probabilities of each item being available are independent of one other (so that the
probability of all items being available is the product of the probabilities for each item). This probabilistic
determination of availability is only done _once_ for the ``HSI_Event``: i.e., if the equipment is determined to
not be available for the instance of the ``HSI_Event``, then it will remain not available if the same event is
re-scheduled / re-entered into the ``HealthSystem`` queue. This represents that if the facility that a particular
person attends for the ``HSI_Event`` does not have the equipment available, then it will still not be available on
another day.

Where data on availability is not provided for an item, the probability of availability is inferred from the
average availability of other items in that facility ID. Likewise, the probability of an item being available
at a facility ID is inferred from the average availability of that item at other facilities. If an item code is
referred in ``add_equipment`` that is not recognised (not included in :py:attr:`catalogue`), a :py:exc:`UserWarning` is issued, but
that item is then silently ignored. If a facility ID is ever referred that is not recognised (not included in
:py:attr:`master_facilities_list`), an :py:exc:`AssertionError` is raised.
"""
This is the equipment class. It maintains a current record of the availability of equipment in the health system. It
is expected that this is instantiated by the :py:class:`~.HealthSystem` module.

The basic paradigm is that an :py:class:`~.HSI_Event` can declare equipment that is required for delivering the
healthcare service that the ``HSI_Event`` represents. The ``HSI_Event`` uses :py:meth:`HSI_event.add_equipment` to
make these declarations, with reference to the items of equipment that are defined in
``ResourceFile_EquipmentCatalogue.csv``. (These declaration can be in the form of the descriptor or the equipment
item code). These declarations can be used when the ``HSI_Event`` is created but before it is run (in ``__init__``),
or during execution of the ``HSI_Event`` (in :py:meth:`.HSI_Event.apply`).

As the ``HSI_Event`` can declare equipment that is required before it is run, the HealthSystem *can* use this to
prevent an ``HSI_Event`` running if the equipment declared is not available. Note that for equipment that is
declared whilst the ``HSI_Event`` is running, there are no checks on availability, and the ``HSI_Event`` is allowed
to continue running even if equipment is declared is not available. For this reason, the ``HSI_Event`` should
declare equipment that is *essential* for the healthcare service in its ``__init__`` method. If the logic inside the
``apply`` method of the ``HSI_Event`` depends on the availability of equipment, then it can find the probability
with which item(s) will be available using :py:meth:`.HSI_Event.probability_equipment_available`.

The data on the availability of equipment data refers to the proportion of facilities in a district of a particular
level (i.e., the ``Facility_ID``) that do have that piece of equipment. In the model, we do not know which actual
facility the person is attending (there are many actual facilities grouped together into one ``Facility_ID`` in the
model). Therefore, the determination of whether equipment is available is made probabilistically for the
``HSI_Event`` (i.e., the probability that the actual facility being attended by the person has the equipment is
represented by the proportion of such facilities that do have that equipment). It is assumed that the probabilities
of each item being available are independent of one other (so that the probability of all items being available is
the product of the probabilities for each item). This probabilistic determination of availability is only done
_once_ for the ``HSI_Event``: i.e., if the equipment is determined to not be available for the instance of the
``HSI_Event``, then it will remain not available if the same event is re-scheduled / re-entered into the
``HealthSystem`` queue. This represents that if the facility that a particular person attends for the ``HSI_Event``
does not have the equipment available, then it will still not be available on another day.

Where data on availability is not provided for an item, the probability of availability is inferred from the average
availability of other items in that facility ID. Likewise, the probability of an item being available at a facility
ID is inferred from the average availability of that item at other facilities. If an item code is referred in
``add_equipment`` that is not recognised (not included in :py:attr:`catalogue`), a :py:exc:`UserWarning` is issued,
but that item is then silently ignored. If a facility ID is ever referred that is not recognised (not included in
:py:attr:`master_facilities_list`), an :py:exc:`AssertionError` is raised.

:param catalogue: The database of all recognised item_codes.
:param data_availability: Specifies the probability with which each equipment (identified by an ``item_code``) is
available at a facility level. Note that information must be provided for every item in the :py:attr`catalogue`
and every facility ID in the :py:attr`master_facilities_list`.
:param: rng: The random number generator object to use for random numbers.
:param availability: Determines the mode availability of the equipment. If 'default' then use the availability
specified in :py:attr:`data_availability`; if 'none', then let no equipment be ever be available; if 'all', then all
equipment is always available.
:param master_facilities_list: The :py:class:`~pandas.DataFrame` with the line-list of all the facilities in the health system.
specified in :py:attr:`data_availability`; if 'none', then let no equipment be ever be available; if 'all', then
all equipment is always available.
:param master_facilities_list: The :py:class:`~pandas.DataFrame` with the line-list of all the facilities in the
health system.
"""

def __init__(
Expand Down Expand Up @@ -90,7 +92,6 @@ def __init__(
# {facility_id: {item_code: count}}.
self._record_of_equipment_used_by_facility_id = defaultdict(Counter)


def on_simulation_end(self):
"""Things to do when the simulation ends:
* Log (to the summary logger) the equipment that has been used.
Expand All @@ -117,7 +118,10 @@ def _get_equipment_availability_probabilities(self) -> pd.Series:
calculation if the equipment availability change event occurs during the simulation.
"""
dat = self.data_availability.set_index(
[self.data_availability["Facility_ID"].astype(np.int64), self.data_availability["Item_Code"].astype(np.int64)]
[
self.data_availability["Facility_ID"].astype(np.int64),
self.data_availability["Item_Code"].astype(np.int64),
]
)["Pr_Available"]

# Confirm that there is an estimate for every item_code at every facility_id
Expand Down
27 changes: 20 additions & 7 deletions src/tlo/methods/hiv.py
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tdm32 Have you got any active branches that update src/tlo/methods/hiv.py that the below changes (reformatting lines to make them conform with 120 character line length limit) might conflict with? If so we can hold off merging this until those changes are in to master and then update here.

Original file line number Diff line number Diff line change
Expand Up @@ -1121,10 +1121,14 @@ def update_parameters_for_program_scaleup(self):
# prep poll for AGYW - target to the highest risk
# increase retention to 75% for FSW and AGYW
p["prob_prep_for_agyw"] = scaled_params["prob_prep_for_agyw"]
p["probability_of_being_retained_on_prep_every_3_months"] = scaled_params["probability_of_being_retained_on_prep_every_3_months"]
p["probability_of_being_retained_on_prep_every_3_months"] = scaled_params[
"probability_of_being_retained_on_prep_every_3_months"
]

# perfect retention on ART
p["probability_of_being_retained_on_art_every_3_months"] = scaled_params["probability_of_being_retained_on_art_every_3_months"]
p["probability_of_being_retained_on_art_every_3_months"] = scaled_params[
"probability_of_being_retained_on_art_every_3_months"
]

# increase probability of VMMC after hiv test
p["prob_circ_after_hiv_test"] = scaled_params["prob_circ_after_hiv_test"]
Expand Down Expand Up @@ -2899,11 +2903,20 @@ def get_drugs(self, age_of_person):
if age_of_person < p["ART_age_cutoff_young_child"]:
# Formulation for young children
drugs_available = self.get_consumables(
item_codes={self.module.item_codes_for_consumables_required[
'First line ART regimen: young child']: dispensation_days * 2},
optional_item_codes={self.module.item_codes_for_consumables_required[
'First line ART regimen: young child: cotrimoxazole']: dispensation_days * 240},
return_individual_results=True)
item_codes={
self.module.item_codes_for_consumables_required[
"First line ART regimen: young child"
]: dispensation_days
* 2
},
optional_item_codes={
self.module.item_codes_for_consumables_required[
"First line ART regimen: young child: cotrimoxazole"
]: dispensation_days
* 240
},
return_individual_results=True,
)

elif age_of_person <= p["ART_age_cutoff_older_child"]:
# Formulation for older children
Expand Down
8 changes: 4 additions & 4 deletions src/tlo/methods/hsi_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,10 +289,10 @@ def is_all_declared_equipment_available(self) -> bool:
"""Returns ``True`` if all the (currently) declared items of equipment are available. This is called by the
``HealthSystem`` module before the HSI is run and so is looking only at those items that are declared when this
instance was created. The evaluation of whether equipment is available is only done *once* for this instance of
the event: i.e., if the equipment is not available for the instance of this ``HSI_Event``, then it will remain not
available if the same event is re-scheduled/re-entered into the HealthSystem queue. This is representing that
if the facility that a particular person attends for the ``HSI_Event`` does not have the equipment available, then
it will also not be available on another day."""
the event: i.e., if the equipment is not available for the instance of this ``HSI_Event``, then it will remain
not available if the same event is re-scheduled/re-entered into the HealthSystem queue. This is representing
that if the facility that a particular person attends for the ``HSI_Event`` does not have the equipment
available, then it will also not be available on another day."""

if self._is_all_declared_equipment_available is None:
# Availability has not already been evaluated: determine availability
Expand Down
Loading