Skip to content

Commit 14f3a6c

Browse files
authored
Merge pull request #41 from mattmanley/add_priority_model
Add priority rule model
2 parents 5e5d2a7 + 9eb5c17 commit 14f3a6c

7 files changed

Lines changed: 233 additions & 1 deletion

File tree

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Welcome to MapRoulette's documentation!
1717
usage/models/project
1818
usage/models/challenge
1919
usage/models/task
20+
usage/models/priority_rule
2021
usage/exceptions
2122

2223
---------------
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Priority Rule Model
2+
=====================================================
3+
4+
.. autoclass:: maproulette.models.priority_rule.PriorityRule
5+
:members:
6+
7+
.. autoclass:: maproulette.models.priority_rule.PriorityRuleModel
8+
:members:
9+
10+
.. autoclass:: maproulette.models.priority_rule.Conditions
11+
:members:
12+
13+
.. autoclass:: maproulette.models.priority_rule.Types
14+
:members:
15+
:undoc-members:
16+
17+
.. autoclass:: maproulette.models.priority_rule.Conditions
18+
:members:
19+
:undoc-members:
20+
21+
.. autoclass:: maproulette.models.priority_rule.StringOperators
22+
:members:
23+
:undoc-members:
24+
25+
.. autoclass:: maproulette.models.priority_rule.NumericOperators
26+
:members:
27+
:undoc-members:

examples/create_challenge_from_model.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@
1616
# Adding required instruction
1717
challenge_data.instruction = "Do something"
1818

19+
# Let's create a basic rule to classify features with tags 'highway' = 'footway' to be high priority
20+
rule_1 = maproulette.PriorityRule(priority_value='highway.footway',
21+
priority_type=maproulette.priority_rule.Types.STRING,
22+
priority_operator=maproulette.priority_rule.StringOperators.EQUAL)
23+
24+
# Create a formal priority rule for the challenge
25+
challenge_data.high_priority_rule = maproulette.PriorityRuleModel(condition=maproulette.priority_rule.Conditions.OR,
26+
rules=rule_1
27+
).to_json()
28+
1929
# Adding example overpass QL input for challenge
2030
challenge_data.overpassQL = open('data/Example_OverpassQL_Query', 'r').read()
2131

maproulette/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from .models.project import ProjectModel
88
from .models.challenge import ChallengeModel
99
from .models.task import TaskModel
10+
from .models.priority_rule import PriorityRule, PriorityRuleModel
11+
from .models import priority_rule
1012
from .api.project import Project
1113
from .api.challenge import Challenge
1214
from .api.task import Task

maproulette/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
from .project import ProjectModel
22
from .challenge import ChallengeModel
33
from .task import TaskModel
4+
from .priority_rule import PriorityRule, PriorityRuleModel

