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

Housekeeping for 2024-W13 #809

Merged
merged 12 commits into from
Mar 29, 2024
4 changes: 1 addition & 3 deletions .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,9 @@ jobs:
# By default, the below installs ixmp from the main branch. To run against
# other code, e.g. other branches for open PRs), temporarily edit as
# appropriate. DO NOT merge such changes to `main`.
# plotnine: temporary work around for https://github.com/has2k1/plotnine/pull/751
run: |
pip install --upgrade "ixmp @ git+https://github.com/iiasa/ixmp.git@main"
pip install .[tests]
pip install "plotnine != 0.13.0"

- name: Install R dependencies and tutorial requirements
run: |
Expand Down Expand Up @@ -202,7 +200,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: # Same as the "Latest version supported by message_ix", above
python-version: "3.11"
python-version: "3.12"

- name: Force recreation of pre-commit virtual environment for mypy
if: github.event_name == 'schedule' # Comment this line to run on a PR
Expand Down
4 changes: 3 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ repos:
- asyncssh
- git+https://github.com/iiasa/ixmp.git@main
- importlib_resources
- matplotlib
- pandas-stubs
- pytest
- Sphinx
- types-PyYAML
- types-requests
args: ["."]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.2
rev: v0.3.4
hooks:
- id: ruff
- id: ruff-format
Expand Down
66 changes: 56 additions & 10 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,8 @@ The full API is also available from R; see :doc:`rmessageix`.
:show-inheritance:
:inherited-members:

This class extends :class:`ixmp.Scenario` and :class:`ixmp.TimeSeries` and
inherits all their methods. Documentation of these inherited methods is
included here for convenience. :class:`message_ix.Scenario` defines
additional methods specific to |MESSAGEix|:

.. versionchanged:: 3.0

:meth:`.read_excel` and :meth:`.to_excel` are now methods of :class:`ixmp.Scenario`, but continue to work with message_ix.Scenario.
This class extends :class:`ixmp.Scenario` and :class:`ixmp.TimeSeries` and inherits of the methods of those classes, shown below.
:class:`message_ix.Scenario` adds or overrides the following methods specific to |MESSAGEix|:

.. autosummary::

Expand All @@ -61,19 +55,71 @@ The full API is also available from R; see :doc:`rmessageix`.
add_spatial_sets
cat
cat_list
clone
equ
firstmodelyear
par
read_excel
rename
to_excel
set
solve
var
vintage_and_active_years
y0
years_active
ya
yv_ya

Inherited from :class:`.ixmp.Scenario`:

.. versionchanged:: 3.0

:meth:`.read_excel` and :meth:`.to_excel` are now methods of :class:`ixmp.Scenario`, but continue to work with message_ix.Scenario.

.. autosummary::

add_par
add_set
change_scalar
has_item
has_solution
idx_names
idx_sets
init_item
init_scalar
items
list_items
load_scenario_data
read_excel
remove_par
remove_set
remove_solution
scalar
to_excel

Inherited from :class:`.ixmp.TimeSeries`:

.. autosummary::

add_geodata
add_timeseries
check_out
commit
discard_changes
get_geodata
get_meta
is_default
last_update
preload_timeseries
read_file
remove_geodata
remove_timeseries
run_id
set_as_default
set_meta
timeseries
transact
url

.. automethod:: add_macro

.. warning:: MACRO support via :meth:`add_macro` is **experimental** in message_ix 3.0 and may not function as expected on all possible |MESSAGEix| models.
Expand Down
80 changes: 43 additions & 37 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,9 @@
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

import re
from importlib.metadata import version as get_version
from pathlib import Path
from typing import TYPE_CHECKING, Optional

if TYPE_CHECKING:
import sphinx
from typing import Optional

# -- Project information ---------------------------------------------------------------

