コード例 #1
0
    def get_html_field_types_to_rule_specs(cls, state_schema_version=None):
        """Returns a dict containing a html_field_types_to_rule_specs dict of
        the specified state schema verison, if available.

        Args:
            state_schema_version: int|None. The state schema version to retrieve
                the html_field_types_to_rule_specs for. If None, the current
                state schema version's html_field_types_to_rule_specs will be
                returned.

        Returns:
            dict. The html_field_types_to_rule_specs specs for the given state
            schema version.

        Raises:
            Exception. No html_field_types_to_rule_specs json file found for the
                given state schema version.
        """
        cached = (
            state_schema_version in
            cls._state_schema_version_to_html_field_types_to_rule_specs)

        if not cached and state_schema_version is None:
            cls._state_schema_version_to_html_field_types_to_rule_specs[
                state_schema_version] = json.loads(
                    python_utils.get_package_file_contents(
                        'extensions',
                        feconf
                        .HTML_FIELD_TYPES_TO_RULE_SPECS_EXTENSIONS_MODULE_PATH))
        elif not cached:
            file_name = 'html_field_types_to_rule_specs_state_v%i.json' % (
                state_schema_version)
            spec_file = os.path.join(
                feconf
                .LEGACY_HTML_FIELD_TYPES_TO_RULE_SPECS_EXTENSIONS_MODULE_DIR,
                file_name)

            try:
                specs_from_json = json.loads(
                    python_utils.get_package_file_contents(
                        'extensions', spec_file))
            except Exception as e:
                raise Exception(
                    'No specs json file found for state schema v%i' %
                    state_schema_version) from e

            cls._state_schema_version_to_html_field_types_to_rule_specs[
                state_schema_version] = specs_from_json

        return cls._state_schema_version_to_html_field_types_to_rule_specs[
            state_schema_version]
コード例 #2
0
 def _refresh(cls):
     """Repopulate the registry."""
     cls._rte_components.clear()
     package, filepath = os.path.split(
         feconf.RTE_EXTENSIONS_DEFINITIONS_PATH)
     cls._rte_components = constants.parse_json_from_ts(
         python_utils.get_package_file_contents(package, filepath))
コード例 #3
0
def get_default_object_values():
    """Returns a dictionary containing the default object values."""
    # TODO(wxy): Cache this as it is accessed many times.

    return json.loads(
        python_utils.get_package_file_contents(
            'extensions', feconf.OBJECT_DEFAULT_VALUES_EXTENSIONS_MODULE_PATH))
コード例 #4
0
ファイル: components.py プロジェクト: vojtechjelinek/oppia
class BaseRteComponent:
    """Base Rte Component class.

    This is the superclass for rich text components in Oppia, such as
    Image and Video.
    """

    package, filepath = os.path.split(feconf.RTE_EXTENSIONS_DEFINITIONS_PATH)
    rich_text_component_specs = constants.parse_json_from_ts(
        python_utils.get_package_file_contents(package, filepath))

    obj_types_to_obj_classes = {
        'unicode': objects.UnicodeString,
        'html': objects.Html,
        'Filepath': objects.Filepath,
        'SanitizedUrl': objects.SanitizedUrl,
        'MathExpressionContent': objects.MathExpressionContent,
        'ListOfTabs': objects.ListOfTabs,
        'SvgFilename': objects.SvgFilename,
        'int': objects.Int,
        'bool': objects.Boolean,
        'SkillSelector': objects.SkillSelector
    }

    @classmethod
    def validate(cls, value_dict):
        """Validates customization args for a rich text component.

        Raises:
            TypeError. If any customization arg is invalid.
        """
        arg_names_to_obj_classes = {}
        customization_arg_specs = cls.rich_text_component_specs[
            cls.__name__]['customization_arg_specs']
        for customization_arg_spec in customization_arg_specs:
            arg_name = '%s-with-value' % customization_arg_spec['name']
            schema = customization_arg_spec['schema']
            if schema['type'] != 'custom':
                obj_type = schema['type']
            else:
                obj_type = schema['obj_type']
            obj_class = cls.obj_types_to_obj_classes[obj_type]
            arg_names_to_obj_classes[arg_name] = obj_class

        required_attr_names = list(arg_names_to_obj_classes.keys())
        attr_names = list(value_dict.keys())

        if set(attr_names) != set(required_attr_names):
            missing_attr_names = list(
                set(required_attr_names) - set(attr_names))
            extra_attr_names = list(set(attr_names) - set(required_attr_names))
            raise utils.ValidationError(
                'Missing attributes: %s, Extra attributes: %s' %
                (', '.join(missing_attr_names), ', '.join(extra_attr_names)))

        for arg_name in required_attr_names:
            arg_obj_class = arg_names_to_obj_classes[arg_name]
            arg_obj_class.normalize(value_dict[arg_name])
コード例 #5
0
    def rules_dict(self):
        """A dict of rule names to rule properties."""
        if self._cached_rules_dict is not None:
            return self._cached_rules_dict

        rules_index_dict = json.loads(
            python_utils.get_package_file_contents(
                'extensions', feconf.RULES_DESCRIPTIONS_EXTENSIONS_MODULE_PATH))
        self._cached_rules_dict = rules_index_dict[self.id]

        return self._cached_rules_dict
