Repository: callowayproject/bump-my-version (python)

Issue:
Empty string replacement (`--replace ""`) is interpreted as absence of parameter
* bump-my-version version: 0.15.4
* Python version: 3.12.1
* Operating System: macOS 14.2.1

### Description

A simple search and replace of plain string by an empty one is polluted by non-matching rules from the configuration file.

This is a follow-up of #70.

### What I Did

Here are my files:

* `pyproject.toml`:
  ```toml
  [tool.bumpversion]
  current_version = "2.21.1"
  allow_dirty = true
  
  [[tool.bumpversion.files]]
  filename = "./changelog.md"
  search = "random"
  replace = "blah_blah_blah"
  ```

* `changelog.md`:
  ```md
   Changelog
  
  ## [2.21.1 (unreleased)](https://github.com/kdeldycke/workflows/compare/v2.21.0...main)
  
  - Test profanity.
  ```

Here I'm trying to replace the `profanity` string by `XXX` with this CLI invokation, and it works:

```shell-session
$ bump-my-version replace --dry-run --verbose --no-configured-files --allow-dirty --ignore-missing-version --search "profanity" --replace "XXX" ./changelog.md
Starting BumpVersion 0.15.4                                                                                                                                                                                         
Reading configuration                                                                                                                                                                                               
  Reading config file: /Users/kde/bump_test/pyproject.toml                                                                                                                                                          
Parsing version '2.21.1' using regexp '(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)'                                                                                                                              
  Parsed the following values: major=2, minor=21, patch=1                                                                                                                                                           
                                                                                                                                                                                                                    
File ./changelog.md: replace `profanity` with `XXX`                                                                                                                                                                 
  Found 'profanity' at line 5: profanity                                                                                                                                                                            
  Would change file ./changelog.md:                                                                                                                                                                                 
    *** before ./changelog.md                                                                                                                                                                                       
    --- after ./changelog.md                                                                                                                                                                                        
    ***************                                                                                                                                                                                                 
    *** 2,5 ****                                                                                                                                                                                                    
                                                                                                                                                                                                                    
      ## [2.21.1 (unreleased)](https://github.com/kdeldycke/workflows/compare/v2.21.0...main)                                                                                                                       
                                                                                                                                                                                                                    
    ! - Test profanity.                                                                                                                                                                                             
    --- 2,5 ----                                                                                                                                                                                                    
                                                                                                                                                                                                                    
      ## [2.21.1 (unreleased)](https://github.com/kdeldycke/workflows/compare/v2.21.0...main)                                                                                                                       
                                                                                                                                                                                                                    
    ! - Test XXX.                                                                                                                                                                                                   
                                                                                                                                                                                                                    
File ./changelog.md: replace `profanity` with `XXX`                                                                                                                                                                 
  Found 'profanity' at line 5: profanity                                                                                                                                                                            
  Would change file ./changelog.md:                                                                                                                                                                                 
    *** before ./changelog.md                                                                                                                                                                                       
    --- after ./changelog.md                                                                                                                                                                                        
    ***************                                                                                                                                                                                                 
    *** 2,5 ****                                                                                                                                                                                                    
                                                                                                                                                                                                                    
      ## [2.21.1 (unreleased)](https://github.com/kdeldycke/workflows/compare/v2.21.0...main)                                                                                                                       
                                                                                                                                                                                                                    
    ! - Test profanity.                                                                                                                                                                                             
    --- 2,5 ----                                                                                                                                                                                                    
                                                                                                                                                                                                                    
      ## [2.21.1 (unreleased)](https://github.com/kdeldycke/workflows/compare/v2.21.0...main)                                                                                                                       
                                                                                                                                                                                                                    
    ! - Test XXX.    
```

It works as expected, with the only small annoyance that the replacement action seems to be called twice. Maybe this is just a detail of the way the replacement action is reported, or it might indicate a trickier problem. Anyway.

Now instead of `XXX`, I want to remove the `profanity` entirely, and replace it by an empty string.

So here I call the same CLI as above, but use the `--replace ""` option instead:

