Remove most references to old teams config scheme (#22238)
This is a follow up from MST-16, which was commited
in 3858036a4e.
Changes:
* Enrich course teams_configuration from a plain Dict
to a custom XBlock field that uses the new TeamsConfig
wrapper class.
* Remove teams_conf property from course, as the previous
change made it redundant.
* Update teams_enabled implementation.
* Remove teams_max_size field from course, which is
no longer semantically correct, as max team size
is now defined on a teamset level.
* Remove teams_topics in order to discourage use of raw
teams config dict.
* Add convenience properties teamsets and teamsets_by_id
to course.
* Allow periods and spaces in teamset IDs to avoid breaking
existing course teams.
Some parts of the code still use the old raw config data
(identifiable by searching "cleaned_data_old_format"),
which we expect to be slowly factored away as we build
new teams features. MST-40 has been created to remove any
remaining references if necessary.
MST-18
* fix: bokchoy test
* fix: remove pdb break
This commit is contained in:
@@ -41,12 +41,25 @@ class TeamsConfig(object):
|
||||
"""
|
||||
Return developer-helpful string.
|
||||
"""
|
||||
return "<{} max_team_size={} teamsets=[{}]>".format(
|
||||
return "<{} default_max_team_size={} teamsets=[{}]>".format(
|
||||
self.__class__.__name__,
|
||||
self.max_team_size,
|
||||
self.default_max_team_size,
|
||||
", ".join(repr(teamset) for teamset in self.teamsets),
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
"""
|
||||
Define equality based on cleaned data.
|
||||
"""
|
||||
return isinstance(other, self.__class__) and self.cleaned_data == other.cleaned_data
|
||||
|
||||
def __ne__(self, other):
|
||||
"""
|
||||
Overrides default inequality to be the inverse of our custom equality.
|
||||
Safe to remove once we're in Python 3 -- Py3 does this for us.
|
||||
"""
|
||||
return not self.__eq__(other)
|
||||
|
||||
@property
|
||||
def source_data(self):
|
||||
"""
|
||||
@@ -60,7 +73,7 @@ class TeamsConfig(object):
|
||||
JSON-friendly dictionary containing cleaned data from this TeamsConfig.
|
||||
"""
|
||||
return {
|
||||
'max_team_size': self.max_team_size,
|
||||
'max_team_size': self.default_max_team_size,
|
||||
'team_sets': [
|
||||
teamset.cleaned_data for teamset in self.teamsets
|
||||
]
|
||||
@@ -72,10 +85,10 @@ class TeamsConfig(object):
|
||||
JSON-friendly dictionary containing cleaned data from this TeamsConfig,
|
||||
excluding newly added fields.
|
||||
|
||||
Here for backwards compatibility; to be removed (TODO MST-18).
|
||||
Here for backwards compatibility; to be removed (TODO MST-40).
|
||||
"""
|
||||
return {
|
||||
'max_team_size': self.max_team_size,
|
||||
'max_team_size': self.default_max_team_size,
|
||||
'topics': [
|
||||
teamset.cleaned_data_old_format for teamset in self.teamsets
|
||||
]
|
||||
@@ -123,9 +136,11 @@ class TeamsConfig(object):
|
||||
return {teamset.teamset_id: teamset for teamset in self.teamsets}
|
||||
|
||||
@cached_property
|
||||
def max_team_size(self):
|
||||
def default_max_team_size(self):
|
||||
"""
|
||||
The default maximum size for teams in this course.
|
||||
|
||||
Can be overriden by individual team sets; see `calc_max_team_size`.
|
||||
"""
|
||||
return _clean_max_team_size(self._data.get('max_team_size'))
|
||||
|
||||
@@ -147,7 +162,7 @@ class TeamsConfig(object):
|
||||
return None
|
||||
if teamset.max_team_size:
|
||||
return teamset.max_team_size
|
||||
return self.max_team_size
|
||||
return self.default_max_team_size
|
||||
|
||||
|
||||
class TeamsetConfig(object):
|
||||
@@ -157,7 +172,7 @@ class TeamsetConfig(object):
|
||||
Takes in a configuration from a JSON-friendly dictionary,
|
||||
and exposes cleaned data from it.
|
||||
"""
|
||||
teamset_id_regex = re.compile(r'^[A-Za-z0-9_-]+$')
|
||||
teamset_id_regex = re.compile(r'^[A-Za-z0-9_. -]+$')
|
||||
|
||||
def __init__(self, data):
|
||||
"""
|
||||
@@ -192,6 +207,19 @@ class TeamsetConfig(object):
|
||||
),
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
"""
|
||||
Define equality based on cleaned data.
|
||||
"""
|
||||
return isinstance(other, self.__class__) and self.cleaned_data == other.cleaned_data
|
||||
|
||||
def __ne__(self, other):
|
||||
"""
|
||||
Overrides default inequality to be the inverse of our custom equality.
|
||||
Safe to remove once we're in Python 3 -- Py3 does this for us.
|
||||
"""
|
||||
return not self.__eq__(other)
|
||||
|
||||
@property
|
||||
def source_data(self):
|
||||
"""
|
||||
@@ -218,7 +246,7 @@ class TeamsetConfig(object):
|
||||
JSON-friendly dictionary containing cleaned data from this TeamsConfig,
|
||||
excluding newly added fields.
|
||||
|
||||
Here for backwards compatibility; to be removed (TODO MST-18).
|
||||
Here for backwards compatibility; to be removed (TODO MST-40).
|
||||
"""
|
||||
return {
|
||||
'id': self.teamset_id,
|
||||
@@ -231,7 +259,8 @@ class TeamsetConfig(object):
|
||||
"""
|
||||
An identifier for this team-set.
|
||||
|
||||
Should be a URL-slug friendly string.
|
||||
Should be a URL-slug friendly string,
|
||||
but for a historical reasons may contain periods and spaces.
|
||||
"""
|
||||
teamset_id = _clean_string(self._data.get('id'))
|
||||
if not self.teamset_id_regex.match(teamset_id):
|
||||
@@ -301,11 +330,11 @@ class TeamsetType(Enum):
|
||||
|
||||
def _clean_string(value):
|
||||
"""
|
||||
Return `value` if it's a string, otherwise "".
|
||||
Return `str(value)` if it's a string or int, otherwise "".
|
||||
"""
|
||||
if not isinstance(value, six.string_types):
|
||||
return ""
|
||||
return value
|
||||
if isinstance(value, six.integer_types + six.string_types):
|
||||
return six.text_type(value)
|
||||
return ""
|
||||
|
||||
|
||||
def _clean_max_team_size(value):
|
||||
|
||||
@@ -91,14 +91,14 @@ class TeamsConfigTests(TestCase):
|
||||
},
|
||||
{
|
||||
# Team-set should be dropped due to invalid ID.
|
||||
"id": "Not a slug.",
|
||||
"name": "Assignment about slugs",
|
||||
"id": "the character & cannot be in an ID",
|
||||
"name": "Assignment about ampersands",
|
||||
},
|
||||
{
|
||||
# All fields invalid except ID;
|
||||
# Team-set will exist but have all fallbacks.
|
||||
"id": "horses",
|
||||
"name": {"assignment", "about", "horses"},
|
||||
"id": "_1. How quickly daft-jumping zebras vex",
|
||||
"name": {"assignment", "about", "zebras"},
|
||||
"description": object(),
|
||||
"max_team_size": -1000,
|
||||
"type": "matrix",
|
||||
@@ -115,8 +115,8 @@ class TeamsConfigTests(TestCase):
|
||||
"max_team_size": None,
|
||||
"team_sets": [
|
||||
{
|
||||
"id": "horses",
|
||||
"name": "horses",
|
||||
"id": "_1. How quickly daft-jumping zebras vex",
|
||||
"name": "_1. How quickly daft-jumping zebras vex",
|
||||
"description": "",
|
||||
"max_team_size": None,
|
||||
"type": "open",
|
||||
@@ -202,3 +202,11 @@ class TeamsConfigTests(TestCase):
|
||||
assert '987' in config_repr
|
||||
assert 'open' in config_repr
|
||||
assert 'hedgehogs' in config_repr
|
||||
|
||||
def test_teamset_int_id(self):
|
||||
"""
|
||||
Assert integer teaset IDs are treated as strings,
|
||||
for backwards compatibility.
|
||||
"""
|
||||
teamset = TeamsetConfig({"id": 5})
|
||||
assert teamset.teamset_id == "5"
|
||||
|
||||
Reference in New Issue
Block a user