overthesun / simoc

A scalable model of an interactive, off-world community
https://ngs.simoc.space/
GNU General Public License v3.0
2 stars 2 forks source link

Handle None values in /new_game #94

Open ezio-melotti opened 5 years ago

ezio-melotti commented 5 years ago

I'm currently fixing this in the front-end, but it would be good to fix it in the backend as well to avoid future problems.

I tried this send an empty config:

{"game_config":{
    "duration":{"value":null,"type":"none"},
    "human_agent":{"amount":null},
    "food_storage":{"amount":null},
    "solar_pv_array_mars":{"amount":null},
    "power_storage":{"amount":null},
    "eclss":{"amount":null},
    "single_agent":1,
    "plants":[{"species":"","amount":null}]}}

Since the food_storage is null, the server failed with:

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib/python3.6/dist-packages/flask_login/utils.py", line 261, in decorated_view
    return func(*args, **kwargs)
  File "/simoc/simoc_server/views.py", line 115, in new_game
    game_config = convert_configuration(json.loads(request.data)["game_config"])
  File "/simoc/simoc_server/front_end_routes.py", line 140, in convert_configuration
    (game_config["food_storage"]["amount"]) / (int(food_storage_capacity)))
TypeError: unsupported operand type(s) for /: 'NoneType' and 'int'

If I enter a value for the food_storage it fails with:

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib/python3.6/dist-packages/flask_login/utils.py", line 261, in decorated_view
    return func(*args, **kwargs)
  File "/simoc/simoc_server/views.py", line 115, in new_game
    game_config = convert_configuration(json.loads(request.data)["game_config"])
  File "/simoc/simoc_server/front_end_routes.py", line 176, in convert_configuration
    for y in range(1, int(power_storage_amount) + 1):
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'

and so on for the other missing values.

I see two possible fixes: 1) assume that null values are 0 and start the simulation 2) return an error to the frontend (e.g. "missing value for food storage")

The 1st option might be better (at least for now since I don't have a proper error handling in the frontend).

@kstaats : is the 1st option fine? @iurii-milovanov : can you go through all the values, set them to null, and make sure that the server doesn't fail with an HTTP 5XX error?

ezio-melotti commented 5 years ago

I updated the frontend to send 0s instead of nulls, but still got this error (the first half is from celery, the second half from flask):

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/celery/app/trace.py", line 385, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/celery/app/trace.py", line 648, in __protected_call__
    return self.run(*args, **kwargs)
  File "/simoc/celery_worker/tasks.py", line 66, in new_game
    game_runner_manager.new_game(user, game_runner_init_params)
  File "/simoc/simoc_server/game_runner.py", line 349, in new_game
    game_runner = GameRunner.from_new_game(user, game_runner_init_params)
  File "/simoc/simoc_server/game_runner.py", line 141, in from_new_game
    game_runner_init_params.agent_init_recipe)
  File "/simoc/simoc_server/agent_model/agent_model.py", line 309, in create_new
    agent_init_recipe.init_agents(model)
  File "/simoc/simoc_server/agent_model/agent_model.py", line 771, in init_agents
    amount=amount))
  File "/simoc/simoc_server/agent_model/agents/core.py", line 225, in __init__
    super(GeneralAgent, self).__init__(*args, **kwargs)
  File "/simoc/simoc_server/agent_model/agents/core.py", line 150, in __init__
    super(EnclosedAgent, self).__init__(*args, **kwargs)
  File "/simoc/simoc_server/agent_model/agents/core.py", line 55, in __init__
    self._load_agent_type_attributes()
  File "/simoc/simoc_server/agent_model/agents/core.py", line 67, in _load_agent_type_attributes
    self.agent_class = agent_type.agent_class
