diff --git a/IPython/core/completer.py b/IPython/core/completer.py
index d2637c4bb..80aafee41 100644
--- a/IPython/core/completer.py
+++ b/IPython/core/completer.py
@@ -622,8 +622,27 @@ def get__all__entries(obj):
     return [cast_unicode_py2(w) for w in words if isinstance(w, str)]
 
 
-def match_dict_keys(keys, prefix, delims):
-    """Used by dict_key_matches, matching the prefix to a list of keys"""
+def match_dict_keys(keys: List[str], prefix: str, delims: str):
+    """Used by dict_key_matches, matching the prefix to a list of keys
+
+    Parameters
+    ==========
+        keys:
+            list of keys in dictionary currently being completed.
+        prefix:
+            Part of the text already typed by the user. e.g. `mydict[b'fo`
+        delims:
+            String of delimiters to consider when finding the current key.
+
+    Returns
+    =======
+
+    A tuple of three elements: ``quote``, ``token_start``, ``matched``, with
+    ``quote`` being the quote that need to be used to close current string.
+    ``token_start`` the position where the replacement should start occurring,
+    ``matches`` a list of replacement/completion
+
+    """
     if not prefix:
         return None, 0, [repr(k) for k in keys
                       if isinstance(k, (str, bytes))]
@@ -639,7 +658,6 @@ def match_dict_keys(keys, prefix, delims):
     token_start = token_match.start()
     token_prefix = token_match.group()
 
-    # TODO: support bytes in Py3k
     matched = []
     for key in keys:
         try:
@@ -652,7 +670,7 @@ def match_dict_keys(keys, prefix, delims):
         # reformat remainder of key to begin with prefix
         rem = key[len(prefix_str):]
         # force repr wrapped in '
-        rem_repr = repr(rem + '"')
+        rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"')
         if rem_repr.startswith('u') and prefix[0] not in 'uU':
             # Found key is unicode, but prefix is Py2 string.
             # Therefore attempt to interpret key as string.

Dict key completion with bytes keys raises
Dict key tab completion raises when trying to complete a prefix of a bytes literal that is a valid key in the dict, as below.  This issue persists after `pip install --upgrade ipython`.

``` python
Python 3.4.3 (default, Mar  3 2015, 10:49:33) 
Type "copyright", "credits" or "license" for more information.

IPython 3.2.1 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: foo = {b'spam': True, 'ham': False}

In [2]: foo['s<TAB>
%%script             %%system             %store               set                  stat+tlrc.BRIK.gz    str                  symptoms.csv
%%sh                 %save                %sx                  setattr              stat+tlrc.HEAD       sum                  
%%svg                %sc                  %system              slice                staticmethod         sun_et_al_seeds.txt  
%%sx                 %set_env             scripts/             sorted               stims/               super                

In [2]: foo['h<TAB>
%%html    %hist     %history  ham       hasattr   hash      help      hex       

In [2]: foo[b'h<TAB>
%%html    %hist     %history  hasattr   hash      help      hex       

In [2]: foo[b's<TAB>Traceback (most recent call last):
  File "/home/schwabacher/lib/python3.4/site-packages/IPython/core/completer.py", line 1092, in complete
    self.matches.extend(matcher(text))
  File "/home/schwabacher/lib/python3.4/site-packages/IPython/core/completer.py", line 917, in dict_key_matches
    closing_quote, token_offset, matches = match_dict_keys(keys, prefix, self.splitter.delims)
  File "/home/schwabacher/lib/python3.4/site-packages/IPython/core/completer.py", line 449, in match_dict_keys
    rem_repr = repr(rem + '"')
TypeError: can't concat bytes to str

If you suspect this is an IPython bug, please report it at:
    https://github.com/ipython/ipython/issues
or send an email to the mailing list at ipython-dev@scipy.org

You can print a more detailed traceback right now with "%tb", or use "%debug"
to interactively debug it.

Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
    %config Application.verbose_crash=True


%%script             %%system             %store               set                  stat+tlrc.BRIK.gz    str                  symptoms.csv
%%sh                 %save                %sx                  setattr              stat+tlrc.HEAD       sum                  
%%svg                %sc                  %system              slice                staticmethod         sun_et_al_seeds.txt  
%%sx                 %set_env             scripts/             sorted               stims/               super                
```

diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py
index dab79ecad..cd193b934 100644
--- a/IPython/core/tests/test_completer.py
+++ b/IPython/core/tests/test_completer.py
@@ -20,7 +20,7 @@
 from IPython.utils.generics import complete_object
 from IPython.testing import decorators as dec
 
-from IPython.core.completer import Completion, provisionalcompleter
+from IPython.core.completer import Completion, provisionalcompleter, match_dict_keys
 from nose.tools import assert_in, assert_not_in
 
 #-----------------------------------------------------------------------------
@@ -526,7 +526,28 @@ def test_magic_completion_order():
 
     # Order of user variable and line and cell magics with same name:
     text, matches = c.complete('timeit')
-    nt.assert_equal(matches, ["timeit", "%timeit","%%timeit"])
+    nt.assert_equal(matches, ["timeit", "%timeit", "%%timeit"])
+
+def test_match_dict_keys():
+    """
+    Test that match_dict_keys works on a couple of use case does return what
+    expected, and does not crash
+    """
+    delims = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
+
+
+    keys = ['foo', b'far']
+    assert match_dict_keys(keys, "b'", delims=delims)  == ("'", 2 ,['far'])
+    assert match_dict_keys(keys, "b'f", delims=delims) == ("'", 2 ,['far'])
+    assert match_dict_keys(keys, 'b"', delims=delims)  == ('"', 2 ,['far'])
+    assert match_dict_keys(keys, 'b"f', delims=delims) == ('"', 2 ,['far'])
+
+    assert match_dict_keys(keys, "'", delims=delims)  == ("'", 1 ,['foo'])
+    assert match_dict_keys(keys, "'f", delims=delims) == ("'", 1 ,['foo'])
+    assert match_dict_keys(keys, '"', delims=delims)  == ('"', 1 ,['foo'])
+    assert match_dict_keys(keys, '"f', delims=delims) == ('"', 1 ,['foo'])
+    
+    match_dict_keys
 
 
 def test_dict_key_completion_string():

pip install -e .[test]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-xdist pytest-mock pytest-asyncio
apt-get update apt-get install -y gcc
3.6
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
certifi==2021.5.30
charset-normalizer==2.0.12
coverage==6.2
decorator==5.1.1
entrypoints==0.4
execnet==1.9.0
idna==3.10
importlib-metadata==4.8.3
iniconfig==1.1.1
ipykernel==5.5.6
-e git+https://github.com/ipython/ipython.git@06e6b58e0f7878296ee655c825e8a764999a5cc8#egg=ipython
ipython-genutils==0.2.0
jedi==0.19.2
jsonschema==3.2.0
jupyter-client==7.1.2
jupyter-core==4.9.2
nbformat==5.1.3
nest-asyncio==1.6.0
nose==1.3.7
numpy==1.19.5
packaging==21.3
parso==0.8.4
pexpect==4.9.0
pickleshare==0.7.5
pluggy==1.0.0
prompt-toolkit==1.0.18
ptyprocess==0.7.0
py==1.11.0
Pygments==2.14.0
pyparsing==3.1.4
pyrsistent==0.18.0
pytest==7.0.1
pytest-asyncio==0.16.0
pytest-cov==4.0.0
pytest-mock==3.6.1
pytest-xdist==3.0.2
python-dateutil==2.9.0.post0
pyzmq==25.1.2
requests==2.27.1
simplegeneric==0.8.1
six==1.17.0
testpath==0.6.0
tomli==1.2.3
tornado==6.1
traitlets==4.3.3
typing==3.7.4.3
typing_extensions==4.1.1
urllib3==1.26.20
wcwidth==0.2.13
zipp==3.6.0

