144

Does anyone know why I can't overwrite an existing endpoint function if i have two url rules like this

app.add_url_rule('/',
                 view_func=Main.as_view('main'),
                 methods=["GET"])

app.add_url_rule('/<page>/',
                 view_func=Main.as_view('main'),
                 methods=["GET"])

Traceback:

Traceback (most recent call last): 
  File "demo.py", line 20, in <module> methods=["GET"]) 
  File ".../python2.6/site-packages/flask‌​/app.py", 
    line 62, in wrapper_func return f(self, *args, **kwargs) 
  File ".../python2.6/site-packages/flask‌​/app.py", 
    line 984, in add_url_rule 'existing endpoint function: %s' % endpoint)  
AssertionError: View function mapping is overwriting an existing endpoint 
    function: main
Paulo Scardine
  • 73,447
  • 11
  • 124
  • 153
Kimmy
  • 3,787
  • 5
  • 22
  • 20
  • Are you asking how you can, or why you can? – Michael Davis Jun 23 '13 at 00:23
  • 5
    why it does not work I'm following a tutorial – Kimmy Jun 23 '13 at 00:26
  • 1
    If someone is curious to know why Flask has this boundation of unique view names see my answer to a similar question: https://stackoverflow.com/a/47558985/4440675 This answer explains what logic goes behind having a unique name for each method. – Amit Tripathi Nov 29 '17 at 18:28

18 Answers18

209

This same issue happened to me when I had more than one API function in the module and tried to wrap each function with 2 decorators:

  1. @app.route()
  2. My custom @exception_handler decorator

I got this same exception because I tried to wrap more than one function with those two decorators:

@app.route("/path1")
@exception_handler
def func1():
    pass

@app.route("/path2")
@exception_handler
def func2():
    pass

Specifically, it is caused by trying to register a few functions with the name wrapper:

def exception_handler(func):
  def wrapper(*args, **kwargs):
    try:
        return func(*args, **kwargs)
    except Exception as e:
        error_code = getattr(e, "code", 500)
        logger.exception("Service exception: %s", e)
        r = dict_to_json({"message": e.message, "matches": e.message, "error_code": error_code})
        return Response(r, status=error_code, mimetype='application/json')
  return wrapper

Changing the name of the function solved it for me (wrapper.__name__ = func.__name__):

def exception_handler(func):
  def wrapper(*args, **kwargs):
    try:
        return func(*args, **kwargs)
    except Exception as e:
        error_code = getattr(e, "code", 500)
        logger.exception("Service exception: %s", e)
        r = dict_to_json({"message": e.message, "matches": e.message, "error_code": error_code})
        return Response(r, status=error_code, mimetype='application/json')
  # Renaming the function name:
  wrapper.__name__ = func.__name__
  return wrapper

Then, decorating more than one endpoint worked.

Ian Ash
  • 1,087
  • 11
  • 23
Roei Bahumi
  • 3,433
  • 2
  • 20
  • 19
  • 47
    You can also use [`functools.wraps`](https://docs.python.org/2/library/functools.html#functools.wraps) to achieve the function rename. – ryannjohnson Apr 02 '17 at 22:46
  • 4
    I had to use `wrapper.__name__` instead of `wrapper.func_name`. Perhaps this is a difference between python2 and python3? – Resonance Jan 30 '18 at 11:36
  • 2
    That was the problem in my flask restful API using decorators. `wrapper.__name__ = func.__name__` before calling wrapper solved the problem. – Tom Wojcik Apr 05 '18 at 09:46
  • This is linked to the function being called `wrapper`, but _any_ name for the inside function will cause this issue. The answer actually does not explain why, though. Is Flask registering this anew for each method that has been decorated and thus detects the "duplicate" or what is the root cause of this? – kontur Jan 02 '22 at 10:54
  • this is a bug of flask! – marti_ Jan 19 '23 at 13:42
  • this answer should definitely be updated to use wraps as @ryannjohnson said – Tommy Aug 03 '23 at 19:25
77

Your view names need to be unique even if they are pointing to the same view method.

app.add_url_rule('/',
                 view_func=Main.as_view('main'),
                 methods = ['GET'])

app.add_url_rule('/<page>/',
                 view_func=Main.as_view('page'),
                 methods = ['GET'])
Michael Davis
  • 2,350
  • 2
  • 21
  • 29
  • In other words, the $VIEW_NAME in `.as_view($VIEW_NAME)` method call should be passed in as a unique string name. – Devy Apr 14 '20 at 23:52
48

For users that use @app.route it is better to use the key-argument endpoint rather then chaning the value of __name__ like Roei Bahumi stated. Taking his example will be:

@app.route("/path1", endpoint='func1')
@exception_handler
def func1():
    pass

@app.route("/path2", endpoint='func2')
@exception_handler
def func2():
    pass
Community
  • 1
  • 1
Uri Shalit
  • 2,198
  • 2
  • 19
  • 29
  • 2
    This is an excellent answer. I would just like to point out that providing the endpoint the same as actual function name is not required. You can put anything in the endpoint as long as it doesn't have a conflict. Ex. I have a situation where I am generating a function (3 times) using higher order functions, and I had to generate the endpoint name too to keep them unique. – Ishan Jan 23 '22 at 08:17
  • Best answer, it solved my issue as well :-) – toshiro92 Mar 16 '22 at 02:58
  • This is great to know to add `endpoint=` and in my situation there simply was duplicate function name, so if people are reading this, be sure to check to make sure that function names are not being duplicated as we cut and paste boiler plate codes a lot. – Manabu Tokunaga Jun 25 '23 at 01:07