```shell-session
$ bump-my-version replace --dry-run --verbose --no-configured-files --allow-dirty --ignore-missing-version --search "profanity" --replace "" ./changelog.md
Starting BumpVersion 0.15.4                                                                                                                                                                                         
Reading configuration                                                                                                                                                                                               
  Reading config file: /Users/kde/bump_test/pyproject.toml                                                                                                                                                          
Parsing version '2.21.1' using regexp '(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)'                                                                                                                              
  Parsed the following values: major=2, minor=21, patch=1                                                                                                                                                           
                                                                                                                                                                                                                    
File ./changelog.md: replace `profanity` with `{new_version}`                                                                                                                                                       
  Found 'profanity' at line 5: profanity                                                                                                                                                                            
  Would change file ./changelog.md:                                                                                                                                                                                 
    *** before ./changelog.md                                                                                                                                                                                       
    --- after ./changelog.md                                                                                                                                                                                        
    ***************                                                                                                                                                                                                 
    *** 2,5 ****                                                                                                                                                                                                    
                                                                                                                                                                                                                    
      ## [2.21.1 (unreleased)](https://github.com/kdeldycke/workflows/compare/v2.21.0...main)                                                                                                                       
                                                                                                                                                                                                                    
    ! - Test profanity.                                                                                                                                                                                             
    --- 2,5 ----                                                                                                                                                                                                    
                                                                                                                                                                                                                    
      ## [2.21.1 (unreleased)](https://github.com/kdeldycke/workflows/compare/v2.21.0...main)                                                                                                                       
                                                                                                                                                                                                                    
    ! - Test 2.21.1.                                                                                                                                                                                                
                                                                                                                                                                                                                    
File ./changelog.md: replace `profanity` with `blah_blah_blah`                                                                                                                                                      
  Found 'profanity' at line 5: profanity                                                                                                                                                                            
  Would change file ./changelog.md:                                                                                                                                                                                 
    *** before ./changelog.md                                                                                                                                                                                       
    --- after ./changelog.md                                                                                                                                                                                        
    ***************                                                                                                                                                                                                 
    *** 2,5 ****                                                                                                                                                                                                    
                                                                                                                                                                                                                    
      ## [2.21.1 (unreleased)](https://github.com/kdeldycke/workflows/compare/v2.21.0...main)                                                                                                                       
                                                                                                                                                                                                                    
    ! - Test profanity.                                                                                                                                                                                             
    --- 2,5 ----                                                                                                                                                                                                    
                                                                                                                                                                                                                    
      ## [2.21.1 (unreleased)](https://github.com/kdeldycke/workflows/compare/v2.21.0...main)                                                                                                                       
                                                                                                                                                                                                                    
    ! - Test blah_blah_blah.                                                                                                                                                                                        
```

I expect there the changed line in  `./changelog.md`  to be `- Test .`, but instead, I get two conflicting results:
- the first in which `profanity` is replaced by the current version (`2.21.1`)
- the second in which `profanity` is replaced by the unrelated `blah_blah_blah` string that has been hard-coded in the `pyproject.toml` file

By the nature of this edge-case, it feels like somewhere in the code path, the empty string passed to `--replace` is normalized to `None`, as if `--replace` hasn't been used at all.


Pull request:
Fixed empty string replacement bug
Only a missing replacement value will trigger one of the fallback options.

Fixes #117

Patch:
diff --git a/bumpversion/files.py b/bumpversion/files.py
index 4bca5e87..aee9c505 100644
--- a/bumpversion/files.py
+++ b/bumpversion/files.py
@@ -74,11 +74,13 @@ class ConfiguredFile:
         search: Optional[str] = None,
         replace: Optional[str] = None,
     ) -> None:
+        replacements = [replace, file_change.replace, version_config.replace]
+        replacement = next((r for r in replacements if r is not None), "")
         self.file_change = FileChange(
             parse=file_change.parse or version_config.parse_regex.pattern,
             serialize=file_change.serialize or version_config.serialize_formats,
             search=search or file_change.search or version_config.search,
-            replace=replace or file_change.replace or version_config.replace,
+            replace=replacement,
             regex=file_change.regex or False,
             ignore_missing_version=file_change.ignore_missing_version or False,
             filename=file_change.filename,


Test patch:
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 20532f76..ba5b4654 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -576,6 +576,7 @@ def test_replace_with_empty_string(tmp_path, fixtures_path):
             cli.cli,
             [
                 "replace",
+                "--verbose",
                 "--no-configured-files",
                 "--allow-dirty",
                 "--search",
@@ -590,8 +591,8 @@ def test_replace_with_empty_string(tmp_path, fixtures_path):
         print("Here is the output:")
         print(result.output)
         print(traceback.print_exception(result.exc_info[1]))
-
     assert result.exit_code == 0
+    assert doc_path.read_text() == "We should censor \n\n"
 
 
 def test_valid_regex_not_ignoring_regex(tmp_path: Path, caplog) -> None: