@@ -1187,7 +1187,7 @@ def full_type(self):
11871187
11881188 def get_rule (self ):
11891189 """Gets `Rule` from a specified variable"""
1190- return Rule (name = self .rule )
1190+ return Rule (verbatim = self .rule , is_reference = self . is_reference_rule () )
11911191
11921192 def set_rule (self , rule ):
11931193 """Sets a rule on a specified variable in the dictionary
@@ -1383,7 +1383,7 @@ def get_value(self, key):
13831383
13841384 def get_rule (self ):
13851385 """Gets `Rule` from a specified variable block"""
1386- return Rule (name = self .rule )
1386+ return Rule (verbatim = self .rule )
13871387
13881388 def set_rule (self , rule ):
13891389 """Sets a rule on a specified variable block in the dictionary
@@ -1397,9 +1397,14 @@ def set_rule(self, rule):
13971397 ------
13981398 `TypeError`
13991399 If ``rule`` is not of type `Rule`
1400+
1401+ `ValueError`
1402+ If ``rule`` is a reference rule
14001403 """
14011404 if not isinstance (rule , Rule ):
14021405 raise TypeError (type_error_message ("rule" , rule , Rule ))
1406+ if rule .is_reference :
1407+ raise ValueError ("Cannot set reference rule on a variable block" )
14031408 self .rule = repr (rule )
14041409
14051410 def write (self , writer ):
@@ -1459,16 +1464,8 @@ class Rule:
14591464
14601465 Parameters
14611466 ----------
1462- name : str or bytes
1463- Name or verbatim of the rule. It is intepreted as the verbatim
1464- representation of an entire rule if and only if:
1465-
1466- - it starts with an UpperCamelCase string, followed by a
1467- parenthesized block (...)
1468- - ``operands`` is empty
1469-
1470- operands : tuple of operands
1471- Each operand can have one of the following types:
1467+ name_and_operands : tuple of rule fragments
1468+ Each rule fragment can have one of the following types:
14721469
14731470 - str
14741471 - bytes
@@ -1479,6 +1476,17 @@ class Rule:
14791476 - upper-scoped `Variable`
14801477 - upper-scoped `Rule`
14811478
1479+ .. note::
1480+ The first element of the ``name_and_operands`` tuple is the name of
1481+ the rule and must be str or bytes and non-empty for a standard rule,
1482+ i.e. if ``is_reference`` is not set.
1483+
1484+ verbatim : str or bytes, optional
1485+ Verbatim representation of an entire rule.
1486+
1487+ .. note::
1488+ ``names_and_operands`` must be empty if ``verbatim`` is set.
1489+
14821490 is_reference : bool, default ``False``
14831491 If set to ``True``, then the rule is serialized as a reference rule:
14841492 ``Rule(Operand1, Operand2, ...)`` is serialized as
@@ -1487,7 +1495,7 @@ class Rule:
14871495 Attributes
14881496 ----------
14891497 name : str or bytes
1490- Name of the rule.
1498+ Name of the rule. It is ``None`` for reference rules.
14911499 operands : tuple of operands
14921500 Each operand has one of the following types:
14931501
@@ -1507,12 +1515,47 @@ class Rule:
15071515 This attribute cannot be changed on a `Rule` instance.
15081516 """
15091517
1510- def __init__ (self , name , * operands , is_reference = False ):
1518+ def __init__ (self , * name_and_operands , verbatim = None , is_reference = False ):
15111519 """See class docstring"""
1512- # Check input parameters
1513- if not is_string_like (name ):
1514- raise TypeError (type_error_message ("name" , name , "string-like" ))
1515- for operand in operands :
1520+ # Check input parameters and initialize rule fragments accordigly
1521+ if not isinstance (is_reference , bool ):
1522+ raise TypeError (type_error_message ("is_reference" , is_reference , bool ))
1523+ if verbatim is not None :
1524+ if not is_string_like (verbatim ):
1525+ raise TypeError (type_error_message ("verbatim" , verbatim , "string-like" ))
1526+ if not verbatim :
1527+ raise ValueError (
1528+ "'verbatim' must not be set to an empty string-like object"
1529+ )
1530+ if name_and_operands :
1531+ raise ValueError (
1532+ "Rule name and operands must not be provided for verbatim rules"
1533+ )
1534+ self .name = None
1535+ self .operands = ()
1536+ else :
1537+ if not name_and_operands :
1538+ raise ValueError ("A name must be provided to a standard rule" )
1539+ if is_reference :
1540+ self .name = None
1541+ self .operands = name_and_operands
1542+ else :
1543+ name , * operands = name_and_operands
1544+ if not is_string_like (name ):
1545+ raise TypeError (type_error_message ("name" , name , "string-like" ))
1546+ if not name :
1547+ raise ValueError ("'name' must be a non-empty string" )
1548+ self .name = name
1549+ self .operands = operands
1550+
1551+ self ._check_operands ()
1552+
1553+ # Initialize private attributes
1554+ self ._verbatim = verbatim
1555+ self ._is_reference = is_reference
1556+
1557+ def _check_operands (self ):
1558+ for operand in self .operands :
15161559 if not is_string_like (operand ) and not isinstance (
15171560 operand , (int , float , Variable , Rule , _ScopedOperand )
15181561 ):
@@ -1529,15 +1572,6 @@ def __init__(self, name, *operands, is_reference=False):
15291572 "upper-scoped Rule" ,
15301573 )
15311574 )
1532- if not isinstance (is_reference , bool ):
1533- raise TypeError (type_error_message ("is_reference" , is_reference , bool ))
1534- if not is_reference and not name :
1535- raise ValueError ("'name' must be a non-empty string" )
1536-
1537- # Initialize attributes
1538- self .name = name
1539- self .operands = operands
1540- self ._is_reference = is_reference
15411575
15421576 @property
15431577 def is_reference (self ):
@@ -1568,8 +1602,8 @@ def write(self, writer):
15681602 Output writer.
15691603
15701604 .. note::
1571- If ``self.is_reference `` is set, then ``self.name`` is not
1572- included in the serialization .
1605+ ``self.name `` is not included in the serialization of reference
1606+ rules .
15731607 """
15741608 # Check the type of the writer
15751609 if not isinstance (writer , KhiopsOutputWriter ):
@@ -1606,14 +1640,17 @@ def write(self, writer):
16061640 writer .write ("]" )
16071641 else :
16081642 writer .write (")" )
1609- # Write verbatim-given rule
1643+ # Write no-operand rule
16101644 elif (
16111645 isinstance (self .name , str )
16121646 and rule_regex .match (self .name )
16131647 or isinstance (self .name , bytes )
16141648 and bytes_rule_regex .match (self .name )
16151649 ):
16161650 writer .write (self .name )
1651+ # Write verbatim-given rule
1652+ elif self ._verbatim :
1653+ writer .write (self ._verbatim )
16171654
16181655
16191656class _ScopedOperand :
0 commit comments