# ADAPTED FROM https://github.com/openai/gym-http-api
import requests
import six.moves.urllib.parse as urlparse
import json
import os
import pkg_resources
import sys
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
class Client(object):
"""
Gym client to interface with gym_http_server
"""
def __init__(self, remote_base):
self.remote_base = remote_base
self.session = requests.Session()
self.session.headers.update({'Content-type': 'application/json'})
self.instance_id = None
def _parse_server_error_or_raise_for_status(self, resp):
j = {}
try:
j = resp.json()
except:
# Most likely json parse failed because of network error, not server error (server
# sends its errors in json). Don't let parse exception go up, but rather raise default
# error.
resp.raise_for_status()
if resp.status_code != 200 and "message" in j: # descriptive message from server side
raise ServerError(message=j["message"], status_code=resp.status_code)
resp.raise_for_status()
return j
def _post_request(self, route, data):
url = urlparse.urljoin(self.remote_base, route)
logger.info("POST {}\n{}".format(url, json.dumps(data)))
resp = self.session.post(urlparse.urljoin(self.remote_base, route),
data=json.dumps(data))
return self._parse_server_error_or_raise_for_status(resp)
def _get_request(self, route):
url = urlparse.urljoin(self.remote_base, route)
logger.info("GET {}".format(url))
resp = self.session.get(url)
return self._parse_server_error_or_raise_for_status(resp)
def env_create(self, token, env_id = "Run"):
route = '/v1/envs/'
data = {'env_id': env_id,
'token': token,
'version': pkg_resources.get_distribution("osim-rl").version }
try:
resp = self._post_request(route, data)
except ServerError as e:
sys.exit(e.message)
self.instance_id = resp['instance_id']
self.env_monitor_start("tmp", force=True)
return self.env_reset()
def env_reset(self):
route = '/v1/envs/{}/reset/'.format(self.instance_id)
resp = self._post_request(route, None)
observation = resp['observation']
return observation
def env_step(self, action, render=False):
route = '/v1/envs/{}/step/'.format(self.instance_id)
data = {'action': action, 'render': render}
resp = self._post_request(route, data)
observation = resp['observation']
reward = resp['reward']
done = resp['done']
info = resp['info']
return [observation, reward, done, info]
def env_monitor_start(self, directory,
force=False, resume=False, video_callable=False):
route = '/v1/envs/{}/monitor/start/'.format(self.instance_id)
data = {'directory': directory,
'force': force,
'resume': resume,
'video_callable': video_callable}
self._post_request(route, data)
def submit(self):
route = '/v1/envs/{}/monitor/close/'.format(self.instance_id)
result = self._post_request(route, None)
if result['reward']:
print("Your total reward from this submission: %f" % result['reward'])
else:
print("There was an error in your submission. Please contact administrators.")
route = '/v1/envs/{}/close/'.format(self.instance_id)
self.env_close()
def env_close(self):
route = '/v1/envs/{}/close/'.format(self.instance_id)
self._post_request(route, None)
class ServerError(Exception):
def __init__(self, message, status_code=None):
Exception.__init__(self)
print('ServerErrorPrint',message,status_code)
self.message = message
if status_code is not None:
self.status_code = status_code