16

This can happen also when you have identical function names on different routes.

Joseph
  • 307
  • 2
  • 12
  • 1
    This saved me, thanks! I knew it was simple but wasn't sure what had gone wrong (serves me right for copying functions) – Matthew Foulk Oct 27 '21 at 20:45
13

Adding @wraps(f) above the wrapper function solved my issue.

def list_ownership(f):
    @wraps(f)
    def decorator(*args,**kwargs):
        return f(args,kwargs)
    return decorator
Tajs
  • 521
  • 7
  • 18
12

Flask requires you to associate a single 'view function' with an 'endpoint'. You are calling Main.as_view('main') twice which creates two different functions (exactly the same functionality but different in memory signature). Short story, you should simply do

main_view_func = Main.as_view('main')

app.add_url_rule('/',
             view_func=main_view_func,
             methods=["GET"])

app.add_url_rule('/<page>/',
             view_func=main_view_func,
             methods=["GET"])
dtheodor
  • 4,894
  • 3
  • 22
  • 27
8

I would just like to add to this a more 'template' type solution.

def func_name(f):
    def wrap(*args, **kwargs):
        if condition:
            pass
        else:
            whatever you want
        return f(*args, **kwargs)
    wrap.__name__ = f.__name__
    return wrap

would just like to add a really interesting article "Demystifying Decorators" I found recently: https://sumit-ghosh.com/articles/demystifying-decorators-python/

imbatman
  • 508
  • 5
  • 16
5

This is issue for me was from an (breaking) update to flask-jwt-extended (version 4.x.x and up) used in a basic api I wrote a year ago and am now incorporating into a project.

@jwt_required to @jwt_required()

popandpeek
  • 51
  • 1
  • 1
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/30747228) – Sercan Jan 09 '22 at 02:33
  • This was the cause of the error message in the question (although not quite the same situation) and this was the first Google result. – coderforlife Jan 03 '23 at 19:13
2

There is a fix for Flask issue #570 introduced recenty (flask 0.10) that causes this exception to be raised.

See https://github.com/mitsuhiko/flask/issues/796

So if you go to flask/app.py and comment out the 4 lines 948..951, this may help until the issue is resovled fully in a new version.

The diff of that change is here: http://github.com/mitsuhiko/flask/commit/661ee54bc2bc1ea0763ac9c226f8e14bb0beb5b1

plaes
  • 31,788
  • 11
  • 91
  • 89
yassen
  • 65
  • 2
  • 3
    Re: "until the issue is resolved fully in a new version": There is no "issue" to be resolved. As the issue discussion showed, the raising of an exception in the case of the code in the question is the expected result. As explained in the accepted answer, the endpoints are in conflict. This is a fault in the code of the user of Flask, NOT in Flask itself. – Mark Hildreth Jan 30 '14 at 15:43
2

If you think you have unique endpoint names and still this error is given then probably you are facing issue. Same was the case with me.

This issue is with flask 0.10 in case you have same version then do following to get rid of this:

sudo pip uninstall flask
sudo pip install flask=0.9
shrishinde
  • 3,219
  • 1
  • 20
  • 31
2

maybe something contains no difference

  1. check url
  2. check function name
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 03 '22 at 10:53
2

I'm working on a similar problem and I managed to get rid of it by returning the wrapper funcion, which wasn't being done before:

def decorator_func(func_to_decorate):
    def wrapper_func():
        return func_to_decorate
    return wrapper_func     # I wasn't returning wrapper func!
Kubinha
  • 21
  • 3
1

Your view names need to be unique even if they are pointing to the same view method, or you can add from functools import wraps and use @wraps https://docs.python.org/2/library/functools.html

Andrii
  • 11
  • 3
1

use flask 0.9 instead use the following commands sudo pip uninstall flask

sudo pip install flask==0.9
Joshua Johns
  • 340
  • 1
  • 3
  • 10
1

In case you are using flask on python notebook, you need to restart kernel everytime you make changes in code

imok1948
  • 81
  • 1
  • 3
1

I encountered the same AssertionError, but have not seen a solution here. In my case, I run a decorated function in a Jupyter cell twice, then the error was caused by running an endpoint function with the same name as an existing running endpoint function.

Lerner Zhang
  • 6,184
  • 2
  • 49
  • 66
0

This can also happen if you have selected your debugger as "Python: File" instead of "Python: Flask", making it "Python: Flask" helped me get rid of the said error.

Julia Meshcheryakova
  • 3,162
  • 3
  • 22
  • 42
0

For those that come here later.

To expand on the comment that ryannjohnson left on this answer.

When you use the @wraps() function from the functools library, as far as I understand, it essentially allows you to achieve the same result as using wrapper.__name__ = func.__name__ except it's more concise and it doesn't require you to manually perform the renaming yourself.

Just wanted to add an answer here to make it easier to find this info for those that might not see the comments and are more focused on the submitted answers.

KyleDev
  • 11
  • 1
  • 5