name: ipython
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - charset-normalizer==2.0.12
      - coverage==6.2
      - decorator==5.1.1
      - entrypoints==0.4
      - execnet==1.9.0
      - idna==3.10
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - ipykernel==5.5.6
      - ipython-genutils==0.2.0
      - jedi==0.19.2
      - jsonschema==3.2.0
      - jupyter-client==7.1.2
      - jupyter-core==4.9.2
      - nbformat==5.1.3
      - nest-asyncio==1.6.0
      - nose==1.3.7
      - numpy==1.19.5
      - packaging==21.3
      - parso==0.8.4
      - pexpect==4.9.0
      - pickleshare==0.7.5
      - pluggy==1.0.0
      - prompt-toolkit==1.0.18
      - ptyprocess==0.7.0
      - py==1.11.0
      - pygments==2.14.0
      - pyparsing==3.1.4
      - pyrsistent==0.18.0
      - pytest==7.0.1
      - pytest-asyncio==0.16.0
      - pytest-cov==4.0.0
      - pytest-mock==3.6.1
      - pytest-xdist==3.0.2
      - python-dateutil==2.9.0.post0
      - pyzmq==25.1.2
      - requests==2.27.1
      - simplegeneric==0.8.1
      - six==1.17.0
      - testpath==0.6.0
      - tomli==1.2.3
      - tornado==6.1
      - traitlets==4.3.3
      - typing==3.7.4.3
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - wcwidth==0.2.13
      - zipp==3.6.0
prefix: /opt/conda/envs/ipython

IPython/core/tests/test_completer.py::test_match_dict_keys
IPython/core/tests/test_completer.py::test_custom_completion_error IPython/core/tests/test_completer.py::test_unicode_completions IPython/core/tests/test_completer.py::test_latex_completions IPython/core/tests/test_completer.py::test_back_latex_completion IPython/core/tests/test_completer.py::test_back_unicode_completion IPython/core/tests/test_completer.py::test_forward_unicode_completion IPython/core/tests/test_completer.py::test_no_ascii_back_completion IPython/core/tests/test_completer.py::test_abspath_file_completions IPython/core/tests/test_completer.py::test_local_file_completions IPython/core/tests/test_completer.py::test_omit__names IPython/core/tests/test_completer.py::test_limit_to__all__False_ok IPython/core/tests/test_completer.py::test_func_kw_completions IPython/core/tests/test_completer.py::test_default_arguments_from_docstring IPython/core/tests/test_completer.py::test_line_magics IPython/core/tests/test_completer.py::test_cell_magics IPython/core/tests/test_completer.py::test_line_cell_magics IPython/core/tests/test_completer.py::test_magic_completion_order IPython/core/tests/test_completer.py::test_dict_key_completion_string IPython/core/tests/test_completer.py::test_dict_key_completion_contexts IPython/core/tests/test_completer.py::test_dict_key_completion_bytes IPython/core/tests/test_completer.py::test_dict_key_completion_unicode_py3 IPython/core/tests/test_completer.py::test_struct_array_key_completion IPython/core/tests/test_completer.py::test_dict_key_completion_invalids IPython/core/tests/test_completer.py::test_object_key_completion IPython/core/tests/test_completer.py::test_aimport_module_completer IPython/core/tests/test_completer.py::test_nested_import_module_completer IPython/core/tests/test_completer.py::test_import_module_completer IPython/core/tests/test_completer.py::test_from_module_completer
IPython/core/tests/test_completer.py::test_protect_filename IPython/core/tests/test_completer.py::test_line_split IPython/core/tests/test_completer.py::CompletionSplitterTestCase::test_delim_setting IPython/core/tests/test_completer.py::CompletionSplitterTestCase::test_spaces IPython/core/tests/test_completer.py::test_has_open_quotes1 IPython/core/tests/test_completer.py::test_has_open_quotes2 IPython/core/tests/test_completer.py::test_has_open_quotes3 IPython/core/tests/test_completer.py::test_has_open_quotes4 IPython/core/tests/test_completer.py::test_get__all__entries_ok IPython/core/tests/test_completer.py::test_get__all__entries_no__all__ok IPython/core/tests/test_completer.py::test_tryimport
IPython/core/completer.py
IPython/core/completer.py