2015-05-22 6 views
2

Итак, у меня возникла какая-то странная ошибка с flask-restful и fields.Url, что я не могу понять, почему это происходит, так как это происходит случайным образом. Обычно, когда я запускаю свое приложение, оно, похоже, не происходит, и он просто не выполняется случайным образом в тестах.Случайный 'werkzeug.routing.BuildError' при тестировании приложения с флягой-restful

Следует отметить, что это происходит только при запросах POST и работает с запросами GET.

Для справки, весь код находится по адресу https://github.com/Tehnix/cred-server (с прилагаемым временным исправлением).

Ошибка

кажется, что создание поля URL не удается, в то время как сортировочная мой объект данных. Полная ошибка в конце вопроса.

File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/werkzeug/routing.py", line 1678, in build 
    raise BuildError(endpoint, values, method) 
werkzeug.routing.BuildError: ('events_item', {'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x102df6d68>}, None) 

Виновник

конечная точка определяется как,

# FILE: cred/routes.py 
api.add_resource(EventsItem, '/events/<int:event_id>', endpoint='events_item') 

Я использую следующий маршал моего объекта SQLAlchemy,

# FILE: cred/resources/events.py 
simple_event_fields = { 
    'id': flask.ext.restful.fields.Integer(attribute='event_id'), 
    'uri': flask.ext.restful.fields.Url('events_item', absolute=True), 
} 

где fields.Url, кажется, не в состоянии по какой-то причине. И, наконец, ресурс, который обрабатывает запрос POST,

# FILE: cred/resources/events.py 
class Events(flask.ext.restful.Resource): 
    """Methods going to the /events route.""" 

    def post(self): 
     """Create a new event and return the id and uri of the event.""" 
     # Parse the POST args using the parser from flask-restful into event_args 
     # ... 
     # Create the event in the database 
     event = EventModel(
      self.client, 
      event_args['name'], 
      event_args['location'], 
      event_args['action'], 
      event_args['value'] 
     ) 
     # Save the event in the database 
     db.session.add(event) 
     db.session.commit() 
     # Finally, convert the event object into our format by marshalling it, 
     # and returning the JSON object 
     return { 
      'status': 201, 
      'message': 'Created Event', 
      'event': marshal(event, simple_event_fields) 
     }, 201 

Как сказано в начале, это происходит только при выполнении тестов (и только иногда), так что это не критически само по себе, но это было бы еще будьте добры, чтобы не повторять тесты несколько раз, чтобы проверить, не уходит ли это, и все остальные проходят.

Тестовый случай

Я использую колбовую тестирования, но это еще предстоит довольно много UnitTests,

# FILE: cred/test/test_events.py 
test_event = { 
    'event': { 
     'name': 'Temperature', 
     'location': 'Living Room', 
     'action': 'Temperature Above Setting', 
     'value': '5' 
    } 
} 

class BaseTestCase(flask.ext.testing.TestCase): 
    SQLALCHEMY_DATABASE_URI = "sqlite://" 
    TESTING = True 

    def create_app(self): 
     return app 

    def setUp(self): 
     """Create a SQLite database for quick testing.""" 
     cred.database.init_db(cred.database.db) 
     self.session_key = None 

    def tearDown(self): 
     """Close the database file and unlink it.""" 
     cred.database.db.session.remove() 
     cred.database.db.drop_all() 

    @testutil.authenticate('write') 
    def test_posting_a_complete_event(self): 
     """Create a valid new event.""" 
     # Post the request to the test server 
     response = self.client.post(
      '/events', 
      data=json.dumps(test_event), 
      content_type='application/json' 
     ) 
     resp = json.loads(response.data.decode('utf-8')) 
     # Run self.assertEqual on all items in a dict 
     testutil.assertEqual(self, { 
      response.status_code: 201, 
      resp['status']: 201, 
      resp['message']: 'Created Event', 
      'id' in resp['event']: True, 
      'uri' in resp['event']: True 
     }) 

В вышеприведенном test_posting_a_complete_event потерпит неудачу случайным образом из-за uri пункта.

Полный вывод ошибок из nosetests

====================================================================== 
ERROR: Create a valid new event. 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/cred/test/util.py", line 34, in wrapped 
    fun(self, *args, **kwargs) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/cred/test/test_events.py", line 37, in test_posting_a_complete_event 
    resp = json.loads(response.data.decode('utf-8')) 
    File "/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/json/__init__.py", line 318, in loads 
    return _default_decoder.decode(s) 
    File "/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/json/decoder.py", line 343, in decode 
    obj, end = self.raw_decode(s, idx=_w(s, 0).end()) 
    File "/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/json/decoder.py", line 361, in raw_decode 
    raise ValueError(errmsg("Expecting value", s, err.value)) from None 
nose.proxy.ValueError: Expecting value: line 1 column 1 (char 0) 
-------------------- >> begin captured logging << -------------------- 
cred-server: ERROR: Exception on /events [POST] 
Traceback (most recent call last): 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask/app.py", line 1817, in wsgi_app 
    response = self.full_dispatch_request() 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask/app.py", line 1477, in full_dispatch_request 
    rv = self.handle_user_exception(e) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask_restful/__init__.py", line 265, in error_router 
    return original_handler(e) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask/app.py", line 1381, in handle_user_exception 
    reraise(exc_type, exc_value, tb) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask/_compat.py", line 33, in reraise 
    raise value 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask/app.py", line 1475, in full_dispatch_request 
    rv = self.dispatch_request() 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask/app.py", line 1461, in dispatch_request 
    return self.view_functions[rule.endpoint](**req.view_args) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask_restful/__init__.py", line 446, in wrapper 
    resp = resource(*args, **kwargs) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask/views.py", line 84, in view 
    return self.dispatch_request(*args, **kwargs) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask_restful/__init__.py", line 550, in dispatch_request 
    resp = meth(*args, **kwargs) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/cred/resources/events.py", line 88, in post 
    'event': marshal(event, simple_event_fields) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask_restful/__init__.py", line 603, in marshal 
    return OrderedDict([(envelope, OrderedDict(items))]) if envelope else OrderedDict(items) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/collections/__init__.py", line 56, in __init__ 
    self.__update(*args, **kwds) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/bin/../lib/python3.4/_collections_abc.py", line 602, in update 
    for key, value in other: 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask_restful/__init__.py", line 602, in <genexpr> 
    for k, v in fields.items()) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask_restful/fields.py", line 294, in output 
    o = urlparse(url_for(endpoint, _external=self.absolute, **data)) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask/helpers.py", line 312, in url_for 
    return appctx.app.handle_url_build_error(error, endpoint, values) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask/app.py", line 1641, in handle_url_build_error 
    reraise(exc_type, exc_value, tb) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask/_compat.py", line 33, in reraise 
    raise value 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/flask/helpers.py", line 305, in url_for 
    force_external=external) 
    File "/Users/tehnix/Dropbox/github/Tehnix/cred/env/lib/python3.4/site-packages/werkzeug/routing.py", line 1678, in build 
    raise BuildError(endpoint, values, method) 
werkzeug.routing.BuildError: ('events_item', {'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x102df6d68>}, None) 
+0

Вы можете добавить свой тест? – nathancahill

+0

Добавлено :) Я обнаружил, что это * только * происходит на POST-запросах, а не на любом из запросов GET. Ручное построение и добавление поля 'uri' к маршаллированному результату будет проходить все тесты все время, но это похоже на обходной путь, и я бы скорее выяснил, почему он не может начаться с:/ – Tehnix

+0

И можете ли вы добавить' test_event' ? – nathancahill

ответ

0

Вам нужно назначить events_items внутри 'fields.Url' перед его возвращением.

Эта ссылка How to add fields url for nested output fields in flask restful объясняет больше

Но если вы используете Blueprints, добавьте "." к fields.Url например 'uri': fields.Url('.events_items')

исх https://github.com/flask-restful/flask-restful/issues/266#issuecomment-46678118

 Смежные вопросы

  • Нет связанных вопросов^_^