コード例 #6
0
ファイル: base_test.py プロジェクト: brianrodri/oppia
    def test_html_field_types_to_rule_specs_mapping_are_valid(self):
        """Test that the structure of the file html_field_types_to_rule_specs.
        json are valid. This test ensures that whenever any new type of
        interaction or rule type with HTML string is added, the file
        html_field_types_to_rule_specs.json should be updated accordingly.
        """
        # The file having the information about the assembly of the html in the
        # rule specs.
        html_field_types_to_rule_specs_dict = json.loads(
            python_utils.get_package_file_contents(
                'extensions',
                feconf.HTML_FIELD_TYPES_TO_RULE_SPECS_EXTENSIONS_MODULE_PATH))

        # The file having the templates for the structure of the rule specs.
        # Contents of the file html_field_types_to_rule_specs.json will be
        # verified against this file.
        rule_descriptions_dict = json.loads(
            python_utils.get_package_file_contents(
                'extensions',
                feconf.RULES_DESCRIPTIONS_EXTENSIONS_MODULE_PATH))

        # In the following part, we generate the html_field_types_to_rule_specs
        # dict based on the values in the rule_descriptions.json file.
        generated_html_field_types_dict = (collections.defaultdict(
            lambda: collections.defaultdict(lambda: collections.defaultdict(
                lambda: collections.defaultdict(lambda: collections.
                                                defaultdict(set))))))

        # Verify that each html_type dict has a format key, which must be
        # unique. After verification we delete the key for comparison with
        # the generated html_field_types_to_rule_specs dict. We compare
        # everything except the format, because the format can't be generated
        # from the rule_descriptions.json file.
        for html_type, html_type_dict in (
                html_field_types_to_rule_specs_dict.items()):
            self.assertTrue('format' in html_type_dict)
            self.assertTrue(html_type_dict['format'] in
                            feconf.ALLOWED_HTML_RULE_VARIABLE_FORMATS)
            del html_type_dict['format']

        for interaction_id, interaction_rules in (
                rule_descriptions_dict.items()):
            for rule_type, rule_description in interaction_rules.items():
                description = rule_description['description']
                # Extract the input variables and html_types from the rule
                # description.
                input_variables_with_html_type = (re.findall(
                    r'{{([a-z])\|([^}]*)}', description))
                input_variables = set()
                input_variables_to_html_type_mapping_dict = (
                    collections.defaultdict(set))
                for value in input_variables_with_html_type:
                    if 'Html' in value[1] and 'HtmlContentId' not in value[1]:
                        input_variables_to_html_type_mapping_dict[
                            value[1]].add(value[0])

                # We need to iterate through the html_types for each rule_type,
                # because only after visiting each rule_type the inner dict
                # structure for each html_type gets generated.
                for html_type, input_variables in (
                        input_variables_to_html_type_mapping_dict.items()):
                    html_type_dict = (
                        generated_html_field_types_dict[html_type])

                    # TODO(#9588): This generation (and the format of the
                    # html_field_types_dict) assumes that there is at most one
                    # interaction ID that uses a given HTML object type. If this
                    # changes in the future, the structure of the dict needs to
                    # be amended so that the each HTML object type can
                    # accommodate more than one interaction. Corresponding
                    # checks in state_domain.AnswerGroup
                    # get_all_html_content_strings() also needs to be updated.
                    if isinstance(html_type_dict['interactionId'], str):
                        # The above type check is required because,
                        # all the keys in the generated html type
                        # dict is initialized as defaultdict object.
                        # Below, we raise an exception if the existing
                        # interaction ID is overwritten by another
                        # interaction ID.
                        if (html_type_dict['interactionId'] != interaction_id):
                            raise Exception(
                                'Each html type should refer to only'
                                ' one interaction_id.')

                    html_type_dict['interactionId'] = interaction_id
                    html_type_dict['ruleTypes'][rule_type][
                        'htmlInputVariables'] = sorted(input_variables)

        self.assertEqual(html_field_types_to_rule_specs_dict,
                         dict(generated_html_field_types_dict))
コード例 #7
0
    Returns:
        str. Text with all its comments removed.
    """
    return re.sub(r'  //.*\n', r'', text)


class Constants(dict):  # type: ignore[type-arg]
    """Transforms dict to object, attributes can be accessed by dot notation."""

    # Here `value` has the type Any because it parses and stores the values of
    # contants defined in constants.ts file and we cannot define a single type
    # which works for all of them.
    def __setattr__(self, name: str, value: Any) -> None:
        self[name] = value

    # The return value here refers to the `value` in the above method, hence the
    # type Any is used for it.
    def __getattr__(self, name: str) -> Any:
        return self[name]


constants = Constants(
    parse_json_from_ts(  # pylint:disable=invalid-name
        python_utils.get_package_file_contents('assets', 'constants.ts')))

release_constants = Constants(  # pylint:disable=invalid-name
    json.loads(
        python_utils.get_package_file_contents('assets',
                                               'release_constants.json')))