AttributeError: 'NoneType' object has no attribute 'agent_class'
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib/python3.6/dist-packages/flask_login/utils.py", line 261, in decorated_view
    return func(*args, **kwargs)
  File "/simoc/simoc_server/views.py", line 119, in new_game
    result = tasks.new_game.delay(get_standard_user_obj().username, game_config).get(timeout=60)
  File "/usr/local/lib/python3.6/dist-packages/celery/result.py", line 226, in get
    on_message=on_message,
  File "/usr/local/lib/python3.6/dist-packages/celery/backends/asynchronous.py", line 190, in wait_for_pending
    return result.maybe_throw(callback=callback, propagate=propagate)
  File "/usr/local/lib/python3.6/dist-packages/celery/result.py", line 331, in maybe_throw
    self.throw(value, self._to_remote_traceback(tb))
  File "/usr/local/lib/python3.6/dist-packages/celery/result.py", line 324, in throw
    self.on_ready.throw(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/vine/promises.py", line 244, in throw
    reraise(type(exc), exc, tb)
  File "/usr/local/lib/python3.6/dist-packages/vine/five.py", line 195, in reraise
    raise value
AttributeError: 'NoneType' object has no attribute 'agent_class'

This is the request I sent:

{"game_config":{
    "duration":{"type":"none","value":0},
    "human_agent":{"amount":0},
    "food_storage":{"amount":0},
    "solar_pv_array_mars":{"amount":0},
    "power_storage":{"amount":0},
    "eclss":{"amount":0},
    "single_agent":1,
    "plants":[{"species":"","amount":0}]}
}

This seems to be caused by the empty plant. In this case I would also suggest to ignore the plant if the name is empty, at least for now.

kstaats commented 5 years ago

Yes, option #1 is fine. We can send error messages in the future.

On 9/30/19 1:57 AM, Ezio Melotti wrote:

I'm currently fixing this in the front-end, but it would be good to fix it in the backend as well to avoid future problems.

I tried this send an empty config:

{"game_config":{
     "duration":{"value":null,"type":"none"},
     "human_agent":{"amount":null},
     "food_storage":{"amount":null},
     "solar_pv_array_mars":{"amount":null},
     "power_storage":{"amount":null},
     "eclss":{"amount":null},
     "single_agent":1,
     "plants":[{"species":"","amount":null}]}}

Since the food_storage is null, the server failed with:

Traceback (most recent call last):
   File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1949, in full_dispatch_request
     rv = self.dispatch_request()
   File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1935, in dispatch_request
     return self.view_functions[rule.endpoint](**req.view_args)
   File "/usr/local/lib/python3.6/dist-packages/flask_login/utils.py", line 261, in decorated_view
     return func(*args, **kwargs)
   File "/simoc/simoc_server/views.py", line 115, in new_game
     game_config = convert_configuration(json.loads(request.data)["game_config"])
   File "/simoc/simoc_server/front_end_routes.py", line 140, in convert_configuration
     (game_config["food_storage"]["amount"]) / (int(food_storage_capacity)))
TypeError: unsupported operand type(s) for /: 'NoneType' and 'int'

If I enter a value for the food_storage it fails with:

Traceback (most recent call last):
   File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1949, in full_dispatch_request
     rv = self.dispatch_request()
   File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1935, in dispatch_request
     return self.view_functions[rule.endpoint](**req.view_args)
   File "/usr/local/lib/python3.6/dist-packages/flask_login/utils.py", line 261, in decorated_view
     return func(*args, **kwargs)
   File "/simoc/simoc_server/views.py", line 115, in new_game
     game_config = convert_configuration(json.loads(request.data)["game_config"])
   File "/simoc/simoc_server/front_end_routes.py", line 176, in convert_configuration
     for y in range(1, int(power_storage_amount) + 1):
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'

and so on for the other missing values.

I see two possible fixes: 1) assume that null values are 0 and start the simulation 2) return an error to the frontend (e.g. "missing value for food storage")

The 1st option might be better (at least for now since I don't have a proper error handling in the frontend).

@kstaats : is the 1st option fine? @iurii-milovanov : can you go through all the values, set them to null, and make sure that the server doesn't fail with an HTTP 5XX error?