Use dependency method in Custom extensions not work

Sanic v22.9.1
python: 3.9.15
packages: sanic-routing==22.8.0, sanic-ext==22.9.1

I defined the redis extension myself, and the code is as follows:

class RedisPlugin(Extension):
    name = 'redis'

    def startup(self, bootstrap) -> None:
        if getattr(self.app.config, 'NACOS'):
            self.app.before_server_start(self.set_redis_config)
        if self.included():
            self.app.after_server_start(self.create_pool)
            self.app.before_server_stop(self.disconnect_pool)
            self.app.on_response(self.close_before_response)
        return super().startup(bootstrap)

    @staticmethod
    async def create_pool(app: Sanic):
        """服务启动后创建redis连接池,并进行redis依赖注入

        Args:
            app (Sanic): sanic app
        """
        config = app.ctx.redis_config
        if config.get('url'):
            url = config.pop('url')
            pool = redis.ConnectionPool.from_url(url)
            config['connection_pool'] = pool
            redis_instance = redis.Redis(
                auto_close_connection_pool=False,
                connection_pool=pool
            )
        else:
            pool = redis.ConnectionPool.from_url(f"redis://:{config['password']}@{config['host']}:{config['port']}")
            redis_instance = redis.Redis(
                auto_close_connection_pool=False,
                connection_pool=pool
            )
        redis_proxy = RedisPool(redis_instance)
        app.ext.dependency(redis_proxy, 'redis')
        app.ctx.redis_session_token = redis_session.set(redis_instance)

    @staticmethod
    async def disconnect_pool(app: Sanic):
        """应用关闭前强关所有连接

        Args:
            app (Sanic): sanic app
        """
        await app.ctx.redis.connection_pool.disconnect()

    @staticmethod
    async def close_before_response(request: Request, response: HTTPResponse):
        """请求返回前关闭当此redis session

        Args:
            request (Request): sanic request
            response (HTTPResponse): sanic response
        """
        session_token = request.app.ctx.redis_session_token
        redis_session.reset(session_token)
        await request.app.ctx.redis.close()

    @staticmethod
    async def set_redis_config(app: Sanic):
        """支持nacos时,服务器端将redis配置信息写入配置中心

        Args:
            app (Sanic): sanic app
        """
        nacos_client = NacosClient()
        res = await nacos_client.get_config('redis', app.config.NACOS_GROUP, app.config.NACOS_NAMESPACE)
        if res[0]:
            config = res[0]
        else:
            config = get_local_redis_config(app)
        app.ctx.redis_config = config

    def included(self):
        return self.app.config.CACHE_CONFIG

The dependency method is used

app.ext.dependency(redis_proxy, 'redis')

I also saw the log on startup

[2022-12-03 16:23:19 +0800] [27159] [INFO]   > redis

When you use a dependency object intended to use redis in an api method, you are prompted for missing keyword arguments

    @openapi.definition(exclude=True)
    async def post(self, request: Request, redis: RedisPool) -> HTTPResponse:
        ...
post() missing 1 required positional argument: 'redis'

I removed the redis argument and printed app.ctx.__dict__,Found that ‘_dependencies’ already has a redis object but cannot be used

{'auth': <sanic_jwt.authentication.Authentication object at 0x7f25b1587c40>, '_dependencies': namespace(redis=<framework.cache_ext.redis_plugin.RedisPool object at 0x7f25aef694c0>), 'cors': CORSSettings(allow_headers=frozenset({'*'}), allow_methods=frozenset({'options', 'post', 'put', 'head', 'patch', 'get', 'delete'}), allow_origins=(), always_send=True, automatic_options=True, expose_headers=frozenset(), max_age='5', send_wildcard=False, supports_credentials=False)}

You are using the dependency method improperly. Remove the second argument.

I’ll change it to this

app.ext.dependency(redis_proxy)

I get the same error

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/sanic/app.py", line 924, in handle_request
    response = handler(request, **request.match_info)
  File "/usr/local/lib/python3.9/site-packages/sanic/views.py", line 96, in view
    return self.dispatch_request(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/sanic/views.py", line 86, in dispatch_request
    return handler(request, *args, **kwargs)
TypeError: post() missing 1 required positional argument: 'redis'

I hope you can help me look at this problem when you are free

Yes, I will hopefully today. I have been very busy.

Without having your full code, it is tough to know exactly what is going on. But, here is a barebones structure that you can try and reuse for your own purpose.

class RedisProxy:
    ...


class RedisPlugin(Extension):
    name = "redis"

    def startup(self, bootstrap) -> None:
        if getattr(self.app.config, "NACOS", True):
            self.app.before_server_start(self.set_redis_config)
        if self.included():
            self.app.after_server_start(self.create_pool)
            self.app.before_server_stop(self.disconnect_pool)
            self.app.on_response(self.close_before_response)
        return super().startup(bootstrap)

    @staticmethod
    async def create_pool(app: Sanic):
        print("create_pool")

        app.ext.dependency(RedisProxy())

    @staticmethod
    async def disconnect_pool(app: Sanic):
        print("disconnect_pool")

    @staticmethod
    async def close_before_response(request: Request, response: HTTPResponse):
        print("close_before_response")

    @staticmethod
    async def set_redis_config(app: Sanic):
        print("set_redis_config")

    def included(self):
        return True


app.extend(extensions=[RedisPlugin])


@app.get("/")
async def handler(request: Request, redis: RedisProxy):
    return json({"redis": redis.__class__.__name__})

Using this method can be used
That error occurs if you use method Extend.register

Looks like this is a 22.9 bug
@ahopkins