Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-arviz-base for 
openSUSE:Factory checked in at 2026-08-22 21:35:17
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-arviz-base (Old)
 and      /work/SRC/openSUSE:Factory/.python-arviz-base.new.1258 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-arviz-base"

Sat Aug 22 21:35:17 2026 rev:4 rq:1372938 version:1.3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-arviz-base/python-arviz-base.changes      
2026-07-28 21:01:15.494830881 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-arviz-base.new.1258/python-arviz-base.changes
    2026-08-22 21:37:26.986021501 +0200
@@ -1,0 +2,15 @@
+Fri Aug 21 20:15:45 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 1.3.0:
+  * Update Code of Conduct
+  * Fix for numpyro lp sign
+  * Add posterior group to datatree_binary
+  * Replaces the version-named test envs with tox -e test
+  * Update docstub to 0.6 and regenerate stubs
+  * Fix post-release workflow
+  * PyData inspired fixes
+  * Close files after loading example data and update development
+    pip install instructions
+  * add pylint to arviz-base
+
+-------------------------------------------------------------------

Old:
----
  arviz_base-1.2.0.tar.gz

New:
----
  arviz_base-1.3.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-arviz-base.spec ++++++
--- /var/tmp/diff_new_pack.1mJ5Jo/_old  2026-08-22 21:37:27.786050099 +0200
+++ /var/tmp/diff_new_pack.1mJ5Jo/_new  2026-08-22 21:37:27.788050170 +0200
@@ -16,10 +16,8 @@
 #
 
 
-# Upstream supports Python 3.12+
-%define skip_python311 1
 Name:           python-arviz-base
-Version:        1.2.0
+Version:        1.3.0
 Release:        0
 Summary:        Base ArviZ features and converters
 License:        Apache-2.0

++++++ arviz_base-1.2.0.tar.gz -> arviz_base-1.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/.github/dependabot.yml 
new/arviz-base-1.3.0/.github/dependabot.yml
--- old/arviz-base-1.2.0/.github/dependabot.yml 2026-06-12 17:47:52.000000000 
+0200
+++ new/arviz-base-1.3.0/.github/dependabot.yml 2026-08-11 08:46:05.000000000 
+0200
@@ -10,3 +10,13 @@
     actions:
       patterns:
         - "*"
+- package-ecosystem: "pre-commit"
+  directory: "/"
+  schedule:
+    interval: "monthly"
+  cooldown:
+    default-days: 14
+  groups:
+    pre-commit:
+      patterns:
+        - "*"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/.github/workflows/post-release.yml 
new/arviz-base-1.3.0/.github/workflows/post-release.yml
--- old/arviz-base-1.2.0/.github/workflows/post-release.yml     2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/.github/workflows/post-release.yml     2026-08-11 
08:46:05.000000000 +0200
@@ -1,7 +1,7 @@
 name: Post-release
 on:
   release:
-    types: [published, released]
+    types: [published]
   workflow_dispatch:
 
 jobs:
@@ -9,7 +9,7 @@
     name: Update changelog
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/[email protected]
+      - uses: actions/[email protected]
         with:
           ref: main
       - uses: rhysd/changelog-from-release/action@v3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/.github/workflows/publish.yml 
new/arviz-base-1.3.0/.github/workflows/publish.yml
--- old/arviz-base-1.2.0/.github/workflows/publish.yml  2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/.github/workflows/publish.yml  2026-08-11 
08:46:05.000000000 +0200
@@ -17,7 +17,7 @@
       attestations: write
       id-token: write
     steps:
-      - uses: actions/[email protected]
+      - uses: actions/[email protected]
         with:
           fetch-depth: 0
           persist-credentials: false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/.github/workflows/test.yml 
new/arviz-base-1.3.0/.github/workflows/test.yml
--- old/arviz-base-1.2.0/.github/workflows/test.yml     2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/.github/workflows/test.yml     2026-08-11 
08:46:05.000000000 +0200
@@ -14,9 +14,9 @@
         python-version: ["3.12", "3.13", "3.14"]
       fail-fast: false
     steps:
-      - uses: actions/[email protected]
+      - uses: actions/[email protected]
       - name: Set up Python ${{ matrix.python-version }}
-        uses: actions/setup-python@v6
+        uses: actions/[email protected]
         with:
           python-version: ${{ matrix.python-version }}
       - name: Install dependencies
@@ -26,7 +26,7 @@
       - name: Test with tox
         run: SKIP=no-commit-to-branch tox
       - name: Upload coverage to Codecov
-        uses: codecov/codecov-action@v6
+        uses: codecov/codecov-action@v7
         with:
           name: Python ${{ matrix.python-version }}
           fail_ci_if_error: false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/.pre-commit-config.yaml 
new/arviz-base-1.3.0/.pre-commit-config.yaml
--- old/arviz-base-1.2.0/.pre-commit-config.yaml        2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/.pre-commit-config.yaml        2026-08-11 
08:46:05.000000000 +0200
@@ -1,6 +1,6 @@
 repos:
 - repo: https://github.com/pre-commit/pre-commit-hooks
-  rev: v5.0.0
+  rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c  # frozen: v6.0.0
   hooks:
   - id: check-added-large-files
   - id: check-toml
@@ -21,7 +21,7 @@
       stages: [manual]
 
 - repo: https://github.com/pre-commit/mirrors-mypy
-  rev: 'v1.16.1'
+  rev: '41e691678310dfd3833f7ab4e180ddb014310356'  # frozen: v2.3.0
   hooks:
     - id: mypy
       name: Check static typing
@@ -29,15 +29,28 @@
       pass_filenames: false
 
 - repo: https://github.com/astral-sh/ruff-pre-commit
-  rev: v0.11.13
+  rev: 01a675ea018f2fb714478a5ffb83fcea8374bb06  # frozen: v0.15.21
   hooks:
-    - id: ruff
+    - id: ruff-check
       args: [--fix, --exit-non-zero-on-fix]
       types: [ python ]
     - id: ruff-format
       types: [ python ]
 
 - repo: https://github.com/MarcoGorelli/madforhooks
-  rev: 0.4.1
+  rev: 543b5e414406c00edeb9e2204141713c4c8d2404  # frozen: 0.4.1
   hooks:
     - id: no-print-statements
+
+- repo: local
+  hooks:
+    - id: pylint
+      name: pylint
+      entry: pylint
+      language: system
+      types: [python]
+      args:
+        [
+          "-rn", # Only display messages
+          "-sn", # Don't display the score
+        ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/.pylintrc 
new/arviz-base-1.3.0/.pylintrc
--- old/arviz-base-1.2.0/.pylintrc      2026-06-12 17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/.pylintrc      2026-08-11 08:46:05.000000000 +0200
@@ -30,10 +30,6 @@
 # Specify a configuration file.
 #rcfile=
 
-# When enabled, pylint would attempt to guess common misconfiguration and emit
-# user-friendly hints instead of false-positive error messages
-suggestion-mode=yes
-
 # Allow loading of arbitrary C extensions. Extensions are imported into the
 # active Python interpreter and may run arbitrary code.
 unsafe-load-any-extension=no
@@ -66,6 +62,9 @@
         not-an-iterable,
         no-member,
         import-error,
+        too-many-positional-arguments,
+        possibly-used-before-assignment,
+        duplicate-code,
         fixme
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/CHANGELOG.md 
new/arviz-base-1.3.0/CHANGELOG.md
--- old/arviz-base-1.2.0/CHANGELOG.md   2026-06-12 17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/CHANGELOG.md   2026-08-11 08:46:05.000000000 +0200
@@ -1,3 +1,17 @@
+<a id="v1.2.0"></a>
+# [v1.2.0](https://github.com/arviz-devs/arviz-base/releases/tag/v1.2.0) - 
2026-06-12
+
+## What's Changed
+* Update datatree notebook by [@symeneses](https://github.com/symeneses) in 
[#188](https://github.com/arviz-devs/arviz-base/pull/188)
+* Add constant data to datatree_regression by 
[@aloctavodia](https://github.com/aloctavodia) in 
[#197](https://github.com/arviz-devs/arviz-base/pull/197)
+* prepare relase and improve import times by 
[@OriolAbril](https://github.com/OriolAbril) in 
[#201](https://github.com/arviz-devs/arviz-base/pull/201)
+
+
+**Full Changelog**: 
https://github.com/arviz-devs/arviz-base/compare/v1.1.0...v1.2.0
+
+[Changes][v1.2.0]
+
+
 <a id="v1.1.0"></a>
 # [v1.1.0](https://github.com/arviz-devs/arviz-base/releases/tag/v1.1.0) - 
2026-04-23
 
@@ -242,6 +256,7 @@
 [Changes][v0.4.0]
 
 
+[v1.2.0]: https://github.com/arviz-devs/arviz-base/compare/v1.1.0...v1.2.0
 [v1.1.0]: https://github.com/arviz-devs/arviz-base/compare/v1.0.0...v1.1.0
 [v1.0.0]: https://github.com/arviz-devs/arviz-base/compare/v0.8.2...v1.0.0
 [v0.8.2]: https://github.com/arviz-devs/arviz-base/compare/v0.8.1...v0.8.2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/CODE_OF_CONDUCT.md 
new/arviz-base-1.3.0/CODE_OF_CONDUCT.md
--- old/arviz-base-1.2.0/CODE_OF_CONDUCT.md     2026-06-12 17:47:52.000000000 
+0200
+++ new/arviz-base-1.3.0/CODE_OF_CONDUCT.md     2026-08-11 08:46:05.000000000 
+0200
@@ -3,48 +3,26 @@
 ArviZ adopts the NumFOCUS Code of Conduct directly. In other words, we
 expect our community to treat others with kindness and understanding.
 
+You can find the whole document here https://numfocus.org/code-of-conduct.
 
-# THE SHORT VERSION
-Be kind to others. Do not insult or put down others.
-Behave professionally. Remember that harassment and sexist, racist,
-or exclusionary jokes are not appropriate.
-
-All communication should be appropriate for a professional audience
-including people of many different backgrounds. Sexual language and
-imagery are not appropriate.
-
-ArviZ is dedicated to providing a harassment-free community for everyone,
-regardless of gender, sexual orientation, gender identity, and
-expression, disability, physical appearance, body size, race,
-or religion. We do not tolerate harassment of community members
-in any form.
+## THE SHORT VERSION
+
+NumFOCUS is dedicated to providing a harassment-free community for everyone, 
regardless of gender, sexual orientation, gender identity and expression, 
disability, physical appearance, body size, race, or religion. We do not 
tolerate harassment of community members in any form.
+
+Be kind to others. Do not insult or put down others. Behave professionally. 
Remember that harassment and sexist, racist, or exclusionary jokes are not 
appropriate for NumFOCUS.
+
+All communication should be appropriate for a professional audience including 
people of many different backgrounds. Sexual language and imagery is not 
appropriate.
 
 Thank you for helping make this a welcoming, friendly community for all.
 
+## LONG VERSION
+You can find the long version of the Code of Conduct on the NumFOCUS website 
https://numfocus.org/code-of-conduct
+
+## HOW TO REPORT
+
+If you feel that the Code of Conduct has been violated, feel free to submit a 
report, by using the form: [NumFOCUS Code of Conduct Reporting 
Form](https://forms.monday.com/forms/f130e8cddb99568fa86cf077b8912a60?r=use1)
+
+## WHO WILL RECEIVE YOUR REPORT
+Your report will be received and handled by NumFOCUS Code of Conduct Working 
Group; trained, and experienced contributors with diverse backgrounds. The 
group is making decisions independently from the project, PyData, NumFOCUS or 
any other organization.
 
-# How to Submit a Report
-If you feel that there has been a Code of Conduct violation an anonymous
-reporting form is available.
-**If you feel your safety is in jeopardy or the situation is an
-emergency, we urge you to contact local law enforcement before making
-a report. (In the U.S., dial 911.)**
-
-We are committed to promptly addressing any reported issues.
-If you have experienced or witnessed behavior that violates this
-Code of Conduct, please complete the form below to
-make a report.
-
-**REPORTING FORM:** https://numfocus.typeform.com/to/ynjGdT
-
-Reports are sent to the NumFOCUS Code of Conduct Enforcement Team
-(see below).
-
-You can view the Privacy Policy and Terms of Service for TypeForm here.
-The NumFOCUS Privacy Policy is here:
-https://www.numfocus.org/privacy-policy
-
-
-# Full Code of Conduct
-The full text of the NumFOCUS/ArviZ Code of Conduct can be found on
-NumFOCUS's website
-https://numfocus.org/code-of-conduct
+You can learn more about the current group members, as well as the reporting 
procedure [HERE](https://numfocus.org/code-of-conduct)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/README.md 
new/arviz-base-1.3.0/README.md
--- old/arviz-base-1.2.0/README.md      2026-06-12 17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/README.md      2026-08-11 08:46:05.000000000 +0200
@@ -41,7 +41,7 @@
 The latest development version can be installed from the main branch using pip:
 
 ```
-pip install git+git://github.com/arviz-devs/arviz-base.git
+pip install git+https://github.com/arviz-devs/arviz-base.git
 ```
 
 Another option is to clone the repository and install using git and setuptools:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/external_tests/helpers.py 
new/arviz-base-1.3.0/external_tests/helpers.py
--- old/arviz-base-1.2.0/external_tests/helpers.py      2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/external_tests/helpers.py      2026-08-11 
08:46:05.000000000 +0200
@@ -109,7 +109,7 @@
         return numpyro.sample("obs", dist.Normal(theta, sigma), obs=y)
 
 
-def _numpyro_noncentered_guide(J, sigma, y=None):
+def _numpyro_noncentered_guide(J, sigma, y=None):  # pylint: 
disable=unused-argument
     import jax
     import numpyro
     import numpyro.distributions as dist
@@ -155,7 +155,7 @@
     return {"mcmc": mcmc}
 
 
-def numpyro_schools_model_svi(data, draws, chains):
+def numpyro_schools_model_svi(data, draws, chains):  # pylint: 
disable=unused-argument
     """Non-centered eight schools implementation in NumPyro."""
     from jax.random import PRNGKey
     from numpyro.infer import SVI, Trace_ELBO, init_to_sample
@@ -168,7 +168,7 @@
     return {"svi": svi, "svi_result": svi_result, "model_kwargs": data}
 
 
-def numpyro_schools_model_svi_custom_guide(data, draws, chains):
+def numpyro_schools_model_svi_custom_guide(data, draws, chains):  # pylint: 
disable=unused-argument
     """Non-centered eight schools implementation in NumPyro."""
     from jax.random import PRNGKey
     from numpyro.infer import SVI, Trace_ELBO
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/external_tests/test_cmdstanpy.py 
new/arviz-base-1.3.0/external_tests/test_cmdstanpy.py
--- old/arviz-base-1.2.0/external_tests/test_cmdstanpy.py       2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/external_tests/test_cmdstanpy.py       2026-08-11 
08:46:05.000000000 +0200
@@ -108,7 +108,8 @@
 
 class TestDataCmdStanPy:
     @pytest.fixture(scope="session")
-    def data_directory(self):
+    @classmethod
+    def data_directory(cls):
         here = os.path.dirname(os.path.abspath(__file__))
         data_directory = os.path.join(here, "saved_models", "cmdstanpy")
         if not os.path.isdir(data_directory):
@@ -117,7 +118,8 @@
         return data_directory
 
     @pytest.fixture(scope="class")
-    def filepaths(self, data_directory):
+    @classmethod
+    def filepaths(cls, data_directory):
         files = {
             "nowarmup": glob(
                 os.path.join(data_directory, 
"cmdstanpy_eight_schools_nowarmup-*_[1-4].csv")
@@ -129,7 +131,8 @@
         return files
 
     @pytest.fixture(scope="class")
-    def data(self, filepaths, data_directory, tmp_path_factory):
+    @classmethod
+    def data(cls, filepaths, tmp_path_factory):
         # Skip tests if cmdstanpy not installed
         cmdstanpy = importorskip("cmdstanpy")
         CmdStanModel = cmdstanpy.CmdStanModel  # pylint: disable=invalid-name
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/external_tests/test_emcee.py 
new/arviz-base-1.3.0/external_tests/test_emcee.py
--- old/arviz-base-1.2.0/external_tests/test_emcee.py   2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/external_tests/test_emcee.py   2026-08-11 
08:46:05.000000000 +0200
@@ -62,7 +62,8 @@
     ]
 
     @pytest.fixture(scope="class")
-    def data(self, eight_schools_params, draws, chains):
+    @classmethod
+    def data(cls, eight_schools_params, draws, chains):
         class Data:
             # chains are not used
             # emcee uses lots of walkers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/external_tests/test_numpyro.py 
new/arviz-base-1.3.0/external_tests/test_numpyro.py
--- old/arviz-base-1.2.0/external_tests/test_numpyro.py 2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/external_tests/test_numpyro.py 2026-08-11 
08:46:05.000000000 +0200
@@ -1,4 +1,4 @@
-# pylint: disable=no-member, invalid-name, redefined-outer-name
+# pylint: disable=no-member, invalid-name, redefined-outer-name, no-self-use, 
too-many-public-methods
 from collections import namedtuple
 
 import numpy as np
@@ -39,7 +39,8 @@
         scope="class",
         params=["numpyro", "numpyro_svi", "numpyro_svi_custom_guide"],
     )
-    def data(self, request, eight_schools_params, draws, chains):
+    @classmethod
+    def data(cls, request, eight_schools_params, draws, chains):
         class Data:
             model_key = request.param
             obj = load_cached_models(eight_schools_params, draws, chains, 
"numpyro")[model_key]
@@ -53,7 +54,8 @@
         return {"posterior": data.obj["mcmc"]} if "mcmc" in data.obj else 
data.obj
 
     @pytest.fixture(scope="class")
-    def predictions_params(self):
+    @classmethod
+    def predictions_params(cls):
         """Predictions data for eight schools."""
         return {
             "J": 8,
@@ -61,7 +63,8 @@
         }
 
     @pytest.fixture(scope="class")
-    def predictions_data(self, data, predictions_params):
+    @classmethod
+    def predictions_data(cls, data, predictions_params):
         """Generate predictions for predictions_params"""
         # call internal posterior to avoid group_by_chain in MCMC
         posterior_samples = data.adapter.get_samples()
@@ -600,16 +603,31 @@
                 "svi_result": svi_result,
             }
 
-        else:
-            mcmc = MCMC(NUTS(model), num_warmup=10, num_samples=10)
-            mcmc.run(PRNGKey(0))
-            return {"posterior": mcmc}
+        mcmc = MCMC(NUTS(model), num_warmup=10, num_samples=10)
+        mcmc.run(PRNGKey(0))
+        return {"posterior": mcmc}
 
     def test_from_numpyro_with_adapter(self, data):
         """Adapter can be passed directly to from_numpyro as a posterior."""
         idata = from_numpyro(posterior=data.adapter)
         assert "posterior" in idata
 
+    def test_potential_energy_sign_conversion(self):
+        """Potential energy is converted to log probability with the correct 
sign."""
+
+        def simple_model():
+            numpyro.sample("x", numpyro.distributions.Normal(0, 1))
+
+        mcmc = numpyro.infer.MCMC(numpyro.infer.NUTS(simple_model), 
num_warmup=5, num_samples=10)
+        mcmc.run(PRNGKey(0), extra_fields=["potential_energy"])
+
+        extra_fields = mcmc.get_extra_fields(group_by_chain=True)
+        inference_data = from_numpyro(mcmc)
+
+        np.testing.assert_array_equal(
+            inference_data.sample_stats["lp"].values, 
-extra_fields["potential_energy"]
+        )
+
 
 class TestNumPyroAdapters:
     """Test all NumPyro adapters to ensure they follow the same interface 
conventions."""
@@ -623,7 +641,8 @@
         ],
         ids=["mcmc", "svi", "svi_custom_guide"],
     )
-    def data(self, request, eight_schools_params, draws, chains):
+    @classmethod
+    def data(cls, request, eight_schools_params, draws, chains):
         """Fixture that provides adapter instances for all inference types."""
         model_key, expected_attrs = request.param
 
@@ -649,7 +668,7 @@
         assert data.adapter.model is not None
         assert callable(data.adapter.model)
 
-    def test_get_samples(self, data, eight_schools_params):
+    def test_get_samples(self, data):
         """All adapters must implement get_samples()."""
         samples = data.adapter.get_samples(seed=0)
         assert isinstance(samples, dict)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/external_tests/test_pystan.py 
new/arviz-base-1.3.0/external_tests/test_pystan.py
--- old/arviz-base-1.2.0/external_tests/test_pystan.py  2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/external_tests/test_pystan.py  2026-08-11 
08:46:05.000000000 +0200
@@ -1,4 +1,4 @@
-# pylint: disable=no-member, invalid-name, redefined-outer-name, 
too-many-function-args
+# pylint: disable=no-member, invalid-name, redefined-outer-name, 
too-many-function-args, no-self-use
 import importlib
 
 import numpy as np
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/pyproject.toml 
new/arviz-base-1.3.0/pyproject.toml
--- old/arviz-base-1.2.0/pyproject.toml 2026-06-12 17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/pyproject.toml 2026-08-11 08:46:05.000000000 +0200
@@ -49,13 +49,15 @@
 ]
 ci = [
     "pre-commit",
-    "cloudpickle"
+    "cloudpickle",
+    "pylint"
 ]
 check = [
     "build",
     "pre-commit",
-    "docstub==0.4",
+    "docstub==0.6",
     "mypy",
+    "pylint",
 ]
 doc = [
     "sphinx-book-theme",
@@ -91,7 +93,6 @@
     "NPY", # numpy specific rules
     "UP",  # pyupgrade
     "I",  # isort
-    "PL",  # Pylint
     "TID",  # Absolute imports
 ]
 ignore = [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/_version.py 
new/arviz-base-1.3.0/src/arviz_base/_version.py
--- old/arviz-base-1.2.0/src/arviz_base/_version.py     2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/_version.py     2026-08-11 
08:46:05.000000000 +0200
@@ -1,3 +1,3 @@
 """Base ArviZ version."""
 
-__version__ = "1.2.0"
+__version__ = "1.3.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/base.pyi 
new/arviz-base-1.3.0/src/arviz_base/base.pyi
--- old/arviz-base-1.2.0/src/arviz_base/base.pyi        2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/base.pyi        2026-08-11 
08:46:05.000000000 +0200
@@ -3,11 +3,11 @@
 import datetime
 import importlib
 import re
-import types
 import warnings
 from collections.abc import Callable, Hashable, Iterable, Mapping, Sequence
 from copy import deepcopy
 from numbers import Number
+from types import ModuleType
 from typing import TYPE_CHECKING, Any, TypeVar
 
 import numpy as np
@@ -49,7 +49,7 @@
     data: Mapping[Any, ArrayLike],
     *,
     attrs: Mapping[Any, Any] | None = ...,
-    inference_library: types.ModuleType | None = ...,
+    inference_library: ModuleType | None = ...,
     coords: dict[Any, ArrayLike] | None = ...,
     dims: dict[Hashable, Sequence[Hashable]] | None = ...,
     sample_dims: Sequence[Hashable] | None = ...,
@@ -59,7 +59,7 @@
 ) -> Dataset: ...
 def make_attrs(
     attrs: Mapping[Any, Any] | None = ...,
-    inference_library: types.ModuleType | None = ...,
+    inference_library: ModuleType | None = ...,
     sample_dims: Sequence[Hashable] | None = ...,
 ) -> dict: ...
 
@@ -69,4 +69,4 @@
         self, func: Callable[[RequiresArgTypeT], RequiresReturnTypeT]
     ) -> Callable[[RequiresArgTypeT], RequiresReturnTypeT | None]: ...
 
-def infer_stan_dtypes(stan_code) -> None: ...
+def infer_stan_dtypes(stan_code: Incomplete) -> None: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/citations.py 
new/arviz-base-1.3.0/src/arviz_base/citations.py
--- old/arviz-base-1.2.0/src/arviz_base/citations.py    2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/citations.py    2026-08-11 
08:46:05.000000000 +0200
@@ -39,12 +39,11 @@
         header = _get_header(methods)
         citation_text = _find_bibtex_entries(header, method_citations)
         if filepath:
-            with open(filepath, "w") as fw:
+            with open(filepath, "w", encoding="utf-8") as fw:
                 fw.write(citation_text)
-        else:
-            return citation_text
-    else:
-        raise ValueError("Invalid value for format_type. Use 'bibtex'.")
+            return None
+        return citation_text
+    raise ValueError("Invalid value for format_type. Use 'bibtex'.")
 
 
 def _extract_ids_per_entry(data, text):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/datasets.py 
new/arviz-base-1.3.0/src/arviz_base/datasets.py
--- old/arviz-base-1.2.0/src/arviz_base/datasets.py     2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/datasets.py     2026-08-11 
08:46:05.000000000 +0200
@@ -116,7 +116,8 @@
     """
     if dataset in LOCAL_DATASETS:
         resource = LOCAL_DATASETS[dataset]
-        return open_datatree(resource.filename, **kwargs).load()
+        with open_datatree(resource.filename, **kwargs) as dt:
+            return dt.load()
 
     if dataset in REMOTE_DATASETS:
         remote = REMOTE_DATASETS[dataset]
@@ -135,7 +136,7 @@
                     download_success = True
                 elif os.path.exists(file_path):
                     os.remove(file_path)
-            except Exception:
+            except Exception:  # pylint: disable=broad-exception-caught
                 if os.path.exists(file_path):
                     os.remove(file_path)
 
@@ -153,7 +154,8 @@
                 "Run `arviz.clear_data_home()` and try again, or please open 
an issue."
             )
 
-        return open_datatree(file_path, **kwargs).load()
+        with open_datatree(file_path, **kwargs) as dt:
+            return dt.load()
 
     if dataset is None:
         return dict(itertools.chain(LOCAL_DATASETS.items(), 
REMOTE_DATASETS.items()))
@@ -173,12 +175,11 @@
             msg = f"Did you mean one of these? {', '.join(suggestions)}"
 
         raise ValueError(f"Dataset '{dataset}' not found. {msg}")
-    else:
-        raise ValueError(
-            f"Dataset {dataset} not found! The following are available:"
-            f"\n\n{', '.join(all_datasets)}\n\n"
-            f"{list_datasets()}"
-        )
+    raise ValueError(
+        f"Dataset {dataset} not found! The following are available:"
+        f"\n\n{', '.join(all_datasets)}\n\n"
+        f"{list_datasets()}"
+    )
 
 
 def list_datasets():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/datasets.pyi 
new/arviz-base-1.3.0/src/arviz_base/datasets.pyi
--- old/arviz-base-1.2.0/src/arviz_base/datasets.pyi    2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/datasets.pyi    2026-08-11 
08:46:05.000000000 +0200
@@ -30,7 +30,7 @@
 
 def get_data_home(data_home: str | None = ...) -> None: ...
 def clear_data_home(data_home: str | None = ...) -> None: ...
-def _sha256(path) -> None: ...
+def _sha256(path: Incomplete) -> None: ...
 def load_arviz_data(
     dataset: str | None = ..., data_home: str | None = ..., **kwargs: dict
 ) -> DataTree: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/io_cmdstanpy.pyi 
new/arviz-base-1.3.0/src/arviz_base/io_cmdstanpy.pyi
--- old/arviz-base-1.2.0/src/arviz_base/io_cmdstanpy.pyi        2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/io_cmdstanpy.pyi        2026-08-11 
08:46:05.000000000 +0200
@@ -21,20 +21,20 @@
     def __init__(
         self,
         *,
-        posterior=...,
-        posterior_predictive=...,
-        predictions=...,
-        prior=...,
-        prior_predictive=...,
-        observed_data=...,
-        constant_data=...,
-        predictions_constant_data=...,
-        log_likelihood=...,
-        index_origin=...,
-        coords=...,
-        dims=...,
-        save_warmup=...,
-        dtypes=...,
+        posterior: Incomplete = ...,
+        posterior_predictive: Incomplete = ...,
+        predictions: Incomplete = ...,
+        prior: Incomplete = ...,
+        prior_predictive: Incomplete = ...,
+        observed_data: Incomplete = ...,
+        constant_data: Incomplete = ...,
+        predictions_constant_data: Incomplete = ...,
+        log_likelihood: Incomplete = ...,
+        index_origin: Incomplete = ...,
+        coords: Incomplete = ...,
+        dims: Incomplete = ...,
+        save_warmup: Incomplete = ...,
+        dtypes: Incomplete = ...,
     ) -> None: ...
     def _warmup_return_to_dict(
         self, data: Incomplete, data_warmup: Incomplete, group: Incomplete
@@ -42,10 +42,10 @@
     def posterior_to_xarray(self) -> None: ...
     def sample_stats_to_xarray(self) -> None: ...
     def sample_stats_prior_to_xarray(self) -> None: ...
-    def stats_to_xarray(self, fit) -> None: ...
+    def stats_to_xarray(self, fit: Incomplete) -> None: ...
     def posterior_predictive_to_xarray(self) -> None: ...
     def prior_predictive_to_xarray(self) -> None: ...
-    def predictive_to_xarray(self, names, fit) -> None: ...
+    def predictive_to_xarray(self, names: Incomplete, fit: Incomplete) -> 
None: ...
     def predictions_to_xarray(self) -> None: ...
     def log_likelihood_to_xarray(self) -> None: ...
     def prior_to_xarray(self) -> None: ...
@@ -54,9 +54,11 @@
     def predictions_constant_data_to_xarray(self) -> None: ...
     def to_datatree(self) -> None: ...
 
-def _as_set(spec) -> None: ...
-def _filter(names, spec) -> None: ...
-def _unpack_fit(fit, items: list, save_warmup: bool, dtypes: dict) -> dict: ...
+def _as_set(spec: Incomplete) -> None: ...
+def _filter(names: Incomplete, spec: Incomplete) -> None: ...
+def _unpack_fit(
+    fit: Incomplete, items: list, save_warmup: bool, dtypes: dict
+) -> dict: ...
 def from_cmdstanpy(
     posterior: cmdstanpy.CmdStanMCMC | None = ...,
     *,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/io_emcee.pyi 
new/arviz-base-1.3.0/src/arviz_base/io_emcee.pyi
--- old/arviz-base-1.2.0/src/arviz_base/io_emcee.pyi    2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/io_emcee.pyi    2026-08-11 
08:46:05.000000000 +0200
@@ -4,6 +4,7 @@
 
 import emcee
 import numpy as np
+from _typeshed import Incomplete
 from numpy.typing import ArrayLike
 from xarray import DataTree
 
@@ -20,17 +21,17 @@
 class EmceeConverter:
     def __init__(
         self,
-        sampler,
-        var_names=...,
-        slices=...,
-        arg_names=...,
-        arg_groups=...,
-        blob_names=...,
-        blob_groups=...,
-        index_origin=...,
-        coords=...,
-        dims=...,
-        check_conventions=...,
+        sampler: Incomplete,
+        var_names: Incomplete = ...,
+        slices: Incomplete = ...,
+        arg_names: Incomplete = ...,
+        arg_groups: Incomplete = ...,
+        blob_names: Incomplete = ...,
+        blob_groups: Incomplete = ...,
+        index_origin: Incomplete = ...,
+        coords: Incomplete = ...,
+        dims: Incomplete = ...,
+        check_conventions: Incomplete = ...,
     ) -> None: ...
     def posterior_to_xarray(self) -> None: ...
     def args_to_xarray(self) -> None: ...
@@ -45,7 +46,7 @@
     arg_groups: list[str] | None = ...,
     blob_names: list[str] | None = ...,
     blob_groups: list[str] | None = ...,
-    index_origin=...,
+    index_origin: Incomplete = ...,
     coords: dict[str, ArrayLike] | None = ...,
     dims: dict[str, list[str]] | None = ...,
     check_conventions: bool = ...,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/io_numpyro.py 
new/arviz-base-1.3.0/src/arviz_base/io_numpyro.py
--- old/arviz-base-1.2.0/src/arviz_base/io_numpyro.py   2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/io_numpyro.py   2026-08-11 
08:46:05.000000000 +0200
@@ -52,7 +52,7 @@
         self.posterior = inference_obj
         self.model = model
         self._args = model_args or tuple()
-        self._kwargs = model_kwargs or dict()
+        self._kwargs = model_kwargs or {}
         self.sample_shape = sample_shape
 
         self.prng_key_func = jax.random.PRNGKey
@@ -91,7 +91,7 @@
         """
         raise NotImplementedError
 
-    def get_sample_stats(self, **kwargs):
+    def get_sample_stats(self, **kwargs):  # pylint: disable=no-self-use, 
unused-argument
         """Get sample stats from the inference object (e.g., divergences for 
MCMC).
 
         Returns
@@ -99,7 +99,7 @@
         dict of {str: array-like}
             Dictionary of sample stats. Empty dict by default.
         """
-        return dict()
+        return {}
 
 
 class SVIAdapter(NumPyroInferenceAdapter):
@@ -161,7 +161,9 @@
             )
         # if a custom guide is provided, sample by hand
         predictive = numpyro.infer.Predictive(
-            self.posterior.guide, params=self.result_obj.params, 
num_samples=self.sample_shape[0]
+            self.posterior.guide,
+            params=self.result_obj.params,
+            num_samples=self.sample_shape[0],
         )
         samples = predictive(key, *self._args, **self._kwargs)
         return samples
@@ -254,10 +256,10 @@
     dist = numpyro.distributions
     handlers = numpyro.handlers
     init_to_sample = numpyro.infer.initialization.init_to_sample
-    PytreeTrace = numpyro.ops.pytree.PytreeTrace
+    PytreeTrace = numpyro.ops.pytree.PytreeTrace  # pylint: 
disable=invalid-name
 
     model_args = tuple() if model_args is None else model_args
-    model_kwargs = dict() if model_kwargs is None else model_kwargs
+    model_kwargs = {} if model_kwargs is None else model_kwargs
 
     def _get_dist_name(fn):
         if isinstance(fn, dist.Independent | dist.ExpandedDistribution | 
dist.MaskedDistribution):
@@ -412,10 +414,10 @@
             }
         self.observations = observations if observations else None
 
-    def _get_model_trace(self, model, model_args, model_kwargs, key):
+    def _get_model_trace(self, model, model_args, model_kwargs, key):  # 
pylint: disable=no-self-use
         """Extract the numpyro model trace."""
         model_args = model_args or tuple()
-        model_kwargs = model_kwargs or dict()
+        model_kwargs = model_kwargs or {}
 
         # we need to use an init strategy to generate random samples for 
ImproperUniform sites
         seeded_model = numpyro.handlers.substitute(
@@ -457,34 +459,32 @@
                         f"by the number of chains {self.nchains}."
                     )
                 return (self.nchains, ndraws)
-            else:
-                # Array already has chain/draw dims; optionally validate 
against nchains
-                sample_shape = aelem.shape[: len(rcParams["data.sample_dims"])]
-                if self.nchains is not None and sample_shape[0] != 
self.nchains:
-                    raise ValueError(
-                        f"Array shape {aelem.shape} implies {sample_shape[0]} 
chains, "
-                        f"but nchains={self.nchains}."
-                    )
-                return sample_shape
+            # Array already has chain/draw dims; optionally validate against 
nchains
+            sample_shape = aelem.shape[: len(rcParams["data.sample_dims"])]
+            if self.nchains is not None and sample_shape[0] != self.nchains:
+                raise ValueError(
+                    f"Array shape {aelem.shape} implies {sample_shape[0]} 
chains, "
+                    f"but nchains={self.nchains}."
+                )
+            return sample_shape
 
-        elif no_constant_data:
+        if no_constant_data:
             raise ValueError(
                 "When constructing InferenceData, must have at least one of "
                 "posterior, prior, posterior_predictive, or predictions."
             )
-        else:
-            # fallback shape when there's no inference, but there is constant 
data
-            fallback_shape = (
-                (self.nchains, 1)
-                if self.nchains is not None
-                else (1,) * len(rcParams["data.sample_dims"])
-            )
-            warnings.warn(
-                f"No posterior, prior, or predictive samples provided. "
-                f"Defaulting to sample_shape={fallback_shape}. "
-                f"This may cause unexpected behavior in downstream operations."
-            )
-            return fallback_shape
+        # fallback shape when there's no inference, but there is constant data
+        fallback_shape = (
+            (self.nchains, 1)
+            if self.nchains is not None
+            else (1,) * len(rcParams["data.sample_dims"])
+        )
+        warnings.warn(
+            f"No posterior, prior, or predictive samples provided. "
+            f"Defaulting to sample_shape={fallback_shape}. "
+            f"This may cause unexpected behavior in downstream operations."
+        )
+        return fallback_shape
 
     @requires("posterior")
     def posterior_to_xarray(self):
@@ -513,13 +513,15 @@
                 continue
             name = rename_key.get(stat, stat)
             value_cp = value.copy()
-            data[name] = value_cp
+            if stat == "potential_energy":
+                data[name] = -value_cp
+            else:
+                data[name] = value_cp
             if stat == "num_steps":
                 data["tree_depth"] = np.log2(value_cp).astype(int) + 1
-                if self.posterior._max_tree_depth is not None:
-                    data["reached_max_tree_depth"] = (
-                        data["tree_depth"] >= self.posterior._max_tree_depth
-                    )
+                max_tree_depth = self.posterior._max_tree_depth  # pylint: 
disable=protected-access
+                if max_tree_depth is not None:
+                    data["reached_max_tree_depth"] = data["tree_depth"] >= 
max_tree_depth
 
         return dict_to_dataset(
             data,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/io_numpyro.pyi 
new/arviz-base-1.3.0/src/arviz_base/io_numpyro.pyi
--- old/arviz-base-1.2.0/src/arviz_base/io_numpyro.pyi  2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/io_numpyro.pyi  2026-08-11 
08:46:05.000000000 +0200
@@ -40,7 +40,7 @@
     def get_samples(
         self, seed: int | None = ..., **kwargs: dict
     ) -> dict[str, ArrayLike]: ...
-    def get_sample_stats(self, **kwargs) -> dict[str, ArrayLike]: ...
+    def get_sample_stats(self, **kwargs: Incomplete) -> dict[str, ArrayLike]: 
...
 
 class SVIAdapter(NumPyroInferenceAdapter):
     def __init__(
@@ -97,12 +97,20 @@
         extra_event_dims: dict | None = ...,
         num_chains: int | None = ...,
     ) -> None: ...
-    def _get_model_trace(self, model, model_args, model_kwargs, key) -> None: 
...
+    def _get_model_trace(
+        self,
+        model: Incomplete,
+        model_args: Incomplete,
+        model_kwargs: Incomplete,
+        key: Incomplete,
+    ) -> None: ...
     def _infer_sample_shape(self) -> None: ...
     def posterior_to_xarray(self) -> None: ...
     def sample_stats_to_xarray(self) -> None: ...
     def log_likelihood_to_xarray(self) -> None: ...
-    def translate_posterior_predictive_dict_to_xarray(self, dct, dims) -> 
None: ...
+    def translate_posterior_predictive_dict_to_xarray(
+        self, dct: Incomplete, dims: Incomplete
+    ) -> None: ...
     def posterior_predictive_to_xarray(self) -> None: ...
     def predictions_to_xarray(self) -> None: ...
     def priors_to_xarray(self) -> None: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/io_pystan.pyi 
new/arviz-base-1.3.0/src/arviz_base/io_pystan.pyi
--- old/arviz-base-1.2.0/src/arviz_base/io_pystan.pyi   2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/io_pystan.pyi   2026-08-11 
08:46:05.000000000 +0200
@@ -25,21 +25,21 @@
     def __init__(
         self,
         *,
-        posterior=...,
-        posterior_model=...,
-        posterior_predictive=...,
-        predictions=...,
-        prior=...,
-        prior_model=...,
-        prior_predictive=...,
-        observed_data=...,
-        constant_data=...,
-        predictions_constant_data=...,
-        log_likelihood=...,
-        coords=...,
-        dims=...,
-        save_warmup=...,
-        dtypes=...,
+        posterior: Incomplete = ...,
+        posterior_model: Incomplete = ...,
+        posterior_predictive: Incomplete = ...,
+        predictions: Incomplete = ...,
+        prior: Incomplete = ...,
+        prior_model: Incomplete = ...,
+        prior_predictive: Incomplete = ...,
+        observed_data: Incomplete = ...,
+        constant_data: Incomplete = ...,
+        predictions_constant_data: Incomplete = ...,
+        log_likelihood: Incomplete = ...,
+        coords: Incomplete = ...,
+        dims: Incomplete = ...,
+        save_warmup: Incomplete = ...,
+        dtypes: Incomplete = ...,
     ) -> None: ...
     def _warmup_return_to_dict(
         self,
@@ -62,13 +62,22 @@
     def to_datatree(self) -> None: ...
 
 def get_draws(
-    fit, model=..., variables=..., ignore=..., warmup=..., dtypes=...
+    fit: Incomplete,
+    model: Incomplete = ...,
+    variables: Incomplete = ...,
+    ignore: Incomplete = ...,
+    warmup: Incomplete = ...,
+    dtypes: Incomplete = ...,
 ) -> None: ...
 def get_sample_stats(
-    fit, variables=..., ignore=..., warmup=..., dtypes=...
+    fit: Incomplete,
+    variables: Incomplete = ...,
+    ignore: Incomplete = ...,
+    warmup: Incomplete = ...,
+    dtypes: Incomplete = ...,
 ) -> None: ...
-def get_attrs(fit, model=...) -> None: ...
-def infer_dtypes(fit, model=...) -> None: ...
+def get_attrs(fit: Incomplete, model: Incomplete = ...) -> None: ...
+def infer_dtypes(fit: Incomplete, model: Incomplete = ...) -> None: ...
 def from_pystan(
     posterior: stan.fit.Fit | None = ...,
     *,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/rcparams.pyi 
new/arviz-base-1.3.0/src/arviz_base/rcparams.pyi
--- old/arviz-base-1.2.0/src/arviz_base/rcparams.pyi    2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/rcparams.pyi    2026-08-11 
08:46:05.000000000 +0200
@@ -6,10 +6,10 @@
 import pprint
 import re
 import sys
-import types
 from collections.abc import Callable, Iterable, Iterator, MutableMapping
 from importlib.util import find_spec
 from pathlib import Path
+from types import ModuleType
 from typing import Any, Literal, get_args
 
 import numpy as np
@@ -25,18 +25,21 @@
 def _make_validate_choice_regex(
     accepted_values: Iterable, accepted_values_regex: Iterable, allow_none: 
bool = ...
 ) -> Callable: ...
-def _validate_positive_int(value) -> None: ...
-def _validate_float(value) -> None: ...
-def _validate_str(value) -> None: ...
-def _validate_probability(value) -> float: ...
+def _validate_positive_int(value: Incomplete) -> None: ...
+def _validate_float(value: Incomplete) -> None: ...
+def _validate_str(value: Incomplete) -> None: ...
+def _validate_probability(value: Incomplete) -> float: ...
 def _validate_rounding(value: int | str | None) -> str | int | None: ...
-def _validate_boolean(value) -> None: ...
-def _add_none_to_validator(base_validator) -> None: ...
-def _validate_stats_module(value: str | types.ModuleType) -> str | 
types.ModuleType: ...
-def _validate_bokeh_marker(value) -> None: ...
+def _validate_boolean(value: Incomplete) -> None: ...
+def _add_none_to_validator(base_validator: Incomplete) -> None: ...
+def _validate_stats_module(value: str | ModuleType) -> str | ModuleType: ...
+def _validate_bokeh_marker(value: Incomplete) -> None: ...
 def _validate_backend(value: Incomplete) -> None: ...
 def make_iterable_validator(
-    scalar_validator, length=..., allow_none=..., allow_auto=...
+    scalar_validator: Incomplete,
+    length: Incomplete = ...,
+    allow_none: Incomplete = ...,
+    allow_auto: Incomplete = ...,
 ) -> Callable: ...
 
 _validate_float_or_none: Incomplete
@@ -49,28 +52,30 @@
 
     validate: Incomplete
 
-    def __init__(self, *args, **kwargs) -> None: ...
-    def __setitem__(self, key, val) -> None: ...
-    def __getitem__(self, key) -> None: ...
-    def __delitem__(self, key) -> None: ...
+    def __init__(self, *args: Incomplete, **kwargs: Incomplete) -> None: ...
+    def __setitem__(self, key: Incomplete, val: Incomplete) -> None: ...
+    def __getitem__(self, key: Incomplete) -> None: ...
+    def __delitem__(self, key: Incomplete) -> None: ...
     def clear(self) -> None: ...
-    def pop(self, key, default=...) -> None: ...
+    def pop(self, key: Incomplete, default: Incomplete = ...) -> None: ...
     def popitem(self) -> tuple[Any, Any]: ...
-    def setdefault(self, key, default=...) -> None: ...
+    def setdefault(self, key: Incomplete, default: Incomplete = ...) -> None: 
...
     def __repr__(self) -> str: ...
     def __str__(self) -> str: ...
     def __iter__(self) -> Iterator[Any]: ...
     def __len__(self) -> int: ...
-    def find_all(self, pattern) -> None: ...
+    def find_all(self, pattern: Incomplete) -> None: ...
     def copy(self) -> None: ...
 
 def get_arviz_rcfile() -> None: ...
-def read_rcfile(fname) -> None: ...
-def rc_params(ignore_files=...) -> None: ...
+def read_rcfile(fname: Incomplete) -> None: ...
+def rc_params(ignore_files: Incomplete = ...) -> None: ...
 
 rcParams: Incomplete
 
 class rc_context:
     def __init__(self, rc: dict | None = ..., fname: str | None = ...) -> 
None: ...
     def __enter__(self) -> None: ...
-    def __exit__(self, exc_type, exc_value, exc_tb) -> None: ...
+    def __exit__(
+        self, exc_type: Incomplete, exc_value: Incomplete, exc_tb: Incomplete
+    ) -> None: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/reorg.py 
new/arviz-base-1.3.0/src/arviz_base/reorg.py
--- old/arviz-base-1.2.0/src/arviz_base/reorg.py        2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/reorg.py        2026-08-11 
08:46:05.000000000 +0200
@@ -178,13 +178,13 @@
 
 def _stratified_resample(weights, rng):
     """Stratified resampling."""
-    N = len(weights)
-    single_uniform = (rng.random(N) + np.arange(N)) / N
-    indexes = np.zeros(N, dtype=int)
+    n = len(weights)
+    single_uniform = (rng.random(n) + np.arange(n)) / n
+    indexes = np.zeros(n, dtype=int)
     cum_sum = np.cumsum(weights)
 
     i, j = 0, 0
-    while i < N:
+    while i < n:
         if single_uniform[i] < cum_sum[j]:
             indexes[i] = j
             i += 1
@@ -377,7 +377,7 @@
     return df
 
 
-def explode_dataset_dims(ds, dim, labeller=None):
+def explode_dataset_dims(ds, dim, labeller=None, dim_to_idx=None):
     """Explode dims of a dataset so each slice along them becomes its own 
variable.
 
     Parameters
@@ -389,6 +389,7 @@
     labeller : labeller, optional
         Instance of a labeller class used to label the slices generated when 
exploding along `dim`.
         The method ``make_label_flat`` is used.
+    dim_to_idx : mapping of {str : str}, optional
 
     Returns
     -------
@@ -413,14 +414,24 @@
         dim = [dim]
     if labeller is None:
         labeller = BaseLabeller()
-    return xr.Dataset(
-        {
-            labeller.make_label_flat(var_name, sel, isel): 
ds[var_name].sel(sel, drop=True)
-            for var_name, sel, isel in xarray_sel_iter(
-                ds, skip_dims={d for d in ds.dims if d not in dim}
-            )
-        }
-    )
+    out = {}
+    for var_name, sel, isel in xarray_sel_iter(
+        ds, skip_dims={d for d in ds.dims if d not in dim}, 
dim_to_idx=dim_to_idx
+    ):
+        new_var = labeller.make_label_flat(var_name, sel, isel)
+        new_da = ds[var_name].sel(sel, drop=True)
+        present_dim_to_idx = (
+            {} if dim_to_idx is None else {k: v for k, v in dim_to_idx.items() 
if k in new_da.dims}
+        )
+        if present_dim_to_idx:
+            new_da = new_da.rename(
+                {
+                    key: f"{key}_{labeller.sel_to_str(sel, isel)}"
+                    for key in present_dim_to_idx.keys()
+                }
+            ).drop_vars(list(present_dim_to_idx.values()))
+        out[new_var] = new_da
+    return xr.Dataset(out)
 
 
 def references_to_dataset(references, ds, sample_dims=None, ref_dim=None):
@@ -432,7 +443,7 @@
 
     Parameters
     ----------
-    references : scalar or 1D array-like or dict or DataArray or Dataset
+    references : scalar or array-like or dict or DataArray or Dataset
         References to cast into a compatible dataset.
 
         * scalar inputs are interpreted as a reference line in each 
variable+coordinate not in
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/reorg.pyi 
new/arviz-base-1.3.0/src/arviz_base/reorg.pyi
--- old/arviz-base-1.2.0/src/arviz_base/reorg.pyi       2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/reorg.pyi       2026-08-11 
08:46:05.000000000 +0200
@@ -1,6 +1,6 @@
 # File generated with docstub
 
-from collections.abc import Hashable, Iterable, Sequence
+from collections.abc import Hashable, Iterable, Mapping, Sequence
 from numbers import Number
 from typing import Literal
 
@@ -8,6 +8,7 @@
 import pandas
 import pandas as pd
 import xarray as xr
+from _typeshed import Incomplete
 from numpy.typing import ArrayLike
 from xarray import DataArray, Dataset, DataTree
 
@@ -42,7 +43,7 @@
     keep_dataset: bool = ...,
     random_seed: int | None = ...,
 ) -> DataArray | Dataset: ...
-def _stratified_resample(weights, rng) -> None: ...
+def _stratified_resample(weights: Incomplete, rng: Incomplete) -> None: ...
 def dataset_to_dataarray(
     ds: Dataset,
     sample_dims: Sequence[Hashable] | None = ...,
@@ -59,7 +60,10 @@
     new_dim: Hashable = ...,
 ) -> pandas.DataFrame: ...
 def explode_dataset_dims(
-    ds: Dataset, dim: Hashable | Sequence[Hashable], labeller: Labeller | None 
= ...
+    ds: Dataset,
+    dim: Hashable | Sequence[Hashable],
+    labeller: Labeller | None = ...,
+    dim_to_idx: Mapping[str, str] | None = ...,
 ) -> Dataset: ...
 def references_to_dataset(
     references: Number | ArrayLike | dict | DataArray | Dataset,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/testing.py 
new/arviz-base-1.3.0/src/arviz_base/testing.py
--- old/arviz-base-1.2.0/src/arviz_base/testing.py      2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/testing.py      2026-08-11 
08:46:05.000000000 +0200
@@ -2,7 +2,7 @@
 
 import numpy as np
 
-from arviz_base import from_dict
+from arviz_base.io_dict import from_dict
 
 
 def generate_base_data(seed=31):
@@ -94,12 +94,14 @@
 def datatree_binary(seed=17):
     """Generate a DataTree with binary data."""
     rng = np.random.default_rng(seed)
+    posterior = rng.binomial(1, 0.5, size=(4, 100))
     posterior_predictive = rng.binomial(1, 0.5, size=(4, 100, 7))
     observed_data = rng.binomial(1, 0.5, size=7)
     log_likelihood = rng.normal(loc=0, scale=1, size=(4, 100, 7))
 
     return from_dict(
         {
+            "posterior": {"theta": posterior},
             "posterior_predictive": {"y": posterior_predictive},
             "observed_data": {"y": observed_data},
             "log_likelihood": {"y": log_likelihood},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/testing.pyi 
new/arviz-base-1.3.0/src/arviz_base/testing.pyi
--- old/arviz-base-1.2.0/src/arviz_base/testing.pyi     2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/testing.pyi     2026-08-11 
08:46:05.000000000 +0200
@@ -1,21 +1,22 @@
 # File generated with docstub
 
 import numpy as np
+from _typeshed import Incomplete
 from xarray import DataTree
 
-from arviz_base import from_dict
+from arviz_base.io_dict import from_dict
 
-def generate_base_data(seed=...) -> None: ...
-def datatree(seed=...) -> None: ...
-def datatree2(seed=...) -> None: ...
-def datatree3(seed=...) -> None: ...
-def datatree_binary(seed=...) -> None: ...
-def datatree_regression(seed=...) -> None: ...
-def datatree_4d(seed=...) -> None: ...
-def datatree_sample(seed=...) -> None: ...
+def generate_base_data(seed: Incomplete = ...) -> None: ...
+def datatree(seed: Incomplete = ...) -> None: ...
+def datatree2(seed: Incomplete = ...) -> None: ...
+def datatree3(seed: Incomplete = ...) -> None: ...
+def datatree_binary(seed: Incomplete = ...) -> None: ...
+def datatree_regression(seed: Incomplete = ...) -> None: ...
+def datatree_4d(seed: Incomplete = ...) -> None: ...
+def datatree_sample(seed: Incomplete = ...) -> None: ...
 def cmp() -> None: ...
 def fake_dt() -> None: ...
-def datatree_censored(seed=...) -> None: ...
+def datatree_censored(seed: Incomplete = ...) -> None: ...
 def check_multiple_attrs(
     test_dict: dict[str, list[str]], parent: DataTree
 ) -> list[str | tuple[str, str]]: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/transform.py 
new/arviz-base-1.3.0/src/arviz_base/transform.py
--- old/arviz-base-1.2.0/src/arviz_base/transform.py    2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/transform.py    2026-08-11 
08:46:05.000000000 +0200
@@ -94,7 +94,6 @@
     if return_dataset:
         # return dataset
         return ds_new
-    else:
-        # return datatree in the unconstrained_{group}
-        idata[f"unconstrained_{group}"] = xr.DataTree(ds_new)
-        return idata
+    # return datatree in the unconstrained_{group}
+    idata[f"unconstrained_{group}"] = xr.DataTree(ds_new)
+    return idata
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/src/arviz_base/validate.pyi 
new/arviz-base-1.3.0/src/arviz_base/validate.pyi
--- old/arviz-base-1.2.0/src/arviz_base/validate.pyi    2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/src/arviz_base/validate.pyi    2026-08-11 
08:46:05.000000000 +0200
@@ -5,6 +5,7 @@
 from collections.abc import Callable, Mapping, Sequence
 from typing import Any
 
+from _typeshed import Incomplete
 from xarray import Dataset, DataTree
 
 from arviz_base.rcparams import defaultParams, rcParams
@@ -12,7 +13,9 @@
 def validate_sample_dims(
     sample_dims: str | Sequence[str] | None, data: Dataset | DataTree | None = 
...
 ) -> list[str]: ...
-def validate_dims_chain_draw_axis(dims, data=...) -> tuple[list, int | None, 
int]: ...
+def validate_dims_chain_draw_axis(
+    dims: Incomplete, data: Incomplete = ...
+) -> tuple[list, int | None, int]: ...
 def validate_dict_argument(
     dict_arg: Mapping[str, Any] | None,
     func_arg: tuple[Callable, str] | None | None = ...,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/tests/test_converters.py 
new/arviz-base-1.3.0/tests/test_converters.py
--- old/arviz-base-1.2.0/tests/test_converters.py       2026-06-12 
17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/tests/test_converters.py       2026-08-11 
08:46:05.000000000 +0200
@@ -81,7 +81,8 @@
 
 class TestConvertToDataset:
     @pytest.fixture(scope="class")
-    def data(self):
+    @classmethod
+    def data(cls):
         rng = np.random.default_rng()
 
         # pylint: disable=attribute-defined-outside-init
@@ -152,6 +153,9 @@
 
 
 @netcdf_nightlies_skip
[email protected](
+    "ignore:Setting the shape on a NumPy array has been deprecated in NumPy 
2.5:DeprecationWarning"
+)
 def test_convert_to_datatree_from_file(tmpdir):
     rng = np.random.default_rng()
     first = convert_to_datatree(rng.normal(size=(1, 100)), group="prior")
@@ -167,6 +171,9 @@
 
 
 @netcdf_nightlies_skip
[email protected](
+    "ignore:Setting the shape on a NumPy array has been deprecated in NumPy 
2.5:DeprecationWarning"
+)
 def test_convert_to_dataset_bad(tmpdir):
     rng = np.random.default_rng()
     first = convert_to_datatree(rng.normal(size=(1, 100)), group="prior")
@@ -178,7 +185,8 @@
 
 class TestDataConvert:
     @pytest.fixture(scope="class")
-    def data(self, draws, chains):
+    @classmethod
+    def data(cls, draws, chains):
         rng = np.random.default_rng()
 
         class Data:
@@ -220,7 +228,7 @@
 
 def test_convert_object_with_array_protocol():
     class ArrayLike:
-        def __array__(self, dtype=None):
+        def __array__(self, dtype=None):  # pylint: disable=unused-argument
             return np.ones((1, 5))
 
     obj = ArrayLike()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/tests/test_labels.py 
new/arviz-base-1.3.0/tests/test_labels.py
--- old/arviz-base-1.2.0/tests/test_labels.py   2026-06-12 17:47:52.000000000 
+0200
+++ new/arviz-base-1.3.0/tests/test_labels.py   2026-08-11 08:46:05.000000000 
+0200
@@ -42,7 +42,8 @@
 
 class TestLabellers:
     @pytest.fixture(scope="class")
-    def labellers(self):
+    @classmethod
+    def labellers(cls):
         return {
             "BaseLabeller": BaseLabeller(),
             "DimCoordLabeller": DimCoordLabeller(),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/tests/test_reorg.py 
new/arviz-base-1.3.0/tests/test_reorg.py
--- old/arviz-base-1.2.0/tests/test_reorg.py    2026-06-12 17:47:52.000000000 
+0200
+++ new/arviz-base-1.3.0/tests/test_reorg.py    2026-08-11 08:46:05.000000000 
+0200
@@ -4,8 +4,14 @@
 import pytest
 import xarray as xr
 
-from arviz_base import dataset_to_dataarray, dataset_to_dataframe, extract, 
references_to_dataset
-from arviz_base.labels import DimCoordLabeller
+from arviz_base import (
+    dataset_to_dataarray,
+    dataset_to_dataframe,
+    explode_dataset_dims,
+    extract,
+    references_to_dataset,
+)
+from arviz_base.labels import BaseLabeller, DimCoordLabeller
 
 
 class TestExtract:
@@ -263,3 +269,44 @@
         assert not np.any(np.isnan(ref_ds["mu"]))
         assert np.allclose(ref_ds["theta"].isel(ref_dim=0), 0)
         assert np.all(np.isnan(ref_ds["theta"].isel(ref_dim=[1, 2])))
+
+
+class TestExplodeDsDims:
+    def test_basic(self, centered_eight):
+        ds = explode_dataset_dims(
+            centered_eight.posterior.dataset, "school", labeller=BaseLabeller()
+        )
+        assert len(ds.data_vars) == 10
+        assert set(ds.data_vars) == set(
+            ["mu", "tau"]
+            + [f"theta[{school}]" for school in 
centered_eight.posterior["school"].to_numpy()]
+        )
+
+    def test_labeller(self, centered_eight):
+        ds = explode_dataset_dims(
+            centered_eight.posterior.dataset, "school", 
labeller=DimCoordLabeller()
+        )
+        assert len(ds.data_vars) == 10
+        assert set(ds.data_vars) == set(
+            ["mu", "tau"]
+            + [
+                f"theta[school: {school}]"
+                for school in centered_eight.posterior["school"].to_numpy()
+            ]
+        )
+
+    def test_dim_to_idx(self, centered_eight):
+        input_ds = (
+            centered_eight.posterior.to_dataset()
+            .assign_coords(region=(["school"], list("aaabbbbb")))
+            .set_xindex("region")
+        )
+        ds = explode_dataset_dims(
+            input_ds, "school", labeller=BaseLabeller(), dim_to_idx={"school": 
"region"}
+        )
+        assert len(ds.data_vars) == 4
+        assert set(ds.data_vars) == {"mu", "tau", "theta[a]", "theta[b]"}
+        assert "school_a" in ds["theta[a]"].dims
+        assert ds.sizes["school_a"] == 3
+        assert "school_b" in ds["theta[b]"].dims
+        assert ds.sizes["school_b"] == 5
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/arviz-base-1.2.0/tox.ini new/arviz-base-1.3.0/tox.ini
--- old/arviz-base-1.2.0/tox.ini        2026-06-12 17:47:52.000000000 +0200
+++ new/arviz-base-1.3.0/tox.ini        2026-08-11 08:46:05.000000000 +0200
@@ -3,27 +3,24 @@
     check
     docs
     nightlies
-    {py312,py313,py314}{,-coverage}
+    {test}{,-coverage}
 # See https://tox.readthedocs.io/en/latest/example/package.html#flit
 isolated_build = True
 isolated_build_env = build
 labels =
-    dev = check, cleandocs, docs, livedocs, viewdocs, py312, py313, py314, 
nightlies
+    dev = check, cleandocs, docs, livedocs, viewdocs, test, nightlies
 
 [gh-actions]
 python =
-    3.12: py312-coverage
-    3.13: py313-coverage, check, nightlies
-    3.14: py314-coverage
+    3.12: test-coverage
+    3.13: test-coverage, check, nightlies
+    3.14: test-coverage
 
 [testenv]
 description = Run ArviZ-base tests
 basepython =
-    py312: python3.12
-    py313: python3.13
-    py314: python3.14
     # See https://github.com/tox-dev/tox/issues/1548
-    {check,docs,cleandocs,viewdocs,build,nightlies}: python3
+    {check,docs,cleandocs,viewdocs,build,nightlies,test}: python3
 setenv =
     PYTHONUNBUFFERED = yes
     PYTEST_EXTRA_ARGS = -s

Reply via email to