Repository: kedro-org/kedro
File: kedro/io/data_catalog.py (Python)

Code before:
        for ds_name, ds_config in catalog.items():
            # Assume that any name with "}" in it is a dataset factory to be matched.
            if "}" in ds_name:
                # Add each factory to the dataset_patterns dict.
                dataset_patterns[ds_name] = ds_config
            else:
                ds_layer = ds_config.pop("layer", None)
                if ds_layer is not None:
                    layers[ds_layer].add(ds_name)

                ds_config = _resolve_credentials(ds_config, credentials)
                data_sets[ds_name] = AbstractDataSet.from_config(
                    ds_name, ds_config, load_versions.get(ds_name), save_version
                )
        dataset_layers = layers or None
        return cls(
            data_sets=data_sets,
            layers=dataset_layers,
            dataset_patterns=dataset_patterns,
        )

    def _get_dataset(
        self, data_set_name: str, version: Version = None, suggest: bool = True
    ) -> AbstractDataSet:
        if self.exists_in_catalog_config(data_set_name):
            if data_set_name not in self._data_sets:
                # When a dataset is "used" in the pipeline that's not in the
                # recorded catalog datasets, match it against the data factories
                # in the catalog, resolve it to a dataset instance and add it to
                # the catalog, so it only needs to be matched once and not
                # everytime the dataset is used in the pipeline.
                pattern = self._pattern_matches_cache[data_set_name]
                matched_dataset = self._resolve_dataset(data_set_name, pattern)
                self.add(data_set_name, matched_dataset)
        else:
            error_msg = f"Dataset '{data_set_name}' not found in the catalog"

            # Flag to turn on/off fuzzy-matching which can be time consuming and
            # slow down plugins like `kedro-viz`
            if suggest:
                matches = difflib.get_close_matches(
                    data_set_name, self._data_sets.keys()
                )
                if matches:
                    suggestions = ", ".join(matches)
                    error_msg += f" - did you mean one of these instead: {suggestions}"

            raise DatasetNotFoundError(error_msg)

        data_set = self._data_sets[data_set_name]
        if version and isinstance(data_set, AbstractVersionedDataSet):

Review comment (suggestion):
Could we get rid of the extra indentation level here?

```suggestion
        if self.exists_in_catalog_config(data_set_name) and data_set_name not in self._data_sets:
```

Code after:
            load_versions=load_versions,
            save_version=save_version,
        )

    @staticmethod
    def _is_pattern(pattern: str):
        """Check if a given string is a pattern. Assume that any name with '{' is a pattern."""
        return "{" in pattern

    @staticmethod
    def _match_pattern(
        data_set_patterns: dict[str, dict[str, Any]], data_set_name: str
    ) -> str | None:
        """Match a dataset name against patterns in a dictionary containing patterns"""
        for pattern, _ in data_set_patterns.items():
            result = parse(pattern, data_set_name)
            if result:
                return pattern
        return None

    @classmethod
    def _sort_patterns(
        cls, data_set_patterns: dict[str, dict[str, Any]]
    ) -> dict[str, dict[str, Any]]:
        """Sort a dictionary of dataset patterns according to parsing rules -
        1. Decreasing specificity (number of characters outside the curly brackets)
        2. Decreasing number of placeholders (number of curly bracket pairs)
        3. Alphabetically
        """
        sorted_keys = sorted(
            data_set_patterns,
            key=lambda pattern: (
                -(cls._specificity(pattern)),
                -pattern.count("{"),
                pattern,
            ),
        )
        sorted_patterns = {}
        for key in sorted_keys:
            sorted_patterns[key] = data_set_patterns[key]
        return sorted_patterns

    @staticmethod
    def _specificity(pattern: str) -> int:
        """Helper function to check the length of exactly matched characters not inside brackets
        Example -
        specificity("{namespace}.companies") = 10
        specificity("{namespace}.{dataset}") = 1
        specificity("france.companies") = 16
        """
        # Remove all the placeholders from the pattern and count the number of remaining chars