Repository: Rapptz/discord.py

Issue:
Asset replacing breaks sometimes when using 'gif' as `format`
### Summary

Asset replacing breaks sometimes when using 'gif' as `format`

### Reproduction Steps

- Use discord.py 2.0 (the alpha version, anyways).
- Get an avatar asset of a user (in this case the bot, though this can apply to other types of avatars and possibly other types of assets as well).
- Use the `replace` function to get either an animated GIF or a static PNG of said icon depending on what's provided.
  - In this specific use case and error, the icon needs to be static for the error to happen.
  - Also worth of note is that I get the URL right after by using `str`, though I don't think that matters too much.
  - In the example below I'm using the bot's icon so this is *technically* wasteful, but I only did it this way because I just wanted to use the same line of code for all avatar assets.

### Minimal Reproducible Code

```python
ctx.guild.me.avatar.replace(format='gif',static_format='png',size=128) # should do the trick in a command
```


### Expected Results

It to get the new asset just fine.

### Actual Results

```python
Traceback (most recent call last):
  File "PATH_TO_PYTHON\discord\ext\commands\core.py", line 125, in wrapped
    ret = await coro(*args, **kwargs)
  File "PATH_TO_COG", line 123, in about
    icon_url=f"{str(ctx.guild.me.avatar.replace(format='gif',static_format='png',size=128))}",
  File "PATH_TO_PYTHON\discord\asset.py", line 307, in replace
    raise InvalidArgument(f'format must be one of {VALID_STATIC_FORMATS}')
discord.errors.InvalidArgument: format must be one of frozenset({'jpeg', 'webp', 'png', 'jpg'})
```

### Intents

`guilds=True, members=True, emojis=True, messages=True, reactions=True`

### System Information

```
- Python v3.8.9-final
- discord.py v2.0.0-alpha
    - discord.py pkg_resources: v2.0.0a3453+g58ca9e99
- aiohttp v3.7.4.post0
- system info: Windows 10 10.0.19041
```

### Checklist

- [X] I have searched the open issues for duplicates.
- [X] I have shown the entire traceback, if possible.
- [X] I have removed my token from display, if visible.


Discussion:
This error occurs because the asset is not animated. I guess this could be made more lenient. 
I feel like `.replace`, suggesting both `format` and `static_format` is passed, should use `format` if it is animated and `static_format` if it's not, not really caring if `format` is wrong for non-animated assets. It would allow you to replicate the behavior of `avatar_url_as(format=None,static_format='png', size=128)` from 1.X, which would be nice.

If that's not possible, I understand! Just a bit of a pain to have to use an if statement to detect if it's animated and run two different `.replace`s based off that.

Resolving patch:
diff --git a/discord/asset.py b/discord/asset.py
--- a/discord/asset.py
+++ b/discord/asset.py
@@ -353,6 +353,11 @@ def replace(
     ) -> Self:
         """Returns a new asset with the passed components replaced.
 
+
+        .. versionchanged:: 2.0
+            ``static_format`` is now preferred over ``format``
+            if both are present and the asset is not animated.
+
         .. versionchanged:: 2.0
             This function will now raise :exc:`ValueError` instead of
             ``InvalidArgument``.
@@ -386,7 +391,7 @@ def replace(
                 if format not in VALID_ASSET_FORMATS:
                     raise ValueError(f'format must be one of {VALID_ASSET_FORMATS}')
             else:
-                if format not in VALID_STATIC_FORMATS:
+                if static_format is MISSING and format not in VALID_STATIC_FORMATS:
                     raise ValueError(f'format must be one of {VALID_STATIC_FORMATS}')
             url = url.with_path(f'{path}.{format}')
 


Test patch: