adamchainz/patchy

`patch: **** malformed patch at line xxx` error

gilbh opened this issue · 3 comments

gilbh commented

Python Version

3.10

Package Version

2.6.0

Description

Hi,

Love this project!

(I am unfamiliar with patching conventions so please excuse this if redundant).

I am trying to monkeypatch my IPython so the ansicolors work well in my Windows (see ipython/ipython#13486 among other relevant issues). Long story short, I've came up with the following addition to my ~\.ipython\profile_default\startup\my_startup_stuff.py:

# Monkeypath IPython to avoid hard-to-read colors on Windows
if IS_WIN:
    import patchy
    from IPython.terminal.interactiveshell import TerminalInteractiveShell

    patchy.patch(
        TerminalInteractiveShell._make_style_from_name_or_cls,
        """\
        @@ -21,4 +21,4 @@
         def _make_style_from_name_or_cls(self, name_or_cls):
                     style_overrides.update({
                         Token.Number: '#ansigreen',
                         Token.Operator: 'noinherit',
        -                Token.String: '#ansiblue',
        +                Token.String: '#ansired',
        """,
    )

I've created this code following your instructions, working with these files:
interactiveshell.py
after.py
before.py
and running:

git diff -u before.py after.py

The error that comes up is this:

ValueError: Could not apply the patch to '_make_style_from_name_or_cls'. The message from `patch
` was:
missing header for unified diff at line 1 of patch
patching file C:\Users\gilbe\AppData\Local\Temp\patchyf3wfo853\_make_style_from_name_or_cls.py

patch: **** malformed patch at line 5:                  Token.Operator: 'noinherit',


The code to patch was:
def _make_style_from_name_or_cls(self, name_or_cls):
    """
    Small wrapper that make an IPython compatible style from a style name

    We need that to add style for prompt ... etc.
    """
    style_overrides = {}
    if name_or_cls == 'legacy':
        legacy = self.colors.lower()
        if legacy == 'linux':
            style_cls = get_style_by_name('monokai')
            style_overrides = _style_overrides_linux
        elif legacy == 'lightbg':
            style_overrides = _style_overrides_light_bg
            style_cls = get_style_by_name('pastie')
        elif legacy == 'neutral':
            # The default theme needs to be visible on both a dark background
            # and a light background, because we can't tell what the terminal
            # looks like. These tweaks to the default theme help with that.
            style_cls = get_style_by_name('default')
            style_overrides.update({
                Token.Number: '#ansigreen',
                Token.Operator: 'noinherit',
                Token.String: '#ansiyellow',
                Token.Name.Function: '#ansiblue',
                Token.Name.Class: 'bold #ansiblue',
                Token.Name.Namespace: 'bold #ansiblue',
                Token.Name.Variable.Magic: '#ansiblue',
                Token.Prompt: '#ansigreen',
                Token.PromptNum: '#ansibrightgreen bold',
                Token.OutPrompt: '#ansired',
                Token.OutPromptNum: '#ansibrightred bold',
            })

            # Hack: Due to limited color support on the Windows console
            # the prompt colors will be wrong without this
            if os.name == 'nt':
                style_overrides.update({
                    Token.Prompt: '#ansidarkgreen',
                    Token.PromptNum: '#ansigreen bold',
                    Token.OutPrompt: '#ansidarkred',
                    Token.OutPromptNum: '#ansired bold',
                })
        elif legacy =='nocolor':
            style_cls=_NoStyle
            style_overrides = {}
        else :
            raise ValueError('Got unknown colors: ', legacy)
    else :
        if isinstance(name_or_cls, str):
            style_cls = get_style_by_name(name_or_cls)
        else:
            style_cls = name_or_cls
        style_overrides = {
            Token.Prompt: '#ansigreen',
            Token.PromptNum: '#ansibrightgreen bold',
            Token.OutPrompt: '#ansired',
            Token.OutPromptNum: '#ansibrightred bold',
        }
    style_overrides.update(self.highlighting_style_overrides)
    style = merge_styles([
        style_from_pygments_cls(style_cls),
        style_from_pygments_dict(style_overrides),
    ])

    return style

The patch was:
@@ -21,4 +21,4 @@
 def _make_style_from_name_or_cls(self, name_or_cls):
             style_overrides.update({
                 Token.Number: '#ansigreen',
                 Token.Operator: 'noinherit',
-                Token.String: '#ansiblue',
+                Token.String: '#ansired',

I get it that the error comes from patch and not from patchy, but I am wondering if there's something I am doing wrong in terms of indentations and similar formatting issues. I am not sure the import of the class is the correct way to go, if my indentation is correct, etc.

Thanks in advance for any help!
Best,
Gil

It looks like your patch utility requires the header lines - those before the @@ that specify the filename etc., which step 4 of the "How to Create a Patch" guide encourages you to remove. Can you try adding some back in, until you find which line is required? Hopefully the filenames don't matter, since patchy saves the code in a random temp file.

A better solution to this is to apply the patch in-memory with some Python code. When I created patchy I didn't find any acceptable pure-python implementations of patching. There may be one out there now, or it may be time to just write one :)

Looking again at this, I can see that your example patch seems to have incorrect line numbers - it should be @@ -21,5 +21,5 @@ , because 5 lines are on either side, not 4. I am sensitive to this because I just found the upgraded patch on my computer was failing some tests so I had to fix the tests’ patches’ line numbers in #437 .

I think that we can close this for now. A python patch implementation is on the backburner.

gilbh commented

Thanks Adam.

I will look more closely into this some time later. But I would love to here news about python patch.

Best