Skip to content

Differing behavior between linux and macos #285

Open

Description

@pavelzw
if __name__ == "__main__":
    """Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    aaaaaaaaaaaaaaaaaaaaa┘."""
    # This is a comment

docformatter -i test.py on macOS (arm) results in no changes being made. docformatter -i test.py on linux aarch64 results in the following changes:

if __name__ == "__main__":
    """Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    aaaaaaaaaaaaaaaaaaaaa┘."""

    # This is a comment

Repeatedly executing docformatter -i on linux adds another line on every call which breaks idempotency.

if __name__ == "__main__":
    """Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    aaaaaaaaaaaaaaaaaaaaa┘."""




    # This is a comment

This might be related to ┘ being in the string.

breaking env on linux:

(base) mambauser@79d93f1c012c:/mnt/abc$ micromamba list -p /home/mambauser/.cache/pre-commit/repotqc_4xjd/conda-default
List of packages in environment: "/home/mambauser/.cache/pre-commit/repotqc_4xjd/conda-default"

  Name                   Version   Build               Channel    
────────────────────────────────────────────────────────────────────
  _openmp_mutex          4.5       2_gnu               conda-forge
  bzip2                  1.0.8     h31becfc_5          conda-forge
  ca-certificates        2024.6.2  hcefe29a_0          conda-forge
  charset-normalizer     3.3.2     pyhd8ed1ab_0        conda-forge
  docformatter           1.7.5     pyhd8ed1ab_0        conda-forge
  ld_impl_linux-aarch64  2.40      h9fc2d93_7          conda-forge
  libexpat               2.6.2     h2f0025b_0          conda-forge
  libffi                 3.4.2     h3557bc0_5          conda-forge
  libgcc-ng              14.1.0    he277a41_0          conda-forge
  libgomp                14.1.0    he277a41_0          conda-forge
  libnsl                 2.0.1     h31becfc_0          conda-forge
  libsqlite              3.46.0    hf51ef55_0          conda-forge
  libuuid                2.38.1    hb4cce97_0          conda-forge
  libxcrypt              4.4.36    h31becfc_1          conda-forge
  libzlib                1.3.1     h68df207_1          conda-forge
  ncurses                6.5       h0425590_0          conda-forge
  openssl                3.3.1     h68df207_1          conda-forge
  pip                    24.0      pyhd8ed1ab_0        conda-forge
  python                 3.12.4    h829453d_0_cpython  conda-forge
  readline               8.2       h8fc344f_1          conda-forge
  setuptools             70.1.1    pyhd8ed1ab_0        conda-forge
  tk                     8.6.13    h194ca79_0          conda-forge
  tomli                  2.0.1     pyhd8ed1ab_0        conda-forge
  tzdata                 2024a     h0c530f3_0          conda-forge
  untokenize             0.1.1     py_0                conda-forge
  wheel                  0.43.0    pyhd8ed1ab_1        conda-forge
  xz                     5.2.6     h9cdd2b7_0          conda-forge

working env on macos:

❯ micromamba list -p /Users/pavel/.cache/pre-commit/repox0xmrc5j/conda-default
List of packages in environment: "/Users/pavel/.cache/pre-commit/repox0xmrc5j/conda-default"

  Name                Version       Build               Channel    
─────────────────────────────────────────────────────────────────────
  bzip2               1.0.8         h93a5062_5          conda-forge
  ca-certificates     2024.2.2      hf0a4a13_0          conda-forge
  charset-normalizer  3.3.2         pyhd8ed1ab_0        conda-forge
  docformatter        1.7.5         pyhd8ed1ab_0        conda-forge
  libexpat            2.6.2         hebf3989_0          conda-forge
  libffi              3.4.2         h3422bc3_5          conda-forge
  libsqlite           3.45.2        h091b4b1_0          conda-forge
  libzlib             1.2.13        h53f4e23_5          conda-forge
  ncurses             6.4.20240210  h078ce10_0          conda-forge
  openssl             3.2.1         h0d3ecfb_1          conda-forge
  pip                 24.0          pyhd8ed1ab_0        conda-forge
  python              3.12.2        hdf0ec26_0_cpython  conda-forge
  readline            8.2           h92ec313_1          conda-forge
  setuptools          69.2.0        pyhd8ed1ab_0        conda-forge
  tk                  8.6.13        h5083fa2_1          conda-forge
  tomli               2.0.1         pyhd8ed1ab_0        conda-forge
  tzdata              2024a         h0c530f3_0          conda-forge
  untokenize          0.1.1         py_0                conda-forge
  wheel               0.43.0        pyhd8ed1ab_0        conda-forge
  xz                  5.2.6         h57fd34a_0          conda-forge

Activity

  1. added
    P: bugPEP 257 violation or existing functionality that doesn't work as documented
    C: conventionRelates to docstring format convention
    and removed
    freshThis is a new issue
    on Jul 31, 2024
  2. weibullguy commented on May 11, 2025

    @weibullguy
    Member

    I do not have access to a macos machine to be able to test this.

  3. pinned this issue on May 12, 2025
  4. jamesbraza commented on Oct 30, 2025

    @jamesbraza

    Fwiw one could use GitHub Actions runners (e.g. ubuntu-latest, macos-latest) or Docker containers to test this

  5. jaysheeldodia commented on Oct 6, 2026

    @jaysheeldodia

    Cause

    I was able to reproduce this issue on my Mac as well as in Linux Docker containers. As far as I can tell, this issue is specific to Python 3.12.4.

    Reproducing the issue

    I tested two Python versions, 3.12.4 and 3.14.7, and two docformatter versions, 1.7.5 and 1.7.8. Since I work on macOS, it was easy to reproduce the issue using just uv. The bug appears, in different forms, only when the Python version is 3.12.4. With Python 3.12.4 and docformatter 1.7.5, a new line is added below the docstring every time docformatter -i filename.py runs. With docformatter 1.7.8, a whitespace is added after the docstring instead.

    With Python 3.14.7 (one version behind the latest), the issue does not appear with either docformatter version.

    I also tested this on Linux and was able to reproduce the issue with Python 3.12.4 and both docformatter 1.7.5 and 1.7.8. The issue does not appear with Python 3.14.7 and docformatter 1.7.8.

    Because of an unknown problem in the Linux Docker container, I wasn't able to test Python 3.14.7 with docformatter 1.7.5, but I don't think that test is needed at this point.

    Findings

    The issue appears with Python 3.12.4 on every docformatter version I tested, and goes away when Python is updated to the latest version.

    Fix

    The fix is simple: if you're not limited to Python 3.12.4, use the latest Python version.

    If you have to use Python 3.12.4, you can apply this fix locally. docformatter reads the column numbers Python gives each token and uses them to copy the gap between tokens when it writes the file back. On Python 3.12.4, after a multiline docstring that contains a character like ┘, those numbers are byte counts instead of character counts. The gap is two columns wide and the copied text is a line break, so every run adds another blank line.

    The fix runs immediately after tokenization. For each token on a single line, it checks that the column really points at that token's text. If the column is a byte count, it converts it to a character count, but only when the new column matches the token. On Python versions where the columns are already correct, nothing changes.

    Changes

    @weibullguy, if docformatter needs a code fix for this specific case, I have already implemented one and I'm happy to raise a PR with all test cases passing and the GitHub workflows running successfully.

    If it's decided that a fix specific to this Python version isn't needed, we can keep updating Python to the latest version as the fix and close this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C: conventionRelates to docstring format conventionP: bugPEP 257 violation or existing functionality that doesn't work as documentedU: highhelp wanted

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions