From d983c737d6332f32bc22aab19e5c0ced66f36e20 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 30 Apr 2026 19:58:23 +0300 Subject: [PATCH 1/3] fix: AutoConfig reloads wrong class after save_pretrained + local register --- .../models/auto/configuration_auto.py | 39 ++++++++++- tests/models/auto/test_configuration_auto.py | 69 +++++++++++++++++++ tests/models/auto/test_modeling_auto.py | 38 ++++++++++ 3 files changed, 143 insertions(+), 3 deletions(-) diff --git a/src/transformers/models/auto/configuration_auto.py b/src/transformers/models/auto/configuration_auto.py index d9ebfedb7ae9..bc404ed124d5 100644 --- a/src/transformers/models/auto/configuration_auto.py +++ b/src/transformers/models/auto/configuration_auto.py @@ -88,6 +88,27 @@ def config_class_to_model_type(config) -> str | None: return None +def _local_checkpoint_contains_auto_map_module( + pretrained_model_name_or_path, + class_ref: str, +) -> bool: + path = os.fspath(pretrained_model_name_or_path) + if "--" in class_ref: + _, class_ref = class_ref.split("--", 1) + if os.path.isdir(path): + checkpoint_dir = path + elif os.path.isfile(path): + checkpoint_dir = os.path.dirname(path) or os.curdir + else: + return False + try: + module_file, _ = class_ref.rsplit(".", 1) + except ValueError: + return False + module_path = os.path.join(checkpoint_dir, *module_file.split(".")) + ".py" + return os.path.isfile(module_path) + + class _LazyConfigMapping(OrderedDict[str, type[PreTrainedConfig]]): """ A dictionary that lazily load its values when they are requested. @@ -377,19 +398,31 @@ def from_pretrained(cls, pretrained_model_name_or_path: str | os.PathLike[str], explicit_local_code = has_local_code and not CONFIG_MAPPING[config_dict["model_type"]].__module__.startswith( "transformers." ) + + path = os.fspath(pretrained_model_name_or_path) + if os.path.isfile(path): + dynamic_module_source = os.path.dirname(path) or os.curdir + else: + dynamic_module_source = pretrained_model_name_or_path + + local_checkpoint_has_own_code = False if has_remote_code: class_ref = config_dict["auto_map"]["AutoConfig"] + local_checkpoint_has_own_code = _local_checkpoint_contains_auto_map_module( + pretrained_model_name_or_path, + class_ref, + ) if "--" in class_ref: upstream_repo = class_ref.split("--")[0] else: upstream_repo = None trust_remote_code = resolve_trust_remote_code( - trust_remote_code, pretrained_model_name_or_path, has_local_code, has_remote_code, upstream_repo + trust_remote_code, dynamic_module_source, has_local_code, has_remote_code, upstream_repo ) - if has_remote_code and trust_remote_code and not explicit_local_code: + if has_remote_code and trust_remote_code and (not explicit_local_code or local_checkpoint_has_own_code): config_class = get_class_from_dynamic_module( - class_ref, pretrained_model_name_or_path, code_revision=code_revision, **kwargs + class_ref, dynamic_module_source, code_revision=code_revision, **kwargs ) config_class.register_for_auto_class() return config_class.from_pretrained(pretrained_model_name_or_path, **kwargs) diff --git a/tests/models/auto/test_configuration_auto.py b/tests/models/auto/test_configuration_auto.py index 2ccbde235078..9488214a94cf 100644 --- a/tests/models/auto/test_configuration_auto.py +++ b/tests/models/auto/test_configuration_auto.py @@ -117,6 +117,75 @@ def test_from_pretrained_dynamic_config(self): self.assertEqual(reloaded_config.auto_map["AutoConfig"], "configuration.NewModelConfig") self.assertEqual(reloaded_config.__class__.__name__, "NewModelConfig") + def test_from_pretrained_saved_dynamic_config_conflict(self): + class NewModelConfigLocal(BertConfig): + model_type = "new-model" + local_only_marker = True + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + try: + config = AutoConfig.from_pretrained( + "hf-internal-testing/test_dynamic_model", + trust_remote_code=True, + ) + with tempfile.TemporaryDirectory() as tmp_dir: + config.save_pretrained(tmp_dir) + AutoConfig.register("new-model", NewModelConfigLocal) + reloaded_config = AutoConfig.from_pretrained( + tmp_dir, + trust_remote_code=True, + ) + self.assertIsNot(reloaded_config.__class__, NewModelConfigLocal) + self.assertFalse(getattr(reloaded_config.__class__, "local_only_marker", False)) + self.assertEqual( + reloaded_config.auto_map["AutoConfig"], + "configuration.NewModelConfig", + ) + self.assertEqual(reloaded_config.__class__.__name__, "NewModelConfig") + finally: + if "new-model" in CONFIG_MAPPING._extra_content: + del CONFIG_MAPPING._extra_content["new-model"] + + def test_from_pretrained_saved_dynamic_config_conflict_from_custom_config_file(self): + class NewModelConfigLocal(BertConfig): + model_type = "new-model" + local_only_marker = True + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + try: + config = AutoConfig.from_pretrained( + "hf-internal-testing/test_dynamic_model", + trust_remote_code=True, + ) + with tempfile.TemporaryDirectory() as tmp_dir: + config.save_pretrained(tmp_dir) + custom_config_path = os.path.join(tmp_dir, "custom_config.json") + os.replace(os.path.join(tmp_dir, "config.json"), custom_config_path) + + self.assertFalse(os.path.exists(os.path.join(tmp_dir, "config.json"))) + self.assertTrue(os.path.exists(custom_config_path)) + + AutoConfig.register("new-model", NewModelConfigLocal) + + reloaded_config = AutoConfig.from_pretrained( + custom_config_path, + trust_remote_code=True, + ) + self.assertIsNot(reloaded_config.__class__, NewModelConfigLocal) + self.assertFalse(getattr(reloaded_config.__class__, "local_only_marker", False)) + self.assertEqual( + reloaded_config.auto_map["AutoConfig"], + "configuration.NewModelConfig", + ) + self.assertEqual(reloaded_config.__class__.__name__, "NewModelConfig") + finally: + if "new-model" in CONFIG_MAPPING._extra_content: + del CONFIG_MAPPING._extra_content["new-model"] + def test_from_pretrained_dynamic_config_conflict(self): class NewModelConfigLocal(BertConfig): model_type = "new-model" diff --git a/tests/models/auto/test_modeling_auto.py b/tests/models/auto/test_modeling_auto.py index e9d803852b7f..4bec9229ca2f 100644 --- a/tests/models/auto/test_modeling_auto.py +++ b/tests/models/auto/test_modeling_auto.py @@ -440,6 +440,44 @@ def test_new_model_registration(self): if CustomConfig in mapping._extra_content: del mapping._extra_content[CustomConfig] + def test_from_pretrained_saved_dynamic_model_conflict(self): + class NewModelConfigLocal(BertConfig): + model_type = "new-model" + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + class NewModelLocal(BertModel): + config_class = NewModelConfigLocal + local_only_marker = True + + try: + model = AutoModel.from_pretrained( + "hf-internal-testing/test_dynamic_model", + trust_remote_code=True, + ) + with tempfile.TemporaryDirectory() as tmp_dir: + model.save_pretrained(tmp_dir) + AutoConfig.register("new-model", NewModelConfigLocal) + AutoModel.register(NewModelConfigLocal, NewModelLocal) + reloaded_model = AutoModel.from_pretrained( + tmp_dir, + trust_remote_code=True, + ) + self.assertIsNot(reloaded_model.__class__, NewModelLocal) + self.assertIsNot(reloaded_model.config.__class__, NewModelConfigLocal) + self.assertFalse(getattr(reloaded_model.__class__, "local_only_marker", False)) + self.assertEqual(reloaded_model.__class__.__name__, "NewModel") + self.assertEqual( + reloaded_model.config.__class__.__name__, + "NewModelConfig", + ) + finally: + if "new-model" in CONFIG_MAPPING._extra_content: + del CONFIG_MAPPING._extra_content["new-model"] + if NewModelConfigLocal in MODEL_MAPPING._extra_content: + del MODEL_MAPPING._extra_content[NewModelConfigLocal] + def test_from_pretrained_dynamic_model_conflict(self): class NewModelConfigLocal(BertConfig): model_type = "new-model" From a3dfad47a7a52105bacbb9472d52714a52ffc2f9 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 29 May 2026 21:20:26 +0300 Subject: [PATCH 2/3] Add prefer_auto_map opt-in for auto_map conflicts --- src/transformers/models/auto/auto_factory.py | 56 +++++++++++++++---- .../models/auto/configuration_auto.py | 46 ++++++--------- tests/models/auto/test_configuration_auto.py | 48 +++++++++++----- tests/models/auto/test_modeling_auto.py | 36 ++++++------ 4 files changed, 118 insertions(+), 68 deletions(-) diff --git a/src/transformers/models/auto/auto_factory.py b/src/transformers/models/auto/auto_factory.py index c6a457de9e4a..7921e097b68f 100644 --- a/src/transformers/models/auto/auto_factory.py +++ b/src/transformers/models/auto/auto_factory.py @@ -24,7 +24,10 @@ from huggingface_hub import repo_exists from ...configuration_utils import PreTrainedConfig -from ...dynamic_module_utils import get_class_from_dynamic_module, resolve_trust_remote_code +from ...dynamic_module_utils import ( + get_class_from_dynamic_module, + resolve_trust_remote_code, +) from ...utils import ( CONFIG_NAME, cached_file, @@ -36,7 +39,11 @@ logging, requires_backends, ) -from .configuration_auto import AutoConfig, model_type_to_module_name, replace_list_option_in_docstrings +from .configuration_auto import ( + AutoConfig, + model_type_to_module_name, + replace_list_option_in_docstrings, +) if is_torch_available(): @@ -206,6 +213,7 @@ def __init__(self, *args, **kwargs) -> None: @classmethod def from_config(cls, config, **kwargs): trust_remote_code = kwargs.pop("trust_remote_code", None) + _ = kwargs.pop("prefer_auto_map", None) has_remote_code = hasattr(config, "auto_map") and cls.__name__ in config.auto_map has_local_code = type(config) in cls._model_mapping explicit_local_code = has_local_code and not _get_model_class( @@ -218,7 +226,11 @@ def from_config(cls, config, **kwargs): else: upstream_repo = None trust_remote_code = resolve_trust_remote_code( - trust_remote_code, config._name_or_path, has_local_code, has_remote_code, upstream_repo=upstream_repo + trust_remote_code, + config._name_or_path, + has_local_code, + has_remote_code, + upstream_repo=upstream_repo, ) if has_remote_code and trust_remote_code and not explicit_local_code: @@ -261,8 +273,14 @@ def _prepare_config_for_auto_class(cls, config: PreTrainedConfig) -> PreTrainedC return config @classmethod - def from_pretrained(cls, pretrained_model_name_or_path: str | os.PathLike[str], *model_args, **kwargs): + def from_pretrained( + cls, + pretrained_model_name_or_path: str | os.PathLike[str], + *model_args, + **kwargs, + ): config = kwargs.pop("config", None) + prefer_auto_map = kwargs.pop("prefer_auto_map", False) trust_remote_code = kwargs.get("trust_remote_code") kwargs["_from_auto"] = True hub_kwargs_names = [ @@ -307,7 +325,9 @@ def from_pretrained(cls, pretrained_model_name_or_path: str | os.PathLike[str], adapter_kwargs["token"] = token maybe_adapter_path = find_adapter_config_file( - pretrained_model_name_or_path, _commit_hash=commit_hash, **adapter_kwargs + pretrained_model_name_or_path, + _commit_hash=commit_hash, + **adapter_kwargs, ) if maybe_adapter_path is not None: @@ -341,6 +361,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: str | os.PathLike[str], return_unused_kwargs=True, code_revision=code_revision, _commit_hash=commit_hash, + prefer_auto_map=prefer_auto_map, **hub_kwargs, **kwargs, ) @@ -377,7 +398,11 @@ def from_pretrained(cls, pretrained_model_name_or_path: str | os.PathLike[str], if has_remote_code and trust_remote_code and not explicit_local_code: model_class = get_class_from_dynamic_module( - class_ref, pretrained_model_name_or_path, code_revision=code_revision, **hub_kwargs, **kwargs + class_ref, + pretrained_model_name_or_path, + code_revision=code_revision, + **hub_kwargs, + **kwargs, ) _ = hub_kwargs.pop("code_revision", None) # This block handles the case where the user is loading a model with `trust_remote_code=True` @@ -388,7 +413,11 @@ def from_pretrained(cls, pretrained_model_name_or_path: str | os.PathLike[str], model_class.register_for_auto_class(auto_class=cls) model_class = add_generation_mixin_to_remote_model(model_class) return model_class.from_pretrained( - pretrained_model_name_or_path, *model_args, config=config, **hub_kwargs, **kwargs + pretrained_model_name_or_path, + *model_args, + config=config, + **hub_kwargs, + **kwargs, ) elif has_local_code: model_class = _get_model_class(config, cls._model_mapping) @@ -403,7 +432,11 @@ def from_pretrained(cls, pretrained_model_name_or_path: str | os.PathLike[str], if parent_quant is not None: config.quantization_config = parent_quant return model_class.from_pretrained( - pretrained_model_name_or_path, *model_args, config=config, **hub_kwargs, **kwargs + pretrained_model_name_or_path, + *model_args, + config=config, + **hub_kwargs, + **kwargs, ) raise ValueError( f"Unrecognized configuration class {config.__class__} for this kind of AutoModel: {cls.__name__}.\n" @@ -476,7 +509,8 @@ def insert_head_doc(docstring, head_doc: str = ""): f"one of the model classes of the library (with a {head_doc} head) ", ) return docstring.replace( - "one of the model classes of the library ", "one of the base model classes of the library " + "one of the model classes of the library ", + "one of the base model classes of the library ", ) @@ -569,7 +603,9 @@ def add_generation_mixin_to_remote_model(model_class): ) if has_custom_generate_in_class or has_custom_prepare_inputs: model_class_with_generation_mixin = type( - model_class.__name__, (model_class, GenerationMixin), {**model_class.__dict__} + model_class.__name__, + (model_class, GenerationMixin), + {**model_class.__dict__}, ) return model_class_with_generation_mixin return model_class diff --git a/src/transformers/models/auto/configuration_auto.py b/src/transformers/models/auto/configuration_auto.py index bc404ed124d5..953acb191fca 100644 --- a/src/transformers/models/auto/configuration_auto.py +++ b/src/transformers/models/auto/configuration_auto.py @@ -21,7 +21,10 @@ from typing import Any, TypeVar from ...configuration_utils import PreTrainedConfig -from ...dynamic_module_utils import get_class_from_dynamic_module, resolve_trust_remote_code +from ...dynamic_module_utils import ( + get_class_from_dynamic_module, + resolve_trust_remote_code, +) from ...utils import CONFIG_NAME, logging from .auto_mappings import CONFIG_MAPPING_NAMES, SPECIAL_MODEL_TYPE_TO_MODULE_NAME @@ -88,27 +91,6 @@ def config_class_to_model_type(config) -> str | None: return None -def _local_checkpoint_contains_auto_map_module( - pretrained_model_name_or_path, - class_ref: str, -) -> bool: - path = os.fspath(pretrained_model_name_or_path) - if "--" in class_ref: - _, class_ref = class_ref.split("--", 1) - if os.path.isdir(path): - checkpoint_dir = path - elif os.path.isfile(path): - checkpoint_dir = os.path.dirname(path) or os.curdir - else: - return False - try: - module_file, _ = class_ref.rsplit(".", 1) - except ValueError: - return False - module_path = os.path.join(checkpoint_dir, *module_file.split(".")) + ".py" - return os.path.isfile(module_path) - - class _LazyConfigMapping(OrderedDict[str, type[PreTrainedConfig]]): """ A dictionary that lazily load its values when they are requested. @@ -350,6 +332,10 @@ def from_pretrained(cls, pretrained_model_name_or_path: str | os.PathLike[str], Whether or not to allow for custom models defined on the Hub in their own modeling files. This option should only be set to `True` for repositories you trust and in which you have read the code, as it will execute code present on the Hub on your local machine. + prefer_auto_map (`bool`, *optional*, defaults to `False`): + When `True` and `trust_remote_code=True`, prefer the checkpoint's `auto_map` + code over an explicitly registered local class for the same `model_type`. + By default, explicitly registered local classes keep precedence. kwargs(additional keyword arguments, *optional*): The values in kwargs of any keys which are configuration attributes will be used to override the loaded values. Behavior concerning key/value pairs whose keys are *not* configuration attributes is controlled @@ -391,6 +377,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: str | os.PathLike[str], kwargs["name_or_path"] = pretrained_model_name_or_path trust_remote_code = kwargs.pop("trust_remote_code", None) code_revision = kwargs.pop("code_revision", None) + prefer_auto_map = kwargs.pop("prefer_auto_map", False) config_dict, unused_kwargs = PreTrainedConfig.get_config_dict(pretrained_model_name_or_path, **kwargs) has_remote_code = "auto_map" in config_dict and "AutoConfig" in config_dict["auto_map"] @@ -405,22 +392,23 @@ def from_pretrained(cls, pretrained_model_name_or_path: str | os.PathLike[str], else: dynamic_module_source = pretrained_model_name_or_path - local_checkpoint_has_own_code = False if has_remote_code: class_ref = config_dict["auto_map"]["AutoConfig"] - local_checkpoint_has_own_code = _local_checkpoint_contains_auto_map_module( - pretrained_model_name_or_path, - class_ref, - ) if "--" in class_ref: upstream_repo = class_ref.split("--")[0] else: upstream_repo = None trust_remote_code = resolve_trust_remote_code( - trust_remote_code, dynamic_module_source, has_local_code, has_remote_code, upstream_repo + trust_remote_code, + dynamic_module_source, + has_local_code, + has_remote_code, + upstream_repo=upstream_repo, ) - if has_remote_code and trust_remote_code and (not explicit_local_code or local_checkpoint_has_own_code): + should_prefer_auto_map = prefer_auto_map and explicit_local_code + + if has_remote_code and trust_remote_code and (should_prefer_auto_map or not explicit_local_code): config_class = get_class_from_dynamic_module( class_ref, dynamic_module_source, code_revision=code_revision, **kwargs ) diff --git a/tests/models/auto/test_configuration_auto.py b/tests/models/auto/test_configuration_auto.py index 9488214a94cf..8f0e5fe6aafe 100644 --- a/tests/models/auto/test_configuration_auto.py +++ b/tests/models/auto/test_configuration_auto.py @@ -32,7 +32,6 @@ from test_module.custom_configuration import CustomConfig # noqa E402 - SAMPLE_ROBERTA_CONFIG = get_tests_dir("fixtures/dummy-config.json") @@ -83,13 +82,15 @@ def test_new_config_registration(self): def test_repo_not_found(self): with self.assertRaisesRegex( - EnvironmentError, "bert-base is not a local folder and is not a valid model identifier" + EnvironmentError, + "bert-base is not a local folder and is not a valid model identifier", ): _ = AutoConfig.from_pretrained("bert-base") def test_revision_not_found(self): with self.assertRaisesRegex( - EnvironmentError, r"aaaaaa is not a valid git identifier \(branch name, tag name or commit id\)" + EnvironmentError, + r"aaaaaa is not a valid git identifier \(branch name, tag name or commit id\)", ): _ = AutoConfig.from_pretrained(DUMMY_UNKNOWN_IDENTIFIER, revision="aaaaaa") @@ -117,7 +118,9 @@ def test_from_pretrained_dynamic_config(self): self.assertEqual(reloaded_config.auto_map["AutoConfig"], "configuration.NewModelConfig") self.assertEqual(reloaded_config.__class__.__name__, "NewModelConfig") - def test_from_pretrained_saved_dynamic_config_conflict(self): + def test_from_pretrained_saved_dynamic_config_conflict_prefers_local_by_default( + self, + ): class NewModelConfigLocal(BertConfig): model_type = "new-model" local_only_marker = True @@ -137,18 +140,15 @@ def __init__(self, **kwargs): tmp_dir, trust_remote_code=True, ) - self.assertIsNot(reloaded_config.__class__, NewModelConfigLocal) - self.assertFalse(getattr(reloaded_config.__class__, "local_only_marker", False)) - self.assertEqual( - reloaded_config.auto_map["AutoConfig"], - "configuration.NewModelConfig", - ) - self.assertEqual(reloaded_config.__class__.__name__, "NewModelConfig") + self.assertIs(reloaded_config.__class__, NewModelConfigLocal) + self.assertTrue(getattr(reloaded_config.__class__, "local_only_marker", False)) finally: if "new-model" in CONFIG_MAPPING._extra_content: del CONFIG_MAPPING._extra_content["new-model"] - def test_from_pretrained_saved_dynamic_config_conflict_from_custom_config_file(self): + def test_from_pretrained_saved_dynamic_config_conflict_prefer_auto_map_from_custom_config_file( + self, + ): class NewModelConfigLocal(BertConfig): model_type = "new-model" local_only_marker = True @@ -170,10 +170,10 @@ def __init__(self, **kwargs): self.assertTrue(os.path.exists(custom_config_path)) AutoConfig.register("new-model", NewModelConfigLocal) - reloaded_config = AutoConfig.from_pretrained( custom_config_path, trust_remote_code=True, + prefer_auto_map=True, ) self.assertIsNot(reloaded_config.__class__, NewModelConfigLocal) self.assertFalse(getattr(reloaded_config.__class__, "local_only_marker", False)) @@ -216,6 +216,28 @@ def __init__(self, **kwargs): if "new-model" in CONFIG_MAPPING._extra_content: del CONFIG_MAPPING._extra_content["new-model"] + def test_from_pretrained_dynamic_config_conflict_prefer_auto_map(self): + class NewModelConfigLocal(BertConfig): + model_type = "new-model" + local_only_marker = True + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + try: + AutoConfig.register("new-model", NewModelConfigLocal) + reloaded_config = AutoConfig.from_pretrained( + "hf-internal-testing/test_dynamic_model", + trust_remote_code=True, + prefer_auto_map=True, + ) + self.assertIsNot(reloaded_config.__class__, NewModelConfigLocal) + self.assertFalse(getattr(reloaded_config.__class__, "local_only_marker", False)) + self.assertEqual(reloaded_config.__class__.__name__, "NewModelConfig") + finally: + if "new-model" in CONFIG_MAPPING._extra_content: + del CONFIG_MAPPING._extra_content["new-model"] + def test_config_missing_model_type(self): with tempfile.TemporaryDirectory() as tmp_dir: config_dict = { diff --git a/tests/models/auto/test_modeling_auto.py b/tests/models/auto/test_modeling_auto.py index 4bec9229ca2f..d3caa9b47524 100644 --- a/tests/models/auto/test_modeling_auto.py +++ b/tests/models/auto/test_modeling_auto.py @@ -42,7 +42,6 @@ from test_module.custom_configuration import CustomConfig # noqa E402 - if is_torch_available(): import torch from test_module.custom_modeling import CustomModel @@ -310,7 +309,9 @@ def test_from_pretrained_dynamic_model_distant(self): # Test the dynamic module is reloaded if we force it. reloaded_model = AutoModel.from_pretrained( - "hf-internal-testing/test_dynamic_model", trust_remote_code=True, force_download=True + "hf-internal-testing/test_dynamic_model", + trust_remote_code=True, + force_download=True, ) self.assertIsNot(model.__class__, reloaded_model.__class__) @@ -335,7 +336,9 @@ def test_from_pretrained_dynamic_model_distant(self): # Test the dynamic module is reloaded if we force it. reloaded_model = AutoModel.from_pretrained( - "hf-internal-testing/test_dynamic_model_with_util", trust_remote_code=True, force_download=True + "hf-internal-testing/test_dynamic_model_with_util", + trust_remote_code=True, + force_download=True, ) self.assertIsNot(model.__class__, reloaded_model.__class__) @@ -354,7 +357,8 @@ def test_from_pretrained_dynamic_model_distant_with_ref(self): # This one uses a relative import to a util file, this checks it is downloaded and used properly. model = AutoModel.from_pretrained( - "hf-internal-testing/ref_to_test_dynamic_model_with_util", trust_remote_code=True + "hf-internal-testing/ref_to_test_dynamic_model_with_util", + trust_remote_code=True, ) self.assertEqual(model.__class__.__name__, "NewModel") @@ -385,7 +389,9 @@ def test_from_pretrained_dynamic_model_with_period(self): with tempfile.TemporaryDirectory() as tmp_dir: with unittest.mock.patch.dict(os.environ, {"HF_XET_CACHE": tmp_dir}): model = AutoModel.from_pretrained( - "hf-internal-testing/test_dynamic_model_v1.0", trust_remote_code=True, cache_dir=tmp_dir + "hf-internal-testing/test_dynamic_model_v1.0", + trust_remote_code=True, + cache_dir=tmp_dir, ) self.assertEqual(model.__class__.__name__, "NewModel") @@ -440,7 +446,9 @@ def test_new_model_registration(self): if CustomConfig in mapping._extra_content: del mapping._extra_content[CustomConfig] - def test_from_pretrained_saved_dynamic_model_conflict(self): + def test_from_pretrained_saved_dynamic_model_conflict_prefers_local_by_default( + self, + ): class NewModelConfigLocal(BertConfig): model_type = "new-model" @@ -464,14 +472,8 @@ class NewModelLocal(BertModel): tmp_dir, trust_remote_code=True, ) - self.assertIsNot(reloaded_model.__class__, NewModelLocal) - self.assertIsNot(reloaded_model.config.__class__, NewModelConfigLocal) - self.assertFalse(getattr(reloaded_model.__class__, "local_only_marker", False)) - self.assertEqual(reloaded_model.__class__.__name__, "NewModel") - self.assertEqual( - reloaded_model.config.__class__.__name__, - "NewModelConfig", - ) + self.assertIs(reloaded_model.__class__, NewModelLocal) + self.assertTrue(getattr(reloaded_model.__class__, "local_only_marker", False)) finally: if "new-model" in CONFIG_MAPPING._extra_content: del CONFIG_MAPPING._extra_content["new-model"] @@ -517,13 +519,15 @@ class NewModel(BertModel): def test_repo_not_found(self): with self.assertRaisesRegex( - EnvironmentError, "bert-base is not a local folder and is not a valid model identifier" + EnvironmentError, + "bert-base is not a local folder and is not a valid model identifier", ): _ = AutoModel.from_pretrained("bert-base") def test_revision_not_found(self): with self.assertRaisesRegex( - EnvironmentError, r"aaaaaa is not a valid git identifier \(branch name, tag name or commit id\)" + EnvironmentError, + r"aaaaaa is not a valid git identifier \(branch name, tag name or commit id\)", ): _ = AutoModel.from_pretrained(DUMMY_UNKNOWN_IDENTIFIER, revision="aaaaaa") From 6bc8a8e972d46d0b21baee71667d676b7c7a1651 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 29 May 2026 22:07:55 +0300 Subject: [PATCH 3/3] tests: add prefer_auto_map tests for AutoModel conflict resolution --- tests/models/auto/test_modeling_auto.py | 66 +++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tests/models/auto/test_modeling_auto.py b/tests/models/auto/test_modeling_auto.py index d3caa9b47524..bdbf9079a514 100644 --- a/tests/models/auto/test_modeling_auto.py +++ b/tests/models/auto/test_modeling_auto.py @@ -480,6 +480,72 @@ class NewModelLocal(BertModel): if NewModelConfigLocal in MODEL_MAPPING._extra_content: del MODEL_MAPPING._extra_content[NewModelConfigLocal] + def test_from_pretrained_dynamic_model_conflict_prefer_auto_map(self): + class NewModelConfigLocal(BertConfig): + model_type = "new-model" + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + class NewModelLocal(BertModel): + config_class = NewModelConfigLocal + local_only_marker = True + + try: + AutoConfig.register("new-model", NewModelConfigLocal) + AutoModel.register(NewModelConfigLocal, NewModelLocal) + reloaded_model = AutoModel.from_pretrained( + "hf-internal-testing/test_dynamic_model", + trust_remote_code=True, + prefer_auto_map=True, + ) + self.assertIsNot(reloaded_model.__class__, NewModelLocal) + self.assertIsNot(reloaded_model.config.__class__, NewModelConfigLocal) + self.assertFalse(getattr(reloaded_model.__class__, "local_only_marker", False)) + self.assertEqual(reloaded_model.__class__.__name__, "NewModel") + self.assertEqual(reloaded_model.config.__class__.__name__, "NewModelConfig") + finally: + if "new-model" in CONFIG_MAPPING._extra_content: + del CONFIG_MAPPING._extra_content["new-model"] + if NewModelConfigLocal in MODEL_MAPPING._extra_content: + del MODEL_MAPPING._extra_content[NewModelConfigLocal] + + def test_from_pretrained_saved_dynamic_model_conflict_prefer_auto_map(self): + class NewModelConfigLocal(BertConfig): + model_type = "new-model" + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + class NewModelLocal(BertModel): + config_class = NewModelConfigLocal + local_only_marker = True + + try: + model = AutoModel.from_pretrained( + "hf-internal-testing/test_dynamic_model", + trust_remote_code=True, + ) + with tempfile.TemporaryDirectory() as tmp_dir: + model.save_pretrained(tmp_dir) + AutoConfig.register("new-model", NewModelConfigLocal) + AutoModel.register(NewModelConfigLocal, NewModelLocal) + reloaded_model = AutoModel.from_pretrained( + tmp_dir, + trust_remote_code=True, + prefer_auto_map=True, + ) + self.assertIsNot(reloaded_model.__class__, NewModelLocal) + self.assertIsNot(reloaded_model.config.__class__, NewModelConfigLocal) + self.assertFalse(getattr(reloaded_model.__class__, "local_only_marker", False)) + self.assertEqual(reloaded_model.__class__.__name__, "NewModel") + self.assertEqual(reloaded_model.config.__class__.__name__, "NewModelConfig") + finally: + if "new-model" in CONFIG_MAPPING._extra_content: + del CONFIG_MAPPING._extra_content["new-model"] + if NewModelConfigLocal in MODEL_MAPPING._extra_content: + del MODEL_MAPPING._extra_content[NewModelConfigLocal] + def test_from_pretrained_dynamic_model_conflict(self): class NewModelConfigLocal(BertConfig): model_type = "new-model"