prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Nested attribute access in JS->Python type conversion
  Currently the following code fails,
  ```js
  >>> from js import window
  >>> window.URL.createObjectURL
  Error: Traceback (most recent call last):
    File "/lib/python3.7/site-packages/pyodide.py", line 45, in eval_code
      return eval(compile(expr, '<eval>', mode='eval'), ns, ns)
    File "<eval>", line 1, in <module>
  AttributeError: 'JsBoundMethod' object has no attribute 'createObjectURL'
  ```
  (while `window.URL.createObjectURL` is a valid JS object) because nested attributes (i.e. attribute of an attribute) don't seem to be supported. It would have been nice to make it work, though I have not looked at how difficult that would be.
  from js import fetch treats fetch as a free function
  `fetch` is a member function of `window`.
  However, using `from js import fetch` doesn't realize that and leads to the error:
  
  `TypeError: 'fetch' called on an object that does not implement interface Window.`
  
  For Reproducing the Error:
  ```
  %%py
  
  from js import document, Request, fetch, URL
  img_tag = document.createElement('img')
  req = Request.new('https://i.ibb.co/3f4yJQS/face4.jpg')
  
  def func(response):
      return response.blob()
  
  def func2(blob):
      objURL = URL.createObjectURL(blob)
      img_tag.src = objURL
  
  fetch(req).then(func).then(func2)
  
  document.body.appendChild(img_tag)
  ```
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `src/pyodide-py/pyodide/_core.py`
  Content:
  ```
  1 # type: ignore
  2 import platform
  3 
  4 if platform.system() == "Emscripten":
  5     from _pyodide_core import JsProxy, JsBoundMethod, JsException
  6 else:
  7     # Can add shims here if we are so inclined.
  8     class JsException(Exception):
  9         """
  10         A wrapper around a Javascript Error to allow the Error to be thrown in Python.
  11         """
  12 
  13         # Defined in jsproxy.c
  14 
  15     class JsProxy:
  16         """A proxy to make a Javascript object behave like a Python object"""
  17 
  18         # Defined in jsproxy.c
  19 
  20     class JsBoundMethod:
  21         """A proxy to make it possible to call Javascript bound methods from Python."""
  22 
  23         # Defined in jsproxy.c
  24 
  25 
  26 __all__ = [JsProxy, JsBoundMethod, JsException]
  27
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/src/pyodide-py/pyodide/_core.py b/src/pyodide-py/pyodide/_core.py
  --- a/src/pyodide-py/pyodide/_core.py
  +++ b/src/pyodide-py/pyodide/_core.py
  @@ -2,7 +2,7 @@
   import platform
   
   if platform.system() == "Emscripten":
  -    from _pyodide_core import JsProxy, JsBoundMethod, JsException
  +    from _pyodide_core import JsProxy, JsMethod, JsException
   else:
       # Can add shims here if we are so inclined.
       class JsException(Exception):
  @@ -17,10 +17,10 @@
   
           # Defined in jsproxy.c
   
  -    class JsBoundMethod:
  +    class JsMethod:
           """A proxy to make it possible to call Javascript bound methods from Python."""
   
           # Defined in jsproxy.c
   
   
  -__all__ = [JsProxy, JsBoundMethod, JsException]
  +__all__ = [JsProxy, JsMethod, JsException]
  
verification_info: {"golden_diff": "diff --git a/src/pyodide-py/pyodide/_core.py b/src/pyodide-py/pyodide/_core.py\n--- a/src/pyodide-py/pyodide/_core.py\n+++ b/src/pyodide-py/pyodide/_core.py\n@@ -2,7 +2,7 @@\n import platform\n \n if platform.system() == \"Emscripten\":\n-    from _pyodide_core import JsProxy, JsBoundMethod, JsException\n+    from _pyodide_core import JsProxy, JsMethod, JsException\n else:\n     # Can add shims here if we are so inclined.\n     class JsException(Exception):\n@@ -17,10 +17,10 @@\n \n         # Defined in jsproxy.c\n \n-    class JsBoundMethod:\n+    class JsMethod:\n         \"\"\"A proxy to make it possible to call Javascript bound methods from Python.\"\"\"\n \n         # Defined in jsproxy.c\n \n \n-__all__ = [JsProxy, JsBoundMethod, JsException]\n+__all__ = [JsProxy, JsMethod, JsException]\n", "issue": "Nested attribute access in JS->Python type conversion\nCurrently the following code fails,\r\n```js\r\n>>> from js import window\r\n>>> window.URL.createObjectURL\r\nError: Traceback (most recent call last):\r\n  File \"/lib/python3.7/site-packages/pyodide.py\", line 45, in eval_code\r\n    return eval(compile(expr, '<eval>', mode='eval'), ns, ns)\r\n  File \"<eval>\", line 1, in <module>\r\nAttributeError: 'JsBoundMethod' object has no attribute 'createObjectURL'\r\n```\r\n(while `window.URL.createObjectURL` is a valid JS object) because nested attributes (i.e. attribute of an attribute) don't seem to be supported. It would have been nice to make it work, though I have not looked at how difficult that would be.\nfrom js import fetch treats fetch as a free function\n`fetch` is a member function of `window`.\r\nHowever, using `from js import fetch` doesn't realize that and leads to the error:\r\n\r\n`TypeError: 'fetch' called on an object that does not implement interface Window.`\r\n\r\nFor Reproducing the Error:\r\n```\r\n%%py\r\n\r\nfrom js import document, Request, fetch, URL\r\nimg_tag = document.createElement('img')\r\nreq = Request.new('https://i.ibb.co/3f4yJQS/face4.jpg')\r\n\r\ndef func(response):\r\n    return response.blob()\r\n\r\ndef func2(blob):\r\n    objURL = URL.createObjectURL(blob)\r\n    img_tag.src = objURL\r\n\r\nfetch(req).then(func).then(func2)\r\n\r\ndocument.body.appendChild(img_tag)\r\n```\n", "before_files": [{"content": "# type: ignore\nimport platform\n\nif platform.system() == \"Emscripten\":\n    from _pyodide_core import JsProxy, JsBoundMethod, JsException\nelse:\n    # Can add shims here if we are so inclined.\n    class JsException(Exception):\n        \"\"\"\n        A wrapper around a Javascript Error to allow the Error to be thrown in Python.\n        \"\"\"\n\n        # Defined in jsproxy.c\n\n    class JsProxy:\n        \"\"\"A proxy to make a Javascript object behave like a Python object\"\"\"\n\n        # Defined in jsproxy.c\n\n    class JsBoundMethod:\n        \"\"\"A proxy to make it possible to call Javascript bound methods from Python.\"\"\"\n\n        # Defined in jsproxy.c\n\n\n__all__ = [JsProxy, JsBoundMethod, JsException]\n", "path": "src/pyodide-py/pyodide/_core.py"}], "after_files": [{"content": "# type: ignore\nimport platform\n\nif platform.system() == \"Emscripten\":\n    from _pyodide_core import JsProxy, JsMethod, JsException\nelse:\n    # Can add shims here if we are so inclined.\n    class JsException(Exception):\n        \"\"\"\n        A wrapper around a Javascript Error to allow the Error to be thrown in Python.\n        \"\"\"\n\n        # Defined in jsproxy.c\n\n    class JsProxy:\n        \"\"\"A proxy to make a Javascript object behave like a Python object\"\"\"\n\n        # Defined in jsproxy.c\n\n    class JsMethod:\n        \"\"\"A proxy to make it possible to call Javascript bound methods from Python.\"\"\"\n\n        # Defined in jsproxy.c\n\n\n__all__ = [JsProxy, JsMethod, JsException]\n", "path": "src/pyodide-py/pyodide/_core.py"}]}