maproulette/models/challenge.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,6 @@ def to_dict(self):
332332
"id": self._id,
333333
"name": self._name,
334334
"description": self._description,
335-
"deleted": self.description,
336335
"parent": self._parent,
337336
"instruction": self._instruction,
338337
"difficulty": self._difficulty,
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
"""This module contains the definition of a priority rule object in MapRoulette."""
2+
3+
import json
4+
from enum import Enum, auto
5+
6+
7+
class ExtendedEnum(Enum):
8+
def _generate_next_value_(name, start, count, last_values):
9+
return name.lower()
10+
11+
@classmethod
12+
def list(cls):
13+
return [i.value for i in cls]
14+
15+
16+
class Conditions(ExtendedEnum):
17+
"""An enumeration of valid logical conditions for a priority rule object"""
18+
OR = "OR"
19+
AND = "AND"
20+
21+
22+
class Types(ExtendedEnum):
23+
"""An enumeration of valid types for a priority rule object"""
24+
STRING = auto()
25+
INTEGER = auto()
26+
DOUBLE = auto()
27+
LONG = auto()
28+
29+
30+
class StringOperators(ExtendedEnum):
31+
"""An enumeration of valid string operators for a priority rule object"""
32+
EQUAL = auto()
33+
NOT_EQUAL = auto()
34+
CONTAINS = auto()
35+
NOT_CONTAINS = auto()
36+
IS_EMPTY = auto()
37+
IS_NOT_EMPTY = auto()
38+
39+
40+
class NumericOperators(ExtendedEnum):
41+
"""An enumeration of valid numeric operators for a priority rule object"""
42+
EQUAL_TO = "=="
43+
NOT_EQUAL_TO = "!="
44+
LESS_THAN = "<"
45+
LESS_THAN_OR_EQUAL = "<="
46+
GREATER_THAN = ">"
47+
GREATER_THAN_OR_EQUAL = ">="
48+
49+
50+
class PriorityRuleModel:
51+
"""A model for a priority rule definition in MapRoulette.
52+
53+
:param condition: the logical condition to use to string together multiple rules. The valid options for conditions
54+
are defined by the :class:`~maproulette.models.priority_rule.Conditions` enum.
55+
:type condition: Conditions or str
56+
:param rules: one or more rules to use for the priority rule definition. Rules should be instances of the
57+
:class:`~maproulette.models.priority_rule.PriorityRule` class.
58+
:type rules: PriorityRule or list
59+
"""
60+
61+
@property
62+
def condition(self):
63+
"""The condition to use to chain together multiple priority rules"""
64+
return self._condition
65+
66+
@condition.setter
67+
def condition(self, value):
68+
if isinstance(value, Conditions):
69+
self._condition = value.value
70+
else:
71+
if value not in Conditions.list():
72+
raise ValueError(f"Priority condition must be one of {Conditions.list()}.")
73+
self._condition = value
74+
75+
@property
76+
def rules(self):
77+
"""The list of priority rules to be used in the priority rule model"""
78+
return self._rules
79+
80+
@rules.setter
81+
def rules(self, value):
82+
self._rules = value
83+
84+
def __init__(self, condition, rules):
85+
"""The constructor for the PriorityRuleModel class"""
86+
self.condition = condition
87+
self.rules = list()
88+
if isinstance(rules, list):
89+
if len(rules) > 0:
90+
for i in rules:
91+
if isinstance(i, PriorityRule):
92+
self.rules.append(i.to_dict())
93+
else:
94+
raise ValueError("Rules must be PriorityRule instances")
95+
else:
96+
ValueError("Rule list cannot be empty")
97+
elif isinstance(rules, PriorityRule):
98+
self.rules.append(rules.to_dict())
99+
else:
100+
raise ValueError("Rules must be PriorityRule instances")
101+
102+
def to_dict(self):
103+
"""Converts all properties of a priority rule model object into a dictionary"""
104+
return {
105+
"condition": self._condition,
106+
"rules": self._rules
107+
}
108+
109+
def to_json(self):
110+
"""Converts all properties of a priority rule model object into a JSON object"""
111+
return json.dumps(self.to_dict())
112+
113+
114+
class PriorityRule:
115+
"""Definition for a single priority rule
116+
117+
:param priority_type: the data type for the priority rule. The valid options are defined by the
118+
:class:`~maproulette.models.priority_rule.Types` enum.
119+
:type priority_type: Types or str
120+
:param priority_operator: the operator to use for the priority rule. The valid options for string-type priority
121+
rules are defined by the :class:`~maproulette.models.priority_rule.StringOperators` enum and the valid options
122+
for numeric-type priority rules are defined by the :class:`~maproulette.models.priority_rule.NumericOperators`
123+
enum.
124+
:type priority_operator: NumericOperators or StringOperators or str
125+
:param priority_value: the value to use for the priority rule. This should be formatted like 'highway.footway' to
126+
indicate that any task with a 'highway' property equal to 'footway' should be considered for this rule. Multiple
127+
values can be specified using commas. Example: 'highway.footway,pedestrian'.
128+
:type priority_value: str
129+
"""
130+
131+
@property
132+
def priority_type(self):
133+
"""The type for the priority rule"""
134+
return self._priority_type
135+
136+
@priority_type.setter
137+
def priority_type(self, value):
138+
if isinstance(value, Types):
139+
self._priority_type = value.value
140+
elif value in Types.list():
141+
self._priority_type = value
142+
else:
143+
raise ValueError(f"Priority types must be one of {Types.list()}.")
144+
145+
@property
146+
def priority_operator(self):
147+
"""The operator to use for the priority rule"""
148+
return self._priority_operator
149+
150+
@priority_operator.setter
151+
def priority_operator(self, value):
152+
if self._priority_type == 'string':
153+
if isinstance(value, StringOperators):
154+
self._priority_operator = value.value
155+
elif value in StringOperators.list():
156+
self._priority_operator = value
157+
else:
158+
raise ValueError(f"String type priority operators must be one of {StringOperators.list()}.")
159+
else:
160+
if isinstance(value, NumericOperators):
161+
self._priority_operator = value.value
162+
elif value in NumericOperators.list():
163+
self._priority_operator = value
164+
else:
165+
raise ValueError(f"Numeric type priority operators must be one of {NumericOperators.list()}.")
166+
167+
@property
168+
def priority_value(self):
169+
"""The value for the priority rule"""
170+
return self._priority_value
171+
172+
@priority_value.setter
173+
def priority_value(self, value):
174+
self._priority_value = value
175+
176+
def __init__(self, priority_type, priority_operator, priority_value):
177+
"""The constructor for the PriorityRule class"""
178+
self.priority_type = priority_type
179+
self.priority_operator = priority_operator
180+
self.priority_value = priority_value
181+
182+
def to_dict(self):
183+
"""Converts all properties of a priority rule object into a dictionary"""
184+
return {
185+
"value": self._priority_value,
186+
"type": self._priority_type,
187+
"operator": self._priority_operator
188+
}
189+
190+
def to_json(self):
191+
"""Converts all properties of a priority rule object into a JSON object"""
192+
return json.dumps(self.to_dict())

0 commit comments

Comments
 (0)