Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
edx-platform
Commits
84a2eeb8
Commit
84a2eeb8
authored
Dec 19, 2014
by
Calen Pennington
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #6209 from edx/plat/fix-pure-system
Fix PureSystem so that runtime.publish() works for a pure XBlock.
parents
98878554
2faff29a
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
215 additions
and
100 deletions
+215
-100
common/lib/xmodule/xmodule/split_test_module.py
+4
-0
common/lib/xmodule/xmodule/tests/__init__.py
+34
-12
common/lib/xmodule/xmodule/tests/test_conditional.py
+4
-2
common/lib/xmodule/xmodule/tests/test_split_test_module.py
+3
-13
common/lib/xmodule/xmodule/tests/test_vertical.py
+1
-9
common/lib/xmodule/xmodule/x_module.py
+114
-52
lms/djangoapps/courseware/tests/__init__.py
+1
-11
lms/djangoapps/courseware/tests/test_module_render.py
+54
-1
No files found.
common/lib/xmodule/xmodule/split_test_module.py
View file @
84a2eeb8
...
@@ -609,6 +609,10 @@ class SplitTestDescriptor(SplitTestFields, SequenceDescriptor, StudioEditableDes
...
@@ -609,6 +609,10 @@ class SplitTestDescriptor(SplitTestFields, SequenceDescriptor, StudioEditableDes
Called from Studio view.
Called from Studio view.
"""
"""
user_service
=
self
.
runtime
.
service
(
self
,
'user'
)
if
user_service
is
None
:
return
Response
()
user_partition
=
self
.
get_selected_partition
()
user_partition
=
self
.
get_selected_partition
()
changed
=
False
changed
=
False
...
...
common/lib/xmodule/xmodule/tests/__init__.py
View file @
84a2eeb8
...
@@ -92,16 +92,36 @@ def get_test_system(course_id=SlashSeparatedCourseKey('org', 'course', 'run')):
...
@@ -92,16 +92,36 @@ def get_test_system(course_id=SlashSeparatedCourseKey('org', 'course', 'run')):
where `my_render_func` is a function of the form my_render_func(template, context).
where `my_render_func` is a function of the form my_render_func(template, context).
"""
"""
user
=
Mock
(
is_staff
=
False
)
user
=
Mock
(
name
=
'get_test_system.user'
,
is_staff
=
False
)
descriptor_system
=
get_test_descriptor_system
(),
def
get_module
(
descriptor
):
"""Mocks module_system get_module function"""
# pylint: disable=protected-access
# Unlike XBlock Runtimes or DescriptorSystems,
# each XModule is provided with a new ModuleSystem.
# Construct one for the new XModule.
module_system
=
get_test_system
()
# Descriptors can all share a single DescriptorSystem.
# So, bind to the same one as the current descriptor.
module_system
.
descriptor_runtime
=
descriptor
.
runtime
.
_descriptor_system
descriptor
.
bind_for_student
(
module_system
,
descriptor
.
_field_data
)
return
descriptor
return
TestModuleSystem
(
return
TestModuleSystem
(
static_url
=
'/static'
,
static_url
=
'/static'
,
track_function
=
Mock
(),
track_function
=
Mock
(
name
=
'get_test_system.track_function'
),
get_module
=
Mock
()
,
get_module
=
get_module
,
render_template
=
mock_render_template
,
render_template
=
mock_render_template
,
replace_urls
=
str
,
replace_urls
=
str
,
user
=
user
,
user
=
user
,
get_real_user
=
lambda
(
__
):
user
,
get_real_user
=
lambda
(
__
):
user
,
filestore
=
Mock
(),
filestore
=
Mock
(
name
=
'get_test_system.filestore'
),
debug
=
True
,
debug
=
True
,
hostname
=
"edx.org"
,
hostname
=
"edx.org"
,
xqueue
=
{
xqueue
=
{
...
@@ -109,16 +129,16 @@ def get_test_system(course_id=SlashSeparatedCourseKey('org', 'course', 'run')):
...
@@ -109,16 +129,16 @@ def get_test_system(course_id=SlashSeparatedCourseKey('org', 'course', 'run')):
'callback_url'
:
'/'
,
'callback_url'
:
'/'
,
'default_queuename'
:
'testqueue'
,
'default_queuename'
:
'testqueue'
,
'waittime'
:
10
,
'waittime'
:
10
,
'construct_callback'
:
Mock
(
side_effect
=
"/"
),
'construct_callback'
:
Mock
(
name
=
'get_test_system.xqueue.construct_callback'
,
side_effect
=
"/"
),
},
},
node_path
=
os
.
environ
.
get
(
"NODE_PATH"
,
"/usr/local/lib/node_modules"
),
node_path
=
os
.
environ
.
get
(
"NODE_PATH"
,
"/usr/local/lib/node_modules"
),
anonymous_student_id
=
'student'
,
anonymous_student_id
=
'student'
,
open_ended_grading_interface
=
open_ended_grading_interface
,
open_ended_grading_interface
=
open_ended_grading_interface
,
course_id
=
course_id
,
course_id
=
course_id
,
error_descriptor_class
=
ErrorDescriptor
,
error_descriptor_class
=
ErrorDescriptor
,
get_user_role
=
Mock
(
is_staff
=
False
),
get_user_role
=
Mock
(
name
=
'get_test_system.get_user_role'
,
is_staff
=
False
),
descriptor_runtime
=
get_test_descriptor_system
(
),
user_location
=
Mock
(
name
=
'get_test_system.user_location'
),
user_location
=
Mock
()
,
descriptor_runtime
=
descriptor_system
,
)
)
...
@@ -128,15 +148,17 @@ def get_test_descriptor_system():
...
@@ -128,15 +148,17 @@ def get_test_descriptor_system():
"""
"""
field_data
=
DictFieldData
({})
field_data
=
DictFieldData
({})
return
MakoDescriptorSystem
(
descriptor_system
=
MakoDescriptorSystem
(
load_item
=
Mock
(),
load_item
=
Mock
(
name
=
'get_test_descriptor_system.load_item'
),
resources_fs
=
Mock
(),
resources_fs
=
Mock
(
name
=
'get_test_descriptor_system.resources_fs'
),
error_tracker
=
Mock
(),
error_tracker
=
Mock
(
name
=
'get_test_descriptor_system.error_tracker'
),
render_template
=
mock_render_template
,
render_template
=
mock_render_template
,
mixins
=
(
InheritanceMixin
,
XModuleMixin
),
mixins
=
(
InheritanceMixin
,
XModuleMixin
),
field_data
=
field_data
,
field_data
=
field_data
,
services
=
{
'field-data'
:
field_data
},
services
=
{
'field-data'
:
field_data
},
)
)
descriptor_system
.
get_asides
=
lambda
block
:
[]
return
descriptor_system
def
mock_render_template
(
*
args
,
**
kwargs
):
def
mock_render_template
(
*
args
,
**
kwargs
):
...
...
common/lib/xmodule/xmodule/tests/test_conditional.py
View file @
84a2eeb8
...
@@ -64,14 +64,14 @@ class ConditionalFactory(object):
...
@@ -64,14 +64,14 @@ class ConditionalFactory(object):
error_msg
=
'random error message'
error_msg
=
'random error message'
)
)
else
:
else
:
source_descriptor
=
Mock
()
source_descriptor
=
Mock
(
name
=
'source_descriptor'
)
source_descriptor
.
location
=
source_location
source_descriptor
.
location
=
source_location
source_descriptor
.
runtime
=
descriptor_system
source_descriptor
.
runtime
=
descriptor_system
source_descriptor
.
render
=
lambda
view
,
context
=
None
:
descriptor_system
.
render
(
source_descriptor
,
view
,
context
)
source_descriptor
.
render
=
lambda
view
,
context
=
None
:
descriptor_system
.
render
(
source_descriptor
,
view
,
context
)
# construct other descriptors:
# construct other descriptors:
child_descriptor
=
Mock
()
child_descriptor
=
Mock
(
name
=
'child_descriptor'
)
child_descriptor
.
_xmodule
.
student_view
.
return_value
.
content
=
u'<p>This is a secret</p>'
child_descriptor
.
_xmodule
.
student_view
.
return_value
.
content
=
u'<p>This is a secret</p>'
child_descriptor
.
student_view
=
child_descriptor
.
_xmodule
.
student_view
child_descriptor
.
student_view
=
child_descriptor
.
_xmodule
.
student_view
child_descriptor
.
displayable_items
.
return_value
=
[
child_descriptor
]
child_descriptor
.
displayable_items
.
return_value
=
[
child_descriptor
]
...
@@ -85,6 +85,8 @@ class ConditionalFactory(object):
...
@@ -85,6 +85,8 @@ class ConditionalFactory(object):
source_location
:
source_descriptor
source_location
:
source_descriptor
}
.
get
}
.
get
system
.
descriptor_runtime
=
descriptor_system
# construct conditional module:
# construct conditional module:
cond_location
=
Location
(
"edX"
,
"conditional_test"
,
"test_run"
,
"conditional"
,
"SampleConditional"
,
None
)
cond_location
=
Location
(
"edX"
,
"conditional_test"
,
"test_run"
,
"conditional"
,
"SampleConditional"
,
None
)
field_data
=
DictFieldData
({
field_data
=
DictFieldData
({
...
...
common/lib/xmodule/xmodule/tests/test_split_test_module.py
View file @
84a2eeb8
...
@@ -47,15 +47,7 @@ class SplitTestModuleTest(XModuleXmlImportTest, PartitionTestCase):
...
@@ -47,15 +47,7 @@ class SplitTestModuleTest(XModuleXmlImportTest, PartitionTestCase):
self
.
course_sequence
=
self
.
course
.
get_children
()[
0
]
self
.
course_sequence
=
self
.
course
.
get_children
()[
0
]
self
.
module_system
=
get_test_system
()
self
.
module_system
=
get_test_system
()
def
get_module
(
descriptor
):
self
.
module_system
.
descriptor_runtime
=
self
.
course
.
runtime
.
_descriptor_system
# pylint: disable=protected-access
"""Mocks module_system get_module function"""
module_system
=
get_test_system
()
module_system
.
get_module
=
get_module
descriptor
.
bind_for_student
(
module_system
,
descriptor
.
_field_data
)
# pylint: disable=protected-access
return
descriptor
self
.
module_system
.
get_module
=
get_module
self
.
module_system
.
descriptor_system
=
self
.
course
.
runtime
self
.
course
.
runtime
.
export_fs
=
MemoryFS
()
self
.
course
.
runtime
.
export_fs
=
MemoryFS
()
self
.
partitions_service
=
StaticPartitionService
(
self
.
partitions_service
=
StaticPartitionService
(
...
@@ -97,14 +89,12 @@ class SplitTestModuleLMSTest(SplitTestModuleTest):
...
@@ -97,14 +89,12 @@ class SplitTestModuleLMSTest(SplitTestModuleTest):
self
.
module_system
.
render
(
self
.
split_test_module
,
STUDENT_VIEW
)
.
content
self
.
module_system
.
render
(
self
.
split_test_module
,
STUDENT_VIEW
)
.
content
)
)
@ddt.data
((
0
,),
(
1
,))
@ddt.data
(
0
,
1
)
@ddt.unpack
def
test_child_missing_tag_value
(
self
,
_user_tag
):
def
test_child_missing_tag_value
(
self
,
_user_tag
):
# If user_tag has a missing value, we should still get back a valid child url
# If user_tag has a missing value, we should still get back a valid child url
self
.
assertIn
(
self
.
split_test_module
.
child_descriptor
.
url_name
,
[
'split_test_cond0'
,
'split_test_cond1'
])
self
.
assertIn
(
self
.
split_test_module
.
child_descriptor
.
url_name
,
[
'split_test_cond0'
,
'split_test_cond1'
])
@ddt.data
((
100
,),
(
200
,),
(
300
,),
(
400
,),
(
500
,),
(
600
,),
(
700
,),
(
800
,),
(
900
,),
(
1000
,))
@ddt.data
(
100
,
200
,
300
,
400
,
500
,
600
,
700
,
800
,
900
,
1000
)
@ddt.unpack
def
test_child_persist_new_tag_value_when_tag_missing
(
self
,
_user_tag
):
def
test_child_persist_new_tag_value_when_tag_missing
(
self
,
_user_tag
):
# If a user_tag has a missing value, a group should be saved/persisted for that user.
# If a user_tag has a missing value, a group should be saved/persisted for that user.
# So, we check that we get the same url_name when we call on the url_name twice.
# So, we check that we get the same url_name when we call on the url_name twice.
...
...
common/lib/xmodule/xmodule/tests/test_vertical.py
View file @
84a2eeb8
...
@@ -27,15 +27,7 @@ class BaseVerticalModuleTest(XModuleXmlImportTest):
...
@@ -27,15 +27,7 @@ class BaseVerticalModuleTest(XModuleXmlImportTest):
course_seq
=
self
.
course
.
get_children
()[
0
]
course_seq
=
self
.
course
.
get_children
()[
0
]
self
.
module_system
=
get_test_system
()
self
.
module_system
=
get_test_system
()
def
get_module
(
descriptor
):
self
.
module_system
.
descriptor_runtime
=
self
.
course
.
runtime
.
_descriptor_system
# pylint: disable=protected-access
"""Mocks module_system get_module function"""
module_system
=
get_test_system
()
module_system
.
get_module
=
get_module
descriptor
.
bind_for_student
(
module_system
,
descriptor
.
_field_data
)
# pylint: disable=protected-access
return
descriptor
self
.
module_system
.
get_module
=
get_module
self
.
module_system
.
descriptor_system
=
self
.
course
.
runtime
self
.
course
.
runtime
.
export_fs
=
MemoryFS
()
self
.
course
.
runtime
.
export_fs
=
MemoryFS
()
self
.
vertical
=
course_seq
.
get_children
()[
0
]
self
.
vertical
=
course_seq
.
get_children
()[
0
]
...
...
common/lib/xmodule/xmodule/x_module.py
View file @
84a2eeb8
...
@@ -286,15 +286,7 @@ class XModuleMixin(XBlockMixin):
...
@@ -286,15 +286,7 @@ class XModuleMixin(XBlockMixin):
@property
@property
def
runtime
(
self
):
def
runtime
(
self
):
# Handle XModule backwards compatibility. If this is a pure
return
CombinedSystem
(
self
.
xmodule_runtime
,
self
.
_runtime
)
# XBlock, and it has an xmodule_runtime defined, then we're in
# an XModule context, not an XModuleDescriptor context,
# so we should use the xmodule_runtime (ModuleSystem) as the runtime.
if
(
not
isinstance
(
self
,
(
XModule
,
XModuleDescriptor
))
and
self
.
xmodule_runtime
is
not
None
):
return
PureSystem
(
self
.
xmodule_runtime
,
self
.
_runtime
)
else
:
return
self
.
_runtime
@runtime.setter
@runtime.setter
def
runtime
(
self
,
value
):
def
runtime
(
self
,
value
):
...
@@ -424,6 +416,9 @@ class XModuleMixin(XBlockMixin):
...
@@ -424,6 +416,9 @@ class XModuleMixin(XBlockMixin):
for
child_loc
in
self
.
children
:
for
child_loc
in
self
.
children
:
try
:
try
:
child
=
self
.
runtime
.
get_block
(
child_loc
)
child
=
self
.
runtime
.
get_block
(
child_loc
)
if
child
is
None
:
continue
child
.
runtime
.
export_fs
=
self
.
runtime
.
export_fs
child
.
runtime
.
export_fs
=
self
.
runtime
.
export_fs
except
ItemNotFoundError
:
except
ItemNotFoundError
:
log
.
warning
(
u'Unable to load item {loc}, skipping'
.
format
(
loc
=
child_loc
))
log
.
warning
(
u'Unable to load item {loc}, skipping'
.
format
(
loc
=
child_loc
))
...
@@ -1273,39 +1268,22 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): # p
...
@@ -1273,39 +1268,22 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): # p
result
[
'default_value'
]
=
field
.
to_json
(
field
.
default
)
result
[
'default_value'
]
=
field
.
to_json
(
field
.
default
)
return
result
return
result
def
render
(
self
,
block
,
view_name
,
context
=
None
):
if
view_name
in
PREVIEW_VIEWS
:
assert
block
.
xmodule_runtime
is
not
None
if
isinstance
(
block
,
(
XModule
,
XModuleDescriptor
)):
to_render
=
block
.
_xmodule
else
:
to_render
=
block
return
block
.
xmodule_runtime
.
render
(
to_render
,
view_name
,
context
)
else
:
return
super
(
DescriptorSystem
,
self
)
.
render
(
block
,
view_name
,
context
)
def
handler_url
(
self
,
block
,
handler_name
,
suffix
=
''
,
query
=
''
,
thirdparty
=
False
):
def
handler_url
(
self
,
block
,
handler_name
,
suffix
=
''
,
query
=
''
,
thirdparty
=
False
):
if
block
.
xmodule_runtime
is
not
None
:
# Currently, Modulestore is responsible for instantiating DescriptorSystems
return
block
.
xmodule_runtime
.
handler_url
(
block
,
handler_name
,
suffix
,
query
,
thirdparty
)
# This means that LMS/CMS don't have a way to define a subclass of DescriptorSystem
else
:
# that implements the correct handler url. So, for now, instead, we will reference a
# Currently, Modulestore is responsible for instantiating DescriptorSystems
# global function that the application can override.
# This means that LMS/CMS don't have a way to define a subclass of DescriptorSystem
return
descriptor_global_handler_url
(
block
,
handler_name
,
suffix
,
query
,
thirdparty
)
# that implements the correct handler url. So, for now, instead, we will reference a
# global function that the application can override.
return
descriptor_global_handler_url
(
block
,
handler_name
,
suffix
,
query
,
thirdparty
)
def
local_resource_url
(
self
,
block
,
uri
):
def
local_resource_url
(
self
,
block
,
uri
):
"""
"""
See :meth:`xblock.runtime.Runtime:local_resource_url` for documentation.
See :meth:`xblock.runtime.Runtime:local_resource_url` for documentation.
"""
"""
if
block
.
xmodule_runtime
is
not
None
:
# Currently, Modulestore is responsible for instantiating DescriptorSystems
return
block
.
xmodule_runtime
.
local_resource_url
(
block
,
uri
)
# This means that LMS/CMS don't have a way to define a subclass of DescriptorSystem
else
:
# that implements the correct local_resource_url. So, for now, instead, we will reference a
# Currently, Modulestore is responsible for instantiating DescriptorSystems
# global function that the application can override.
# This means that LMS/CMS don't have a way to define a subclass of DescriptorSystem
return
descriptor_global_local_resource_url
(
block
,
uri
)
# that implements the correct local_resource_url. So, for now, instead, we will reference a
# global function that the application can override.
return
descriptor_global_local_resource_url
(
block
,
uri
)
def
applicable_aside_types
(
self
,
block
):
def
applicable_aside_types
(
self
,
block
):
"""
"""
...
@@ -1323,18 +1301,15 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): # p
...
@@ -1323,18 +1301,15 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): # p
"""
"""
raise
NotImplementedError
(
"edX Platform doesn't currently implement XBlock resource urls"
)
raise
NotImplementedError
(
"edX Platform doesn't currently implement XBlock resource urls"
)
def
publish
(
self
,
block
,
event_type
,
event
):
"""
See :meth:`xblock.runtime.Runtime:publish` for documentation.
"""
if
block
.
xmodule_runtime
is
not
None
:
return
block
.
xmodule_runtime
.
publish
(
block
,
event_type
,
event
)
def
add_block_as_child_node
(
self
,
block
,
node
):
def
add_block_as_child_node
(
self
,
block
,
node
):
child
=
etree
.
SubElement
(
node
,
"unknown"
)
child
=
etree
.
SubElement
(
node
,
"unknown"
)
child
.
set
(
'url_name'
,
block
.
url_name
)
child
.
set
(
'url_name'
,
block
.
url_name
)
block
.
add_xml_to_node
(
child
)
block
.
add_xml_to_node
(
child
)
def
publish
(
self
,
block
,
event_type
,
event
):
# A stub publish method that doesn't emit any events from XModuleDescriptors.
pass
class
XMLParsingSystem
(
DescriptorSystem
):
class
XMLParsingSystem
(
DescriptorSystem
):
def
__init__
(
self
,
process_xml
,
**
kwargs
):
def
__init__
(
self
,
process_xml
,
**
kwargs
):
...
@@ -1585,9 +1560,6 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): # pylin
...
@@ -1585,9 +1560,6 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): # pylin
"""provide uniform access to attributes (like etree)"""
"""provide uniform access to attributes (like etree)"""
self
.
__dict__
[
attr
]
=
val
self
.
__dict__
[
attr
]
=
val
def
__repr__
(
self
):
return
repr
(
self
.
__dict__
)
def
__str__
(
self
):
def
__str__
(
self
):
return
str
(
self
.
__dict__
)
return
str
(
self
.
__dict__
)
...
@@ -1609,11 +1581,15 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): # pylin
...
@@ -1609,11 +1581,15 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): # pylin
pass
pass
class
PureSystem
(
ModuleSystem
,
DescriptorSystem
):
class
CombinedSystem
(
object
):
"""
"""
A subclass of both ModuleSystem and DescriptorSystem to provide pure (non-XModule) XBlocks
This class is a shim to allow both pure XBlocks and XModuleDescriptors
a single Runtime interface for both the ModuleSystem and DescriptorSystem, when available.
that have been bound as XModules to access both the attributes of ModuleSystem
and of DescriptorSystem as a single runtime.
"""
"""
__slots__
=
(
'_module_system'
,
'_descriptor_system'
)
# This system doesn't override a number of methods that are provided by ModuleSystem and DescriptorSystem,
# This system doesn't override a number of methods that are provided by ModuleSystem and DescriptorSystem,
# namely handler_url, local_resource_url, query, and resource_url.
# namely handler_url, local_resource_url, query, and resource_url.
#
#
...
@@ -1621,12 +1597,74 @@ class PureSystem(ModuleSystem, DescriptorSystem):
...
@@ -1621,12 +1597,74 @@ class PureSystem(ModuleSystem, DescriptorSystem):
#
#
# pylint: disable=abstract-method
# pylint: disable=abstract-method
def
__init__
(
self
,
module_system
,
descriptor_system
):
def
__init__
(
self
,
module_system
,
descriptor_system
):
# N.B. This doesn't call super(PureSystem, self).__init__, because it is only inheriting from
# These attributes are set directly to __dict__ below to avoid a recursion in getattr/setattr.
# ModuleSystem and DescriptorSystem to pass isinstance checks.
# pylint: disable=super-init-not-called
self
.
_module_system
=
module_system
self
.
_module_system
=
module_system
self
.
_descriptor_system
=
descriptor_system
self
.
_descriptor_system
=
descriptor_system
def
_get_student_block
(
self
,
block
):
"""
If block is an XModuleDescriptor that has been bound to a student, return
the corresponding XModule, instead of the XModuleDescriptor.
Otherwise, return block.
"""
if
isinstance
(
block
,
XModuleDescriptor
)
and
block
.
xmodule_runtime
:
return
block
.
_xmodule
# pylint: disable=protected-access
else
:
return
block
def
render
(
self
,
block
,
view_name
,
context
=
None
):
"""
Render a block by invoking its view.
Finds the view named `view_name` on `block`. The default view will be
used if a specific view hasn't be registered. If there is no default
view, an exception will be raised.
The view is invoked, passing it `context`. The value returned by the
view is returned, with possible modifications by the runtime to
integrate it into a larger whole.
"""
if
view_name
in
PREVIEW_VIEWS
:
block
=
self
.
_get_student_block
(
block
)
return
self
.
__getattr__
(
'render'
)(
block
,
view_name
,
context
)
def
service
(
self
,
block
,
service_name
):
"""Return a service, or None.
Services are objects implementing arbitrary other interfaces. They are
requested by agreed-upon names, see [XXX TODO] for a list of possible
services. The object returned depends on the service requested.
XBlocks must announce their intention to request services with the
`XBlock.needs` or `XBlock.wants` decorators. Use `needs` if you assume
that the service is available, or `wants` if your code is flexible and
can accept a None from this method.
Runtimes can override this method if they have different techniques for
finding and delivering services.
Arguments:
block (an XBlock): this block's class will be examined for service
decorators.
service_name (string): the name of the service requested.
Returns:
An object implementing the requested service, or None.
"""
service
=
None
if
self
.
_module_system
:
service
=
self
.
_module_system
.
service
(
block
,
service_name
)
if
service
is
None
:
service
=
self
.
_descriptor_system
.
service
(
block
,
service_name
)
return
service
def
__getattr__
(
self
,
name
):
def
__getattr__
(
self
,
name
):
"""
"""
If the ModuleSystem doesn't have an attribute, try returning the same attribute from the
If the ModuleSystem doesn't have an attribute, try returning the same attribute from the
...
@@ -1638,6 +1676,30 @@ class PureSystem(ModuleSystem, DescriptorSystem):
...
@@ -1638,6 +1676,30 @@ class PureSystem(ModuleSystem, DescriptorSystem):
except
AttributeError
:
except
AttributeError
:
return
getattr
(
self
.
_descriptor_system
,
name
)
return
getattr
(
self
.
_descriptor_system
,
name
)
def
__setattr__
(
self
,
name
,
value
):
"""
If the ModuleSystem is set, set the attr on it.
Always set the attr on the DescriptorSystem.
"""
if
name
in
self
.
__slots__
:
return
super
(
CombinedSystem
,
self
)
.
__setattr__
(
name
,
value
)
if
self
.
_module_system
:
setattr
(
self
.
_module_system
,
name
,
value
)
setattr
(
self
.
_descriptor_system
,
name
,
value
)
def
__delattr__
(
self
,
name
):
"""
If the ModuleSystem is set, delete the attribute from it.
Always delete the attribute from the DescriptorSystem.
"""
if
self
.
_module_system
:
delattr
(
self
.
_module_system
,
name
)
delattr
(
self
.
_descriptor_system
,
name
)
def
__repr__
(
self
):
return
"CombinedSystem({!r}, {!r})"
.
format
(
self
.
_module_system
,
self
.
_descriptor_system
)
class
DoNothingCache
(
object
):
class
DoNothingCache
(
object
):
"""A duck-compatible object to use in ModuleSystem when there's no cache."""
"""A duck-compatible object to use in ModuleSystem when there's no cache."""
...
...
lms/djangoapps/courseware/tests/__init__.py
View file @
84a2eeb8
...
@@ -57,17 +57,7 @@ class BaseTestXmodule(ModuleStoreTestCase):
...
@@ -57,17 +57,7 @@ class BaseTestXmodule(ModuleStoreTestCase):
"""
"""
Generate a new ModuleSystem that is minimally set up for testing
Generate a new ModuleSystem that is minimally set up for testing
"""
"""
runtime
=
get_test_system
(
course_id
=
self
.
course
.
id
)
return
get_test_system
(
course_id
=
self
.
course
.
id
)
# When asked for a module out of a descriptor, just create a new xmodule runtime,
# and inject it into the descriptor
def
get_module
(
descr
):
descr
.
xmodule_runtime
=
self
.
new_module_runtime
()
return
descr
runtime
.
get_module
=
get_module
return
runtime
def
new_descriptor_runtime
(
self
):
def
new_descriptor_runtime
(
self
):
runtime
=
get_test_descriptor_system
()
runtime
=
get_test_descriptor_system
()
...
...
lms/djangoapps/courseware/tests/test_module_render.py
View file @
84a2eeb8
...
@@ -39,7 +39,7 @@ from xmodule.modulestore import ModuleStoreEnum
...
@@ -39,7 +39,7 @@ from xmodule.modulestore import ModuleStoreEnum
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
ItemFactory
,
CourseFactory
,
check_mongo_calls
from
xmodule.modulestore.tests.factories
import
ItemFactory
,
CourseFactory
,
check_mongo_calls
from
xmodule.x_module
import
XModuleDescriptor
,
STUDENT_VIEW
from
xmodule.x_module
import
XModuleDescriptor
,
XModule
,
STUDENT_VIEW
TEST_DATA_DIR
=
settings
.
COMMON_TEST_DATA_ROOT
TEST_DATA_DIR
=
settings
.
COMMON_TEST_DATA_ROOT
...
@@ -51,6 +51,20 @@ class PureXBlock(XBlock):
...
@@ -51,6 +51,20 @@ class PureXBlock(XBlock):
pass
pass
class
EmptyXModule
(
XModule
):
# pylint: disable=abstract-method
"""
Empty XModule for testing with no dependencies.
"""
pass
class
EmptyXModuleDescriptor
(
XModuleDescriptor
):
# pylint: disable=abstract-method
"""
Empty XModule for testing with no dependencies.
"""
module_class
=
EmptyXModule
@ddt.ddt
@ddt.ddt
@override_settings
(
MODULESTORE
=
TEST_DATA_MOCK_MODULESTORE
)
@override_settings
(
MODULESTORE
=
TEST_DATA_MOCK_MODULESTORE
)
class
ModuleRenderTestCase
(
ModuleStoreTestCase
,
LoginEnrollmentTestCase
):
class
ModuleRenderTestCase
(
ModuleStoreTestCase
,
LoginEnrollmentTestCase
):
...
@@ -1105,3 +1119,42 @@ class TestRebindModule(TestSubmittingProblems):
...
@@ -1105,3 +1119,42 @@ class TestRebindModule(TestSubmittingProblems):
module
=
self
.
get_module_for_user
(
self
.
anon_user
)
module
=
self
.
get_module_for_user
(
self
.
anon_user
)
module
.
system
.
rebind_noauth_module_to_user
(
module
,
self
.
anon_user
)
module
.
system
.
rebind_noauth_module_to_user
(
module
,
self
.
anon_user
)
self
.
assertFalse
(
psycho_handler
.
called
)
self
.
assertFalse
(
psycho_handler
.
called
)
@ddt.ddt
@override_settings
(
MODULESTORE
=
TEST_DATA_MOCK_MODULESTORE
)
class
TestEventPublishing
(
ModuleStoreTestCase
,
LoginEnrollmentTestCase
):
"""
Tests of event publishing for both XModules and XBlocks.
"""
def
setUp
(
self
):
"""
Set up the course and user context
"""
super
(
TestEventPublishing
,
self
)
.
setUp
()
self
.
mock_user
=
UserFactory
()
self
.
mock_user
.
id
=
1
self
.
request_factory
=
RequestFactory
()
@ddt.data
(
'xblock'
,
'xmodule'
)
@XBlock.register_temp_plugin
(
PureXBlock
,
identifier
=
'xblock'
)
@XBlock.register_temp_plugin
(
EmptyXModuleDescriptor
,
identifier
=
'xmodule'
)
@patch.object
(
render
,
'make_track_function'
)
def
test_event_publishing
(
self
,
block_type
,
mock_track_function
):
request
=
self
.
request_factory
.
get
(
''
)
request
.
user
=
self
.
mock_user
course
=
CourseFactory
()
descriptor
=
ItemFactory
(
category
=
block_type
,
parent
=
course
)
field_data_cache
=
FieldDataCache
([
course
,
descriptor
],
course
.
id
,
self
.
mock_user
)
# pylint: disable=no-member
block
=
render
.
get_module
(
self
.
mock_user
,
request
,
descriptor
.
location
,
field_data_cache
)
event_type
=
'event_type'
event
=
{
'event'
:
'data'
}
block
.
runtime
.
publish
(
block
,
event_type
,
event
)
mock_track_function
.
assert_called_once_with
(
request
)
mock_track_function
.
return_value
.
assert_called_once_with
(
event_type
,
event
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment