Open s-weigand opened 4 years ago
Does this mean that all existing users will see spaces disappear in their config file?
That would introduce a lot of unwanted diffs...
@florisla Yes, this change would remove trailing spaces from existing configs and thus create additional diffs.
That said I think those additional diffs are a one time thing since I don't know of other tools that add trailing whitespaces, but many that remove them.
While the current behavior possibly creates unwanted diffs after each version bumping when the setup.cfg
gets changed.
e.g.: The following scenario
bump2version
is run and possibly adds trailing whitespacesremove trailing whitespaces
the whitespaces are removed again, unrelated to the actual changebump2version
is run and the cycle begins againSo IMHO the current behavior creates possibly more unwanted diffs than the changed one.
Also, if the commit = True
and tag = True
settings are used the diff created by this change most likely won't even be looked at, while the diffs of the scenario described above would be part of the normal reviewing process.
Another noteworthy point in respect to formatting only diffs is that bump2version
will create those anyway since the whole setup.cfg
is rewritten and new_config.getvalue()
doesn't know about the previous formatting.
Lastly, this would allow using bump2version
in conjunction with setup-cfg-fmt as a pre-commit hook, which was my initial problem.
I agree that stripping the trailing whitespace is better.
The question is, will all users be happy (or don't care) if we change this.
Also, we have to decide if we still want to re-write the config file at all, but that's another issue (#185).
I have a theory on why text with return characters (\r
) is also splittable on newlines (\n
)... Because \r
is seldom used on its own, it's always combined with a newline like \r\n
. So it's either \n
or \r\n
. See the table at https://en.wikipedia.org/wiki/Newline .
Do note that the current newline detection has a bug... If a file contains both \n
and \r\n
line endings, then config_newlines
is a tuple. We should probably raise an error when that's the case.
Reason I am a big fan of this change:
Projects that use pre-commit's "Trim Trailing Whitespace" hook will see the version-bump commits fail because setup.cfg otherwise contains whitespace prior to the commit (after its rewrite).
$ bump2version pre
Check python ast.........................................................Passed
Check builtin type constructor use.......................................Passed
Check docstring is first.................................................Passed
Check JSON...........................................(no files to check)Skipped
Check for merge conflicts................................................Passed
Check Toml...........................................(no files to check)Skipped
Check Yaml...............................................................Passed
Debug Statements (Python)................................................Passed
Tests should end in _test.py.........................(no files to check)Skipped
Fix requirements.txt.................................(no files to check)Skipped
Trim Trailing Whitespace.................................................Failed
- hook id: trailing-whitespace
- exit code: 1
- files were modified by this hook
Fixing setup.cfg
flake8...................................................................Passed
yamllint.................................................................Passed
Failed to run ['git', 'commit', '-F', '/var/folders/28/rx5hw8hd3hl48jtj0c1vz9wr0000gn/T/tmpo99tyb6k']: return code 1, output: b''
Traceback (most recent call last):
File "/Users/<redacted>/venv/lib/python3.9/site-packages/bumpversion/vcs.py", line 31, in commit
subprocess.check_output(
File "/usr/local/Cellar/python@3.9/3.9.1_6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/subprocess.py", line 420, in check_output
return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
File "/usr/local/Cellar/python@3.9/3.9.1_6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/subprocess.py", line 524, in run
raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['git', 'commit', '-F', '/var/folders/28/rx5hw8hd3hl48jtj0c1vz9wr0000gn/T/tmpo99tyb6k']' returned non-zero exit status 1.
Traceback (most recent call last):
File "/Users/<redacted>/venv/bin/bump2version", line 8, in <module>
sys.exit(main())
File "/Users/<redacted>/venv/lib/python3.9/site-packages/bumpversion/cli.py", line 135, in main
context = _commit_to_vcs(files, context, config_file, config_file_exists, vcs,
File "/Users/<redacted>/venv/lib/python3.9/site-packages/bumpversion/cli.py", line 706, in _commit_to_vcs
vcs.commit(
File "/Users/<redacted>/venv/lib/python3.9/site-packages/bumpversion/vcs.py", line 39, in commit
raise exc
File "/Users/<redacted>/venv/lib/python3.9/site-packages/bumpversion/vcs.py", line 31, in commit
subprocess.check_output(
File "/usr/local/Cellar/python@3.9/3.9.1_6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/subprocess.py", line 420, in check_output
return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
File "/usr/local/Cellar/python@3.9/3.9.1_6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/subprocess.py", line 524, in run
raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['git', 'commit', '-F', '/var/folders/28/rx5hw8hd3hl48jtj0c1vz9wr0000gn/T/tmpo99tyb6k']' returned non-zero exit status 1.
I think I finally found the black magic that puzzled me back then 😄 It looks like python sanitizes line endings when reading a file in text mode.
In [1]: with open("dummy.txt", "wb") as dummy:
: dummy.write(b"foo\r\nbar")
:
In [2]: with open("dummy.txt", "rb") as dummy:
: print(dummy.read())
:
b'foo\r\nbar'
In [3]: with open("dummy.txt", "r") as dummy:
: print(dummy.read().encode())
:
b'foo\nbar'
Same result on windows (gitbash
, cmd
) and Linux (WSL2
)
There is another complication: files which use multiple newline styles intermixed!
When calling open()
in text mode on a file, you can reference newlines. Typically this is "\n" or "\r\n", but it could be a tuple with multiple styles.
bump2version already checks newlines
and returns it from _load_configuration().
Edit: Python's newline interpretation behavior is documented in open().
There are some questions I have regarding raising an error on intermixed newline, first and foremost should it be done in this PR?
ValueError
or rather a custom error MixedLineEndingError
\n
(if it is in the tuple) would be a better user experience since I can't think of a reason why someone would purposefully have mixed line endings.Just want to hop in here and give my +1. I find the trailing whitespace to be annoying, and I would much rather have a one-time diff that removes trailing whitespace than continuous diffs that pop up every time I have to adjust the config file. I would love for this PR to get released!
Not that I'm qualified to answer your question, but I'll give my 2 cents while I'm here: I think fixing the line ending bug is outside the scope of this PR. You haven't touched any of the code that affects which newline(s) the file uses, and it's not really relevant to the conceptual change either.
First of all thanks for the nice tool, I have used it for 3 years and together with a CD system, releasing a new version of your package is a breeze 😄
Recently I made my first
setup.cfg
only package (bare minimumsetup.py
) and when I wanted to bump the version with (commit = True
andtag = True
settings as usual), my pre-commit hook removing trailing white spaces failed, rendering me unable to make a commit.After some investigating I found that
bump2version
generates the following unwanted diff:Since many people have editor settings and/or other measures to remove trailing white spaces, and I don't know of any reason to add them, I decided to make this ninja PR, which makes
bump2version
remove them by default.Since the line spitting is closely related to the used newline character, I integrated the test into
test_retain_newline
.Confusing black magic
Even so splitting lines which have
\r
as newline character, with\n
shouldn't work in theory it somehow does. Also, I found that the passed value ofconfig_newlines
in the tests is oftenNone
, which is why tests failed when I tried to split onconfig_newlines
or simply use.splitlines()
. This is also the reason why I had to manually add back the\n
, instead of.writelines
taking care of that.The only way for
config_newlines
to beNone
, without any other issues, would be if the file wasn't read before retrievingnewlines
from the file descriptor. But it is read before: https://github.com/c4urself/bump2version/blob/8e6db2370a683f17a4188d8b4cc8968bac881c56/bumpversion/cli.py#L270-L272And the function where it is read is always called: https://github.com/c4urself/bump2version/blob/8e6db2370a683f17a4188d8b4cc8968bac881c56/bumpversion/cli.py#L89-L91
So I'm very confused and have the 2nd biggest problem in programming, 'It works and I don't know why!'. Maybe you can enlighten me, about what kind of black magic is going on here 😅