Repository: pallets/werkzeug (python)

Issue:
calls to `iri_to_uri` fails when the argument is a bytestring
Calls to `iri_to_uri` fails when the argument is a bytestring. Here's an example:

```console
>>> from werkzeug import urls
>>> urls.iri_to_uri(b'/foo')
<stdin>:1: DeprecationWarning: Passing bytes is deprecated and will not be supported in Werkzeug 3.0.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/midchildan/Documents/playground/werkzeug/lib/python3.10/site-packages/werkzeug/urls.py", line 983, in iri_to_uri
    iri = iri.decode(charset)
TypeError: decode() argument 'encoding' must be str, not None
```

This is what should've happened instead:

```console
>>> from werkzeug import urls
>>> urls.iri_to_uri(b'/foo')
>>> '/foo'
```

Environment:

- Python version: 3.10.11
- Werkzeug version: 2.3.4


Pull request description:
show warning instead of error when passing bytes to `iri_to_uri`
This fixes the `iri_to_uri` method referencing the `charset` variable before it is ready.

- fixes #2708

<!--
Ensure each step in CONTRIBUTING.rst is complete by adding an "x" to
each box below.

If only docs were changed, these aren't relevant and can be removed.
-->

Checklist:

- [X] Add tests that demonstrate the correct behavior of the change. Tests should fail without the change.
- [X] Add or update relevant docs, in the docs folder and in code.
- [X] Add an entry in `CHANGES.rst` summarizing the change and linking to the issue.
- [X] Add `.. versionchanged::` entries in any relevant code docs.
- [X] Run `pre-commit` hooks and fix any issues.
- [x] Run `pytest` and `tox`, no tests failed.

The current flake8 failures also happen on the `main` branch, so I'm not sure if this PR is the right place to fix this.

Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index eb262fb6..5ea84fd0 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -10,6 +10,8 @@ Unreleased
 -   The debugger escapes the exception message in the page title. :pr:`2719`
 -   When binding ``routing.Map``, a long IDNA ``server_name`` with a port does not fail
     encoding. :issue:`2700`
+-   ``iri_to_uri`` shows a deprecation warning instead of an error when passing bytes.
+    :issue:`2708`
 
 
 Version 2.3.4
diff --git a/src/werkzeug/urls.py b/src/werkzeug/urls.py
index 89ef2194..f5760eb4 100644
--- a/src/werkzeug/urls.py
+++ b/src/werkzeug/urls.py
@@ -966,6 +966,16 @@ def iri_to_uri(
 
     .. versionadded:: 0.6
     """
+    if charset is not None:
+        warnings.warn(
+            "The 'charset' parameter is deprecated and will be removed"
+            " in Werkzeug 3.0.",
+            DeprecationWarning,
+            stacklevel=2,
+        )
+    else:
+        charset = "utf-8"
+
     if isinstance(iri, tuple):
         warnings.warn(
             "Passing a tuple is deprecated and will not be supported in Werkzeug 3.0.",
@@ -982,16 +992,6 @@ def iri_to_uri(
         )
         iri = iri.decode(charset)
 
-    if charset is not None:
-        warnings.warn(
-            "The 'charset' parameter is deprecated and will be removed"
-            " in Werkzeug 3.0.",
-            DeprecationWarning,
-            stacklevel=2,
-        )
-    else:
-        charset = "utf-8"
-
     if errors is not None:
         warnings.warn(
             "The 'errors' parameter is deprecated and will be removed in Werkzeug 3.0.",


Test patch:
diff --git a/tests/test_urls.py b/tests/test_urls.py
index 56bca8e9..0b0f2aee 100644
--- a/tests/test_urls.py
+++ b/tests/test_urls.py
@@ -229,6 +229,9 @@ def test_iri_support():
     with pytest.deprecated_call():
         assert urls.uri_to_iri(b"/foo") == "/foo"
 
+    with pytest.deprecated_call():
+        assert urls.iri_to_uri(b"/foo") == "/foo"
+
     assert urls.iri_to_uri("/foo") == "/foo"
 
     assert (