Remove unnecessary copy.deepcopy calls (#45135)
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							b237ee3689
						
					
				
				
					commit
					9001e9328a
				
			@@ -156,7 +156,7 @@ def print_flattened_configuration(*, blame: bool) -> None:
 | 
				
			|||||||
    """
 | 
					    """
 | 
				
			||||||
    env = ev.active_environment()
 | 
					    env = ev.active_environment()
 | 
				
			||||||
    if env is not None:
 | 
					    if env is not None:
 | 
				
			||||||
        pristine = env.manifest.pristine_yaml_content
 | 
					        pristine = env.manifest.yaml_content
 | 
				
			||||||
        flattened = pristine.copy()
 | 
					        flattened = pristine.copy()
 | 
				
			||||||
        flattened[spack.schema.env.TOP_LEVEL_KEY] = pristine[spack.schema.env.TOP_LEVEL_KEY].copy()
 | 
					        flattened[spack.schema.env.TOP_LEVEL_KEY] = pristine[spack.schema.env.TOP_LEVEL_KEY].copy()
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -174,9 +174,7 @@ def _write_section(self, section: str) -> None:
 | 
				
			|||||||
        if data is None:
 | 
					        if data is None:
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # We copy data here to avoid adding defaults at write time
 | 
					        validate(data, SECTION_SCHEMAS[section])
 | 
				
			||||||
        validate_data = copy.deepcopy(data)
 | 
					 | 
				
			||||||
        validate(validate_data, SECTION_SCHEMAS[section])
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            filesystem.mkdirp(self.path)
 | 
					            filesystem.mkdirp(self.path)
 | 
				
			||||||
@@ -1080,11 +1078,8 @@ def validate(
 | 
				
			|||||||
    """
 | 
					    """
 | 
				
			||||||
    import jsonschema
 | 
					    import jsonschema
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Validate a copy to avoid adding defaults
 | 
					 | 
				
			||||||
    # This allows us to round-trip data without adding to it.
 | 
					 | 
				
			||||||
    test_data = syaml.deepcopy(data)
 | 
					 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        spack.schema.Validator(schema).validate(test_data)
 | 
					        spack.schema.Validator(schema).validate(data)
 | 
				
			||||||
    except jsonschema.ValidationError as e:
 | 
					    except jsonschema.ValidationError as e:
 | 
				
			||||||
        if hasattr(e.instance, "lc"):
 | 
					        if hasattr(e.instance, "lc"):
 | 
				
			||||||
            line_number = e.instance.lc.line + 1
 | 
					            line_number = e.instance.lc.line + 1
 | 
				
			||||||
@@ -1093,7 +1088,7 @@ def validate(
 | 
				
			|||||||
        raise ConfigFormatError(e, data, filename, line_number) from e
 | 
					        raise ConfigFormatError(e, data, filename, line_number) from e
 | 
				
			||||||
    # return the validated data so that we can access the raw data
 | 
					    # return the validated data so that we can access the raw data
 | 
				
			||||||
    # mostly relevant for environments
 | 
					    # mostly relevant for environments
 | 
				
			||||||
    return test_data
 | 
					    return data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def read_config_file(
 | 
					def read_config_file(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,6 @@
 | 
				
			|||||||
import collections
 | 
					import collections
 | 
				
			||||||
import collections.abc
 | 
					import collections.abc
 | 
				
			||||||
import contextlib
 | 
					import contextlib
 | 
				
			||||||
import copy
 | 
					 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import pathlib
 | 
					import pathlib
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
@@ -528,8 +527,8 @@ def _read_yaml(str_or_file):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    filename = getattr(str_or_file, "name", None)
 | 
					    filename = getattr(str_or_file, "name", None)
 | 
				
			||||||
    default_data = spack.config.validate(data, spack.schema.env.schema, filename)
 | 
					    spack.config.validate(data, spack.schema.env.schema, filename)
 | 
				
			||||||
    return data, default_data
 | 
					    return data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _write_yaml(data, str_or_file):
 | 
					def _write_yaml(data, str_or_file):
 | 
				
			||||||
@@ -957,18 +956,25 @@ def write_transaction(self):
 | 
				
			|||||||
        """Get a write lock context manager for use in a `with` block."""
 | 
					        """Get a write lock context manager for use in a `with` block."""
 | 
				
			||||||
        return lk.WriteTransaction(self.txlock, acquire=self._re_read)
 | 
					        return lk.WriteTransaction(self.txlock, acquire=self._re_read)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _process_definition(self, item):
 | 
					    def _process_definition(self, entry):
 | 
				
			||||||
        """Process a single spec definition item."""
 | 
					        """Process a single spec definition item."""
 | 
				
			||||||
        entry = copy.deepcopy(item)
 | 
					        when_string = entry.get("when")
 | 
				
			||||||
        when = _eval_conditional(entry.pop("when", "True"))
 | 
					        if when_string is not None:
 | 
				
			||||||
        assert len(entry) == 1
 | 
					            when = _eval_conditional(when_string)
 | 
				
			||||||
 | 
					            assert len([x for x in entry if x != "when"]) == 1
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            when = True
 | 
				
			||||||
 | 
					            assert len(entry) == 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if when:
 | 
					        if when:
 | 
				
			||||||
            name, spec_list = next(iter(entry.items()))
 | 
					            for name, spec_list in entry.items():
 | 
				
			||||||
            user_specs = SpecList(name, spec_list, self.spec_lists.copy())
 | 
					                if name == "when":
 | 
				
			||||||
            if name in self.spec_lists:
 | 
					                    continue
 | 
				
			||||||
                self.spec_lists[name].extend(user_specs)
 | 
					                user_specs = SpecList(name, spec_list, self.spec_lists.copy())
 | 
				
			||||||
            else:
 | 
					                if name in self.spec_lists:
 | 
				
			||||||
                self.spec_lists[name] = user_specs
 | 
					                    self.spec_lists[name].extend(user_specs)
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    self.spec_lists[name] = user_specs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _process_view(self, env_view: Optional[Union[bool, str, Dict]]):
 | 
					    def _process_view(self, env_view: Optional[Union[bool, str, Dict]]):
 | 
				
			||||||
        """Process view option(s), which can be boolean, string, or None.
 | 
					        """Process view option(s), which can be boolean, string, or None.
 | 
				
			||||||
@@ -2767,12 +2773,8 @@ def __init__(self, manifest_dir: Union[pathlib.Path, str], name: Optional[str] =
 | 
				
			|||||||
            raise SpackEnvironmentError(msg)
 | 
					            raise SpackEnvironmentError(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with self.manifest_file.open() as f:
 | 
					        with self.manifest_file.open() as f:
 | 
				
			||||||
            raw, with_defaults_added = _read_yaml(f)
 | 
					            self.yaml_content = _read_yaml(f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #: Pristine YAML content, without defaults being added
 | 
					 | 
				
			||||||
        self.pristine_yaml_content = raw
 | 
					 | 
				
			||||||
        #: YAML content with defaults added by Spack, if they're missing
 | 
					 | 
				
			||||||
        self.yaml_content = with_defaults_added
 | 
					 | 
				
			||||||
        self.changed = False
 | 
					        self.changed = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _all_matches(self, user_spec: str) -> List[str]:
 | 
					    def _all_matches(self, user_spec: str) -> List[str]:
 | 
				
			||||||
@@ -2786,7 +2788,7 @@ def _all_matches(self, user_spec: str) -> List[str]:
 | 
				
			|||||||
            ValueError: if no equivalent match is found
 | 
					            ValueError: if no equivalent match is found
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        result = []
 | 
					        result = []
 | 
				
			||||||
        for yaml_spec_str in self.pristine_configuration["specs"]:
 | 
					        for yaml_spec_str in self.configuration["specs"]:
 | 
				
			||||||
            if Spec(yaml_spec_str) == Spec(user_spec):
 | 
					            if Spec(yaml_spec_str) == Spec(user_spec):
 | 
				
			||||||
                result.append(yaml_spec_str)
 | 
					                result.append(yaml_spec_str)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2801,7 +2803,6 @@ def add_user_spec(self, user_spec: str) -> None:
 | 
				
			|||||||
        Args:
 | 
					        Args:
 | 
				
			||||||
            user_spec: user spec to be appended
 | 
					            user_spec: user spec to be appended
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        self.pristine_configuration.setdefault("specs", []).append(user_spec)
 | 
					 | 
				
			||||||
        self.configuration.setdefault("specs", []).append(user_spec)
 | 
					        self.configuration.setdefault("specs", []).append(user_spec)
 | 
				
			||||||
        self.changed = True
 | 
					        self.changed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2816,7 +2817,6 @@ def remove_user_spec(self, user_spec: str) -> None:
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            for key in self._all_matches(user_spec):
 | 
					            for key in self._all_matches(user_spec):
 | 
				
			||||||
                self.pristine_configuration["specs"].remove(key)
 | 
					 | 
				
			||||||
                self.configuration["specs"].remove(key)
 | 
					                self.configuration["specs"].remove(key)
 | 
				
			||||||
        except ValueError as e:
 | 
					        except ValueError as e:
 | 
				
			||||||
            msg = f"cannot remove {user_spec} from {self}, no such spec exists"
 | 
					            msg = f"cannot remove {user_spec} from {self}, no such spec exists"
 | 
				
			||||||
@@ -2834,7 +2834,6 @@ def override_user_spec(self, user_spec: str, idx: int) -> None:
 | 
				
			|||||||
            SpackEnvironmentError: when the user spec cannot be overridden
 | 
					            SpackEnvironmentError: when the user spec cannot be overridden
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            self.pristine_configuration["specs"][idx] = user_spec
 | 
					 | 
				
			||||||
            self.configuration["specs"][idx] = user_spec
 | 
					            self.configuration["specs"][idx] = user_spec
 | 
				
			||||||
        except ValueError as e:
 | 
					        except ValueError as e:
 | 
				
			||||||
            msg = f"cannot override {user_spec} from {self}"
 | 
					            msg = f"cannot override {user_spec} from {self}"
 | 
				
			||||||
@@ -2847,10 +2846,10 @@ def set_include_concrete(self, include_concrete: List[str]) -> None:
 | 
				
			|||||||
        Args:
 | 
					        Args:
 | 
				
			||||||
            include_concrete: list of already existing concrete environments to include
 | 
					            include_concrete: list of already existing concrete environments to include
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        self.pristine_configuration[included_concrete_name] = []
 | 
					        self.configuration[included_concrete_name] = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for env_path in include_concrete:
 | 
					        for env_path in include_concrete:
 | 
				
			||||||
            self.pristine_configuration[included_concrete_name].append(env_path)
 | 
					            self.configuration[included_concrete_name].append(env_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.changed = True
 | 
					        self.changed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2864,14 +2863,13 @@ def add_definition(self, user_spec: str, list_name: str) -> None:
 | 
				
			|||||||
        Raises:
 | 
					        Raises:
 | 
				
			||||||
            SpackEnvironmentError: is no valid definition exists already
 | 
					            SpackEnvironmentError: is no valid definition exists already
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        defs = self.pristine_configuration.get("definitions", [])
 | 
					        defs = self.configuration.get("definitions", [])
 | 
				
			||||||
        msg = f"cannot add {user_spec} to the '{list_name}' definition, no valid list exists"
 | 
					        msg = f"cannot add {user_spec} to the '{list_name}' definition, no valid list exists"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for idx, item in self._iterate_on_definitions(defs, list_name=list_name, err_msg=msg):
 | 
					        for idx, item in self._iterate_on_definitions(defs, list_name=list_name, err_msg=msg):
 | 
				
			||||||
            item[list_name].append(user_spec)
 | 
					            item[list_name].append(user_spec)
 | 
				
			||||||
            break
 | 
					            break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.configuration["definitions"][idx][list_name].append(user_spec)
 | 
					 | 
				
			||||||
        self.changed = True
 | 
					        self.changed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def remove_definition(self, user_spec: str, list_name: str) -> None:
 | 
					    def remove_definition(self, user_spec: str, list_name: str) -> None:
 | 
				
			||||||
@@ -2885,7 +2883,7 @@ def remove_definition(self, user_spec: str, list_name: str) -> None:
 | 
				
			|||||||
            SpackEnvironmentError: if the user spec cannot be removed from the list,
 | 
					            SpackEnvironmentError: if the user spec cannot be removed from the list,
 | 
				
			||||||
                or the list does not exist
 | 
					                or the list does not exist
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        defs = self.pristine_configuration.get("definitions", [])
 | 
					        defs = self.configuration.get("definitions", [])
 | 
				
			||||||
        msg = (
 | 
					        msg = (
 | 
				
			||||||
            f"cannot remove {user_spec} from the '{list_name}' definition, "
 | 
					            f"cannot remove {user_spec} from the '{list_name}' definition, "
 | 
				
			||||||
            f"no valid list exists"
 | 
					            f"no valid list exists"
 | 
				
			||||||
@@ -2898,7 +2896,6 @@ def remove_definition(self, user_spec: str, list_name: str) -> None:
 | 
				
			|||||||
            except ValueError:
 | 
					            except ValueError:
 | 
				
			||||||
                pass
 | 
					                pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.configuration["definitions"][idx][list_name].remove(user_spec)
 | 
					 | 
				
			||||||
        self.changed = True
 | 
					        self.changed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def override_definition(self, user_spec: str, *, override: str, list_name: str) -> None:
 | 
					    def override_definition(self, user_spec: str, *, override: str, list_name: str) -> None:
 | 
				
			||||||
@@ -2913,7 +2910,7 @@ def override_definition(self, user_spec: str, *, override: str, list_name: str)
 | 
				
			|||||||
        Raises:
 | 
					        Raises:
 | 
				
			||||||
            SpackEnvironmentError: if the user spec cannot be overridden
 | 
					            SpackEnvironmentError: if the user spec cannot be overridden
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        defs = self.pristine_configuration.get("definitions", [])
 | 
					        defs = self.configuration.get("definitions", [])
 | 
				
			||||||
        msg = f"cannot override {user_spec} with {override} in the '{list_name}' definition"
 | 
					        msg = f"cannot override {user_spec} with {override} in the '{list_name}' definition"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for idx, item in self._iterate_on_definitions(defs, list_name=list_name, err_msg=msg):
 | 
					        for idx, item in self._iterate_on_definitions(defs, list_name=list_name, err_msg=msg):
 | 
				
			||||||
@@ -2924,7 +2921,6 @@ def override_definition(self, user_spec: str, *, override: str, list_name: str)
 | 
				
			|||||||
            except ValueError:
 | 
					            except ValueError:
 | 
				
			||||||
                pass
 | 
					                pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.configuration["definitions"][idx][list_name][sub_index] = override
 | 
					 | 
				
			||||||
        self.changed = True
 | 
					        self.changed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _iterate_on_definitions(self, definitions, *, list_name, err_msg):
 | 
					    def _iterate_on_definitions(self, definitions, *, list_name, err_msg):
 | 
				
			||||||
@@ -2956,7 +2952,6 @@ def set_default_view(self, view: Union[bool, str, pathlib.Path, Dict[str, str]])
 | 
				
			|||||||
                True the default view is used for the environment, if False there's no view.
 | 
					                True the default view is used for the environment, if False there's no view.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if isinstance(view, dict):
 | 
					        if isinstance(view, dict):
 | 
				
			||||||
            self.pristine_configuration["view"][default_view_name].update(view)
 | 
					 | 
				
			||||||
            self.configuration["view"][default_view_name].update(view)
 | 
					            self.configuration["view"][default_view_name].update(view)
 | 
				
			||||||
            self.changed = True
 | 
					            self.changed = True
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
@@ -2964,15 +2959,13 @@ def set_default_view(self, view: Union[bool, str, pathlib.Path, Dict[str, str]])
 | 
				
			|||||||
        if not isinstance(view, bool):
 | 
					        if not isinstance(view, bool):
 | 
				
			||||||
            view = str(view)
 | 
					            view = str(view)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.pristine_configuration["view"] = view
 | 
					 | 
				
			||||||
        self.configuration["view"] = view
 | 
					        self.configuration["view"] = view
 | 
				
			||||||
        self.changed = True
 | 
					        self.changed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def remove_default_view(self) -> None:
 | 
					    def remove_default_view(self) -> None:
 | 
				
			||||||
        """Removes the default view from the manifest file"""
 | 
					        """Removes the default view from the manifest file"""
 | 
				
			||||||
        view_data = self.pristine_configuration.get("view")
 | 
					        view_data = self.configuration.get("view")
 | 
				
			||||||
        if isinstance(view_data, collections.abc.Mapping):
 | 
					        if isinstance(view_data, collections.abc.Mapping):
 | 
				
			||||||
            self.pristine_configuration["view"].pop(default_view_name)
 | 
					 | 
				
			||||||
            self.configuration["view"].pop(default_view_name)
 | 
					            self.configuration["view"].pop(default_view_name)
 | 
				
			||||||
            self.changed = True
 | 
					            self.changed = True
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
@@ -2985,17 +2978,12 @@ def flush(self) -> None:
 | 
				
			|||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with fs.write_tmp_and_move(os.path.realpath(self.manifest_file)) as f:
 | 
					        with fs.write_tmp_and_move(os.path.realpath(self.manifest_file)) as f:
 | 
				
			||||||
            _write_yaml(self.pristine_yaml_content, f)
 | 
					            _write_yaml(self.yaml_content, f)
 | 
				
			||||||
        self.changed = False
 | 
					        self.changed = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def pristine_configuration(self):
 | 
					 | 
				
			||||||
        """Return the dictionaries in the pristine YAML, without the top level attribute"""
 | 
					 | 
				
			||||||
        return self.pristine_yaml_content[TOP_LEVEL_KEY]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def configuration(self):
 | 
					    def configuration(self):
 | 
				
			||||||
        """Return the dictionaries in the YAML, without the top level attribute"""
 | 
					        """Return the dictionaries in the pristine YAML, without the top level attribute"""
 | 
				
			||||||
        return self.yaml_content[TOP_LEVEL_KEY]
 | 
					        return self.yaml_content[TOP_LEVEL_KEY]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __len__(self):
 | 
					    def __len__(self):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -640,4 +640,4 @@ def update_config(data):
 | 
				
			|||||||
        config("update", "-y", "config")
 | 
					        config("update", "-y", "config")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with ev.Environment(str(tmpdir)) as e:
 | 
					    with ev.Environment(str(tmpdir)) as e:
 | 
				
			||||||
        assert not e.manifest.pristine_yaml_content["spack"]["config"]["ccache"]
 | 
					        assert not e.manifest.yaml_content["spack"]["config"]["ccache"]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -253,7 +253,7 @@ def test_update_default_view(init_view, update_value, tmp_path, mock_packages, c
 | 
				
			|||||||
    if isinstance(init_view, str) and update_value is True:
 | 
					    if isinstance(init_view, str) and update_value is True:
 | 
				
			||||||
        expected_value = init_view
 | 
					        expected_value = init_view
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert env.manifest.pristine_yaml_content["spack"]["view"] == expected_value
 | 
					    assert env.manifest.yaml_content["spack"]["view"] == expected_value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize(
 | 
					@pytest.mark.parametrize(
 | 
				
			||||||
@@ -384,7 +384,7 @@ def test_can_add_specs_to_environment_without_specs_attribute(tmp_path, mock_pac
 | 
				
			|||||||
    env.add("a")
 | 
					    env.add("a")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assert len(env.user_specs) == 1
 | 
					    assert len(env.user_specs) == 1
 | 
				
			||||||
    assert env.manifest.pristine_yaml_content["spack"]["specs"] == ["a"]
 | 
					    assert env.manifest.yaml_content["spack"]["specs"] == ["a"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize(
 | 
					@pytest.mark.parametrize(
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user