-
Notifications
You must be signed in to change notification settings - Fork 152
/
handler.py
87 lines (68 loc) · 2.87 KB
/
handler.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# Copyright (c) 2020 All Rights Reserved
# Author: William H. Guss, Brandon Houghton
from abc import ABC, abstractmethod
from collections.abc import MutableMapping
from typing import Dict, Iterator, Any, List, Tuple
import typing
from xml.etree.ElementTree import Element
import gym
import jinja2
class Handler(ABC):
"""Defines the minimal interface for a MineRL handler.
At their core, handlers should specify unique identifiers
and a method for producing XML to be given in a mission XML.
"""
@abstractmethod
def to_string(self) -> str:
"""The unique identifier for the agent handler.
This is used for constructing aciton/observation spaces
and unioning different env specifications.
"""
raise NotImplementedError()
# @abstractmethod #TODO: This should be abstract per convention
# but this strict handler -> xml enforcement will happen
# with a pyxb update.
def xml_template(self) -> str:
"""Generates an XML representation of the handler.
This XML representaiton is templated via Jinja2 and
has access to all of the member variables of the class.
Note: This is not an abstract method so that
handlers without corresponding XML's can be combined in
handler groups with group based XML implementations.
"""
raise NotImplementedError()
def xml(self) -> str:
"""Gets the XML representation of Handler by templating
acccording to the xml_template class.
Returns:
str: the XML representation of the handler.
"""
var_dict = {}
for attr_name in dir(self):
if 'xml' not in attr_name:
var_dict[attr_name] = getattr(self, attr_name)
try:
env = jinja2.Environment(undefined=jinja2.StrictUndefined)
template = env.from_string(self.xml_template())
return template.render(var_dict)
except jinja2.UndefinedError as e:
# print the exception with traceback
message = e.message + "\nOccurred in {}".format(self)
raise jinja2.UndefinedError(message=message)
pass
def __or__(self, other):
"""
Checks to see if self and other have the same to_string
and if so returns self, otherwise raises an exception.
"""
assert self.to_string() == other.to_string(), (
"Incompatible handlers: {self} and {other}".format(**locals()))
return self
def __eq__(self, other):
"""
Checks to see if self and other have the same to_string
and if so returns self, otherwise raises an exception.
"""
return self.to_string() == other.to_string()
def __repr__(self):
return super().__repr__() + ":" + self.to_string()