@@ -553,10 +553,10 @@ def test_external_data_path_outside_destination_root_is_unsafe_on_update(
553553
554554
555555
556- def test_relative_template_path_stored_as_absolute_when_outside_destination (
556+ def test_relative_template_path_stored_as_relative_when_outside_destination (
557557 tmp_path : Path ,
558558) -> None :
559- """Template path not under destination -> stored as absolute ."""
559+ """Template path not under destination -> stored as relative ."""
560560 root = tmp_path
561561 template_dir = root / "template"
562562 project_dir = root / "project"
@@ -579,7 +579,7 @@ def test_relative_template_path_stored_as_absolute_when_outside_destination(
579579 os .chdir (old_cwd )
580580
581581 answers = load_answersfile_data (project_dir )
582- assert answers ["_src_path" ] == str (template_dir .resolve ())
582+ assert answers ["_src_path" ] == os . path . relpath ( str (template_dir .resolve ()), str ( project_dir . resolve () ))
583583
584584
585585def test_relative_template_path_stored_as_relative_when_inside_destination (
@@ -610,7 +610,7 @@ def test_relative_template_path_stored_as_relative_when_inside_destination(
610610 os .chdir (old_cwd )
611611
612612 answers = load_answersfile_data (project_dir )
613- assert answers ["_src_path" ] == ".hidden_template"
613+ assert answers ["_src_path" ] == os . path . relpath ( str ( hidden_template_dir . resolve ()), str ( project_dir . resolve ()))
614614
615615
616616def test_absolute_template_path_stored_as_is (
@@ -635,4 +635,96 @@ def test_absolute_template_path_stored_as_is(
635635 )
636636
637637 answers = load_answersfile_data (project_dir )
638- assert answers ["_src_path" ] == str (template_dir )
638+ assert answers ["_src_path" ] == str (template_dir )
639+
640+
641+ def test_relative_template_path_resolved_relative_to_project_root (
642+ tmp_path : Path ,
643+ ) -> None :
644+ """Template path resolved relative to project root on update, even if CWD is different."""
645+ root = tmp_path
646+ template_dir = root / "template"
647+ project_dir = root / "project"
648+
649+ build_file_tree (
650+ {
651+ (template_dir / "{{ _copier_conf.answers_file }}.jinja" ): (
652+ "{{ _copier_answers|to_nice_yaml }}"
653+ ),
654+ }
655+ )
656+ git_save (template_dir , tag = "v1" )
657+
658+ project_dir .mkdir (exist_ok = True )
659+
660+ # Initial copy
661+ old_cwd = Path .cwd ()
662+ try :
663+ os .chdir (root )
664+ copier .run_copy ("./template" , "./project" , defaults = True , overwrite = True )
665+ finally :
666+ os .chdir (old_cwd )
667+
668+ answers = load_answersfile_data (project_dir )
669+ # Verify it was saved as relative
670+ assert answers ["_src_path" ] == os .path .relpath (str (template_dir .resolve ()), str (project_dir .resolve ()))
671+
672+ # Initialize project as git repository and commit answers file
673+ git_save (project_dir )
674+
675+ # Run update from a completely different directory (so relative to CWD would fail)
676+ other_dir = root / "other"
677+ other_dir .mkdir (exist_ok = True )
678+ try :
679+ os .chdir (other_dir )
680+ # update should succeed because template path is resolved relative to project root
681+ copier .run_update (str (project_dir ), defaults = True , overwrite = True )
682+ finally :
683+ os .chdir (old_cwd )
684+
685+
686+ def test_relative_template_path_fallback_resolved_relative_to_cwd (
687+ tmp_path : Path ,
688+ ) -> None :
689+ """Template path fallback resolved relative to CWD if not found relative to project root."""
690+ root = tmp_path
691+ template_dir = root / "template"
692+ project_dir = root / "project"
693+
694+ build_file_tree (
695+ {
696+ (template_dir / "{{ _copier_conf.answers_file }}.jinja" ): (
697+ "{{ _copier_answers|to_nice_yaml }}"
698+ ),
699+ }
700+ )
701+ git_save (template_dir , tag = "v1" )
702+
703+ project_dir .mkdir (exist_ok = True )
704+
705+ # Initial copy
706+ old_cwd = Path .cwd ()
707+ try :
708+ os .chdir (root )
709+ copier .run_copy ("./template" , "./project" , defaults = True , overwrite = True )
710+ finally :
711+ os .chdir (old_cwd )
712+
713+ # Manually modify _src_path to be "template" (which is relative to CWD 'root',
714+ # but "project/template" does not exist).
715+ answers_file = project_dir / ".copier-answers.yml"
716+ content = answers_file .read_text ()
717+ # Replace relative path (e.g. "../template") with "template"
718+ rel_path = os .path .relpath (str (template_dir .resolve ()), str (project_dir .resolve ()))
719+ assert rel_path in content
720+ answers_file .write_text (content .replace (rel_path , "template" ))
721+
722+ # Initialize project as git repository and commit answers file
723+ git_save (project_dir )
724+
725+ try :
726+ os .chdir (root )
727+ # update should succeed because fallback resolves "template" relative to CWD (root)
728+ copier .run_update (str (project_dir ), defaults = True , overwrite = True )
729+ finally :
730+ os .chdir (old_cwd )
0 commit comments