def evaluate_string(self, string):
        """Return value represented by string.

        If allowed, the string might represent None, in
        which case we just return None.

        Otherwise, the string represents a numerical value
        or expression, in which case we also perform extra
        operations to enforce a numerical type and to clamp
        the value to allowed intervals when applicable.

        Parameters
        ==========

        string (string)
            string to be evaluated; it can be...

            1) 'None' (only if None is allowed; see the
               docstring of the __init__ method of the
               IntFloatEntry class about this);

            2) a string representing a numerical value
               (an integer or float);

            3) a string representing a numerical expression
               in Python (for instance '2 + 2', '5 ** 2',
               or even 'randint(10, 20)', etc.)

            4) any other string is considered invalid and
               will raise errors (for instance, an empty
               string or a string representing a numerical
               value with wrong syntax or numerical
               expression with wrong syntax);

               the error raised won't be caught, since this
               method is used in safe contexts (either with
               try/except clauses or with strings known to
               have correct syntax).
        """
        ### if string is empty, raise ValueError indicating
        ### problem

        if not string:

            raise ValueError("there is nothing typed in the entry")

        ### if None is allowed and the string represents it,
        ### return None
        if self.allow_none and string == "None":
            return None

        ### otherwise perform a custom evaluation of the
        ### string
        value = numeric_evaluation(string)

        ### and process it into the final value by passing
        ### it through several relevant operations

        for operation in (
            ## restrain to the allowed numeric type(s); check
            ## the docstring of the __init__ method of the
            ## IntFloatEntry class
            self.ensure_num_type,
            ## clamp to the allowed interval (when applicable)
            self.clamp_min,
            self.clamp_max,
        ):
            value = operation(value)

        ### finally return the value
        return value
Return value represented by string.

        If allowed, the string might represent None, in
        which case we just return None.

        Otherwise, the string represents a numerical value
        or expression, in which case we also perform extra
        operations to enforce a numerical type and to clamp
        the value to allowed intervals when applicable.

        Parameters
        ==========

        string (string)
            string to be evaluated; it can be...

            1) 'None' (only if None is allowed; see the
               docstring of the __init__ method of the
               IntFloatEntry class about this);

            2) a string representing a numerical value
               (an integer or float);

            3) a string representing a numerical expression
               in Python (for instance '2 + 2', '5 ** 2',
               or even 'randint(10, 20)', etc.)

            4) any other string is considered invalid and
               will raise errors (for instance, an empty
               string or a string representing a numerical
               value with wrong syntax or numerical
               expression with wrong syntax);

               the error raised won't be caught, since this
               method is used in safe contexts (either with
               try/except clauses or with strings known to
               have correct syntax).
        
nodezator/widget/intfloatentry/op.py