Skip to content

Mutable reference options.headers #1095

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
2 tasks done
AsahiSoftWareEngineer opened this issue Apr 2, 2025 · 7 comments
Closed
2 tasks done

Mutable reference options.headers #1095

AsahiSoftWareEngineer opened this issue Apr 2, 2025 · 7 comments
Labels
bug Something isn't working python Pull requests that update Python code

Comments

@AsahiSoftWareEngineer
Copy link
Contributor

Bug report

  • I confirm this is a bug with Supabase, not with my own application.
  • I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

A clear and concise description of what the bug is.

Mutable reference options.headers

options.headers is updated in create_client directry. thats why, The headers may be changed unintentionally if it is shared ClientOptions` instance other position.

To Reproduce

Please execute below source code jupytor notebook.

from supabase import create_client
from supabase.lib.client_options import SyncClientOptions 
class settings:
    SUPABASE_URL = "https://***"
    SUPABASE_KEY = "***"
from supabase._sync.client import create_client, ClientOptions
from gotrue import SyncMemoryStorage

# Share same ClientOptions Instanc
shared_options = ClientOptions(storage=SyncMemoryStorage(), headers={"Custom-Header": "InitialValue"})

# Create client1
client1 = create_client(settings.SUPABASE_URL, settings.SUPABASE_KEY, options=shared_options)

# Create client2
client2 = create_client(settings.SUPABASE_URL, settings.SUPABASE_KEY, options=shared_options)

# Rewrite header client1
client1.options.headers["Custom-Header"] = "ModifiedValue"
client2.options.headers["Custom-Header"] = "ModifiedValue2"

# Check header client2
print(client1.options.headers["Custom-Header"])  # "ModifiedValue2" 

Expected behavior

...
print(client1.options.headers["Custom-Header"])
# -> "ModifiedValue" 

Screenshots

Image

System information

  • mac OS
  • chrome
  • Version of supabase-py: 2.15.0
  • Version of Python: 3.9.0

Additional context

@AsahiSoftWareEngineer AsahiSoftWareEngineer added the bug Something isn't working label Apr 2, 2025
@AsahiSoftWareEngineer
Copy link
Contributor Author

@AsahiSoftWareEngineer I am going to fix bugs

@grdsdev grdsdev added the python Pull requests that update Python code label Apr 4, 2025 — with Linear
@supabase supabase deleted a comment from brambhattabhishek Apr 9, 2025
@gayathriramanesh
Copy link

Hi @AsahiSoftWareEngineer Is this issue fixed?

@AsahiSoftWareEngineer
Copy link
Contributor Author

@gayathriramanesh Hi, I think that already fixed

@grdsdev
Copy link
Contributor

grdsdev commented May 20, 2025

Hey all, as discussed in #1096 this isn't a bug, it is just how Python works.

If you want to change a client's options you need to use the replace method in the option.

We'll make sure this gets included in our docs.

Thanks.

@grdsdev grdsdev closed this as completed May 20, 2025
silentworks added a commit that referenced this issue May 23, 2025
@rild-software
Copy link
Contributor

a deep copy don't looks like a clever option to copy the options content to the config instance class.

I had a bug with this released:

ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/uvicorn/protocols/http/h11_impl.py", line 403, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/starlette/applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 187, in __call__
    raise exc
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 165, in __call__
    await self.app(scope, receive, _send)
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/starlette/middleware/cors.py", line 85, in __call__
    await self.app(scope, receive, send)
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    raise exc
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
    await app(scope, receive, sender)
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/starlette/routing.py", line 714, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/starlette/routing.py", line 734, in app
    await route.handle(scope, receive, send)
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/starlette/routing.py", line 288, in handle
    await self.app(scope, receive, send)
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/starlette/routing.py", line 76, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    raise exc
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
    await app(scope, receive, sender)
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/starlette/routing.py", line 73, in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 291, in app
    solved_result = await solve_dependencies(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/fastapi/dependencies/utils.py", line 640, in solve_dependencies
    solved = await run_in_threadpool(call, **solved_result.values)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/starlette/concurrency.py", line 37, in run_in_threadpool
    return await anyio.to_thread.run_sync(func)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/anyio/to_thread.py", line 56, in run_sync
    return await get_async_backend().run_sync_in_worker_thread(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/anyio/_backends/_asyncio.py", line 2470, in run_sync_in_worker_thread
    return await future
           ^^^^^^^^^^^^
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/anyio/_backends/_asyncio.py", line 967, in run
    result = context.run(func, *args)
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ricardo/Dev/api_portalcannabis/app/core/database.py", line 54, in get_supabase
    return create_client(
           ^^^^^^^^^^^^^^
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/supabase/_sync/client.py", line 341, in create_client
    return SyncClient.create(
           ^^^^^^^^^^^^^^^^^^
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/supabase/_sync/client.py", line 103, in create
    client = cls(supabase_url, supabase_key, options)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ricardo/Dev/api_portalcannabis/.venv/lib/python3.12/site-packages/supabase/_sync/client.py", line 71, in __init__
    self.options = copy.deepcopy(options)
                   ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 162, in deepcopy
    y = _reconstruct(x, memo, *rv)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 259, in _reconstruct
    state = deepcopy(state, memo)
            ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 136, in deepcopy
    y = copier(x, memo)
        ^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 221, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
                             ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 162, in deepcopy
    y = _reconstruct(x, memo, *rv)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 259, in _reconstruct
    state = deepcopy(state, memo)
            ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 136, in deepcopy
    y = copier(x, memo)
        ^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 221, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
                             ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 162, in deepcopy
    y = _reconstruct(x, memo, *rv)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 259, in _reconstruct
    state = deepcopy(state, memo)
            ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 136, in deepcopy
    y = copier(x, memo)
        ^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 221, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
                             ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 162, in deepcopy
    y = _reconstruct(x, memo, *rv)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 259, in _reconstruct
    state = deepcopy(state, memo)
            ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 136, in deepcopy
    y = copier(x, memo)
        ^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 221, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
                             ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 162, in deepcopy
    y = _reconstruct(x, memo, *rv)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 259, in _reconstruct
    state = deepcopy(state, memo)
            ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 136, in deepcopy
    y = copier(x, memo)
        ^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 221, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
                             ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 162, in deepcopy
    y = _reconstruct(x, memo, *rv)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 259, in _reconstruct
    state = deepcopy(state, memo)
            ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 136, in deepcopy
    y = copier(x, memo)
        ^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 221, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
                             ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 162, in deepcopy
    y = _reconstruct(x, memo, *rv)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 259, in _reconstruct
    state = deepcopy(state, memo)
            ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 136, in deepcopy
    y = copier(x, memo)
        ^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 221, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
                             ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/copy.py", line 151, in deepcopy
    rv = reductor(4)
         ^^^^^^^^^^^
TypeError: cannot pickle '_thread.RLock' object

@rild-software
Copy link
Contributor

If I change the line 71 of supabase._sync.client.py from
self.options = copy.deepcopy(options)
to
self.options = copy.copy(options)

It's solve this problem

@rild-software
Copy link
Contributor

I will open a issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working python Pull requests that update Python code
Projects
None yet
Development

No branches or pull requests

4 participants