Expand All @@ -28,6 +24,7 @@
# Add any Sphinx extension module names here, as strings. They can be extensions coming
# with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
# First-party
"sphinx.ext.autodoc",
"sphinx.ext.doctest",
"sphinx.ext.extlinks",
Expand All @@ -38,6 +35,8 @@
"sphinxcontrib.bibtex",
"sphinx.ext.autosummary",
"sphinx.ext.napoleon",
# Others
"genno.compat.sphinx.rewrite_refs",
"ixmp.util.sphinx_linkcode_github",
"message_ix.util.sphinx_gams",
]
Expand Down Expand Up @@ -66,30 +65,9 @@
.. |IIASA| raw:: html

<abbr title="International Institute for Applied Systems Analysis">IIASA</abbr>

.. |KeyLike| replace:: :obj:`~genno.core.key.KeyLike`
""" # noqa: E501


def setup(app: "sphinx.application.Sphinx") -> None:
"""Sphinx setup hook."""

expr = re.compile("docstring of (ixmp|genno)")

def warn_missing_reference(app: "sphinx.application.Sphinx", domain, node) -> bool:
"""Silently discard unresolved references internal to upstream code.

When base classes in upstream (genno, ixmp) packages are inherited in
message_ix, Sphinx cannot properly resolve relative references within docstrings
of methods of the former.
"""
# Return True without doing anything to silently discard the warning. Anything
# else, return False to allow other Sphinx hook implementations to handle.
return expr.search(node.source or "") is not None

app.connect("warn-missing-reference", warn_missing_reference)


# -- Options for HTML output -----------------------------------------------------------

# A list of CSS files.
Expand All @@ -116,6 +94,43 @@ def warn_missing_reference(app: "sphinx.application.Sphinx", domain, node) -> bo
# The LaTeX engine to build the docs.
latex_engine = "lualatex"

# -- Options for genno.compat.sphinx.rewrite_refs --------------------------------------

# When base classes in upstream (genno, ixmp) packages are inherited in message_ix,
# Sphinx will not properly resolve relative references within docstrings of methods of
# the former. Some of these aliases are to allow Sphinx to locate the correct targets.
reference_aliases = {
# genno
"AnyQuantity": ":data:`genno.core.quantity.AnyQuantity`",
"Computer": "genno.Computer",
"Graph": "genno.core.graph.Graph",
"Operator": "genno.Operator",
"KeyLike": ":data:`genno.core.key.KeyLike`",
"iter_keys": "genno.core.key.iter_keys",
"single_key": "genno.core.key.single_key",
r"(genno\.|)Key(?=Seq|[^\w]|$)": "genno.core.key.Key",
r"(genno\.|)Quantity": "genno.core.attrseries.AttrSeries",
# ixmp
"ItemType": "ixmp.backend.ItemType",
"Platform": "ixmp.Platform",
"TimeSeries": "ixmp.TimeSeries",
#
# Many projects (including Sphinx itself!) do not have a py:module target in for the
# top-level module in objects.inv. Resolve these using :doc:`index` or similar for
# each project.
"dask$": ":std:doc:`dask:index`",
"plotnine$": ":class:`plotnine.ggplot`",
}

# -- Options for ixmp.util.sphinx_linkcode_github / sphinx.ext.linkcode ----------------

linkcode_github_repo_slug = "iiasa/message_ix"

# -- Options for message_ix.util.sphinx_gams -------------------------------------------

gams_source_dir = Path(__file__).parents[1].joinpath("message_ix", "model")
gams_target_dir = "model"

# -- Options for sphinx.ext.extlinks ---------------------------------------------------

# Link to "main" blob if a non-release version of the docs is being built; otherwise
Expand Down Expand Up @@ -159,17 +174,13 @@ def local_inv(name: str, *parts: str) -> Optional[str]:
"message_doc": ("https://docs.messageix.org/projects/global/en/latest/", None),
"pandas": ("https://pandas.pydata.org/pandas-docs/stable/", None),
"pint": ("https://pint.readthedocs.io/en/stable/", None),
"plotnine": ("https://plotnine.readthedocs.io/en/stable", None),
"plotnine": ("https://plotnine.org", None),
"pyam": ("https://pyam-iamc.readthedocs.io/en/stable/", None),
"python": ("https://docs.python.org/3/", None),
"sphinx": ("https://www.sphinx-doc.org/en/master/", None),
"xarray": ("https://xarray.pydata.org/en/stable/", None),
"xarray": ("https://docs.xarray.dev/en/stable", None),
}

# -- Options for sphinx.ext.linkcode / ixmp.util.sphinx_linkcode_github ----------------

linkcode_github_repo_slug = "iiasa/message_ix"

# -- Options for sphinx.ext.mathjax ----------------------------------------------------

# See https://github.com/iiasa/message_ix/pull/721#pullrequestreview-1497907368:
Expand Down Expand Up @@ -215,8 +226,3 @@ def local_inv(name: str, *parts: str) -> Optional[str]:
# -- Options for sphinxcontrib.bibtex --------------------------------------------------

bibtex_bibfiles = ["references.bib"]

# -- Options for message_ix.util.sphinx_gams -------------------------------------------

gams_source_dir = Path(__file__).parents[1].joinpath("message_ix", "model")
gams_target_dir = "model"
2 changes: 1 addition & 1 deletion doc/contrib/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Developing tutorials
Developers *and users* of the |MESSAGEix| framework are welcome to contribute **tutorials**, according to the following guidelines.
Per the license and CLA, tutorials will become part of the message_ix test suite and will be publicly available.

Developers **must** ensure new features (including :mod:`message_ix.tools` submodules) are fully documented.
Developers **must** ensure new features (including :py:`message_ix.tools` submodules) are fully documented.
This can be done via the API documentation (this site) and, optionally, a tutorial.
These have complementary purposes:

Expand Down
34 changes: 33 additions & 1 deletion message_ix/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import os
from functools import lru_cache, partial
from itertools import chain, product, zip_longest
from typing import Iterable, List, Mapping, Optional, Tuple, Union
from typing import Dict, Iterable, List, Mapping, Optional, Sequence, Tuple, Union
from warnings import warn

import ixmp
Expand Down Expand Up @@ -232,6 +232,38 @@ def cat(self, name, cat):
)
)

def add_par(
self,
name: str,
key_or_data: Optional[
Union[int, str, Sequence[Union[int, str]], Dict, pd.DataFrame]
] = None,
value=None,
unit: Optional[str] = None,
comment: Optional[str] = None,
) -> None:
# ixmp.Scenario.add_par() is typed as accepting only str, but this method also
# accepts int for "year"-like dimensions. Proxy the call to avoid type check
# failures.
# TODO Move this upstream, to ixmp
super().add_par(name, key_or_data, value, unit, comment) # type: ignore [arg-type]

add_par.__doc__ = ixmp.Scenario.add_par.__doc__

def add_set(
self,
name: str,
key: Union[int, str, Sequence[Union[str, int]], Dict, pd.DataFrame],
comment: Union[str, Sequence[str], None] = None,
) -> None:
# ixmp.Scenario.add_par() is typed as accepting only str, but this method also
# accepts int for "year"-like dimensions. Proxy the call to avoid type check
# failures.
# TODO Move this upstream, to ixmp
super().add_set(name, key, comment) # type: ignore [arg-type]

add_set.__doc__ = ixmp.Scenario.add_set.__doc__

def add_spatial_sets(self, data):
"""Add sets related to spatial dimensions of the model.

Expand Down
6 changes: 3 additions & 3 deletions message_ix/macro.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,13 @@ def add_structure(
scenario.add_set("cat_node", ["economy", n])

# Add sectoral set structure
scenario.add_set("sector", s.sector)
scenario.add_set("sector", sorted(s.sector))
scenario.add_set("mapping_macro_sector", mapping_macro_sector)


def bconst(
demand_ref: "DataFrame", gdp0: "Series", price_ref: "DataFrame", rho: "Series"
) -> "Series":
) -> "DataFrame":
"""Calculate production function coefficient.

This is the MACRO GAMS parameter ``prfconst``.
Expand Down Expand Up @@ -450,7 +450,7 @@ def validate_transform(
for col in cols:
if df[col].dropna().empty:
raise ValueError(f"Config data for {col!r} is empty")
return
return pd.Series()

# Validate this parameter and retrieve the index columns/dimensions
idx = _validate_data(name, df, s)
Expand Down
Loading