Files
2018-08-14 17:39:02 -04:00

150 lines
5.0 KiB
Python

"""
Common Helper utilities for transformers
"""
def get_field_on_block(block, field_name, default_value=None):
"""
Get the field value that is directly set on the xblock.
Do not get the inherited value since field inheritance
returns value from only a single parent chain
(e.g., doesn't take a union in DAGs).
"""
try:
if block.fields[field_name].is_set_on(block):
return getattr(block, field_name)
except KeyError:
pass
return default_value
def collect_unioned_set_field(block_structure, transformer, merged_field_name, filter_by):
"""
Recursively union a set field on the block structure.
If a block matches filter_by, it will be added to the result set.
This (potentially empty) set is unioned with the sets contained in
merged_field_name for all parents of the block.
This set union operation takes place during a topological traversal
of the block_structure, so all sets are inherited by descendants.
Parameters:
block_structure: BlockStructure to traverse
transformer: transformer that will be used for get_ and
set_transformer_block_field
merged_field_name: name of the field to store
filter_by: a unary lambda that returns true if a given
block_key should be included in the result set
"""
for block_key in block_structure.topological_traversal():
result_set = {block_key} if filter_by(block_key) else set()
for parent in block_structure.get_parents(block_key):
result_set |= block_structure.get_transformer_block_field(
parent,
transformer,
merged_field_name,
set(),
)
block_structure.set_transformer_block_field(
block_key,
transformer,
merged_field_name,
result_set,
)
def collect_merged_boolean_field(
block_structure,
transformer,
xblock_field_name,
merged_field_name,
):
"""
Collects a boolean xBlock field of name xblock_field_name
for the given block_structure and transformer. The boolean
value is percolated down the hierarchy of the block_structure
and stored as a value of merged_field_name in the
block_structure.
Assumes that the boolean field is False, by default. So,
the value is ANDed across all parents for blocks with
multiple parents and ORed across all ancestors down a single
hierarchy chain.
"""
for block_key in block_structure.topological_traversal():
# compute merged value of the boolean field from all parents
parents = block_structure.get_parents(block_key)
all_parents_merged_value = all(
block_structure.get_transformer_block_field(
parent_key, transformer, merged_field_name, False,
)
for parent_key in parents
) if parents else False
# set the merged value for this block
block_structure.set_transformer_block_field(
block_key,
transformer,
merged_field_name,
(
all_parents_merged_value or
get_field_on_block(
block_structure.get_xblock(block_key), xblock_field_name,
False,
)
)
)
def collect_merged_date_field(
block_structure,
transformer,
xblock_field_name,
merged_field_name,
default_date,
func_merge_parents=min,
func_merge_ancestors=max,
):
"""
Collects a date xBlock field of name xblock_field_name
for the given block_structure and transformer. The date
value is percolated down the hierarchy of the block_structure
and stored as a value of merged_field_name in the
block_structure.
"""
for block_key in block_structure.topological_traversal():
parents = block_structure.get_parents(block_key)
block_date = get_field_on_block(block_structure.get_xblock(block_key), xblock_field_name)
if not parents:
# no parents so just use value on block or default
merged_date_value = block_date or default_date
else:
# compute merged value of date from all parents
merged_all_parents_date = func_merge_parents(
block_structure.get_transformer_block_field(
parent_key, transformer, merged_field_name, default_date,
)
for parent_key in parents
)
if not block_date:
# no value on this block so take value from parents
merged_date_value = merged_all_parents_date
else:
# compute merged date of the block and the parent
merged_date_value = func_merge_ancestors(merged_all_parents_date, block_date)
block_structure.set_transformer_block_field(
block_key,
transformer,
merged_field_name,
merged_date_value
)