@@ -174,7 +174,7 @@ def __post_init__(self):
174174 self .global_resources ["_cores" ] = self .resource_settings .cores
175175 self .global_resources ["_nodes" ] = self .resource_settings .nodes
176176
177- self ._rules = OrderedDict ()
177+ self ._rules : OrderedDict [ str , Rule ] = OrderedDict ()
178178 self .default_target = None
179179 self ._workdir_init = os .path .abspath (os .curdir )
180180 self ._ruleorder = Ruleorder ()
@@ -634,24 +634,34 @@ def add_rule(
634634 checkpoint = False ,
635635 allow_overwrite = False ,
636636 ):
637+ """Add a rule.
638+ Check if the rule can be overwritten.
639+
640+ > Specific rules may even be modified before using them,
641+ > via a final with: followed by a block that lists items to overwrite.
642+ > This modification can be performed after a general import,
643+ > and will overwrite any unmodified import of the same rule.
637644 """
638- Add a rule.
639- """
640- is_overwrite = self .is_rule (name )
641- if not allow_overwrite and is_overwrite :
642- raise CreateRuleException (
643- f"The name { name } is already used by another rule" ,
644- lineno = lineno ,
645- snakefile = snakefile ,
645+ if self .is_rule (name ):
646+ is_overwrite = allow_overwrite and (
647+ self .get_rule (name ).module_globals ["__name__" ]
648+ == self .modifier .namespace
646649 )
650+ if not is_overwrite :
651+ raise CreateRuleException (
652+ f"The name { name } is already used by another rule" ,
653+ lineno = lineno ,
654+ snakefile = snakefile ,
655+ )
656+ else :
657+ is_overwrite = False
658+ self .rule_count += 1
659+ if not self .default_target :
660+ self .default_target = name
647661 rule = Rule (name , self , lineno = lineno , snakefile = snakefile )
648662 self ._rules [rule .name ] = rule
649663 self .modifier .rules .add (rule )
650- if not is_overwrite :
651- self .rule_count += 1
652- if not self .default_target :
653- self .default_target = rule .name
654- return name
664+ return is_overwrite
655665
656666 def is_rule (self , name ):
657667 """
@@ -1766,7 +1776,7 @@ def decorate(ruleinfo):
17661776 orig_name = name
17671777 name = self .modifier .modify_rulename (name )
17681778
1769- name = self .add_rule (
1779+ is_overwrite = self .add_rule (
17701780 name ,
17711781 lineno ,
17721782 snakefile ,
@@ -1776,6 +1786,8 @@ def decorate(ruleinfo):
17761786 rule = self .get_rule (name )
17771787 rule .is_checkpoint = checkpoint
17781788 rule .module_globals = self .modifier .globals
1789+ if is_overwrite :
1790+ rule .module_globals ["__name__" ] = None
17791791
17801792 def decorate (ruleinfo ): # type: ignore[no-redef]
17811793 nonlocal name
@@ -1789,10 +1801,9 @@ def decorate(ruleinfo): # type: ignore[no-redef]
17891801 ** ruleinfo .wildcard_constraints [1 ],
17901802 )
17911803 if ruleinfo .name :
1792- rule .name = ruleinfo .name
17931804 del self ._rules [name ]
1794- self . _rules [ ruleinfo . name ] = rule
1795- name = rule . name
1805+ name = rule . name = ruleinfo . name
1806+ self . _rules [ name ] = rule
17961807 if ruleinfo .input :
17971808 rule .input_modifier = ruleinfo .input .modifier
17981809 rule .set_input (* ruleinfo .input .paths , ** ruleinfo .input .kwpaths )
0 commit comments