How to extend/overload range() function from Python 2.7 to accept floats?
<p>Our core application changed from Python 2.6 to Python 2.7 maybe to Python 3 in later release.</p>

<p>Range function from python is changed (quote from the Python 2.7 changelog).</p>

<blockquote>
  <p>The <code>range()</code> function processes its arguments more consistently; it
  will now call <code>__int__()</code> on non-float.</p>
</blockquote>

<p>We allow users to add expressions / Python code based on results we process further.</p>

<p>Now how to change <code>range</code> function? Some of them are using <code>float</code> argument that are failing now in Python 2.7.</p>

<p>As code is written by users we cannot change in Python code/expression. There are 1000s of files. Some users may have their own files.</p>

<ol>
<li><p>Is there is a way to extend the <code>range()</code> function from Python, such that it will take float arguments?</p></li>
<li><p>Another alternative is to parse python code and change <code>float</code> to <code>int</code>. It is very time consuming as it requires lot of sting manipulation and some <code>range</code> calls have formulas as parameter.</p></li>
</ol>

<p>Our application build in C++, and we evaluate python expression using C++ python APIS</p>

<p>You have a serious migration issue. If you want to switch to Python 2.7 and even Python 3, there is basically no easy way around refactoring the existing (user) code base eventually. IMHO, you have the following options.</p>

<ol>
<li><p>Provide a permanent (non-optional) 2.6 compatible interface to your users. That means they do not have to change anything, but it kind of defeats the purpose of upgrading to Python 2.7 since the users still have to satisfy Python 2.6 semantics. <em>Verdict:</em> Not recommended.</p></li>
<li><p>Provide a temporary (non-optional) 2.6 compatible interface for a limited amount of time. In that case the existing code needs to be refactored eventually. <em>Verdict:</em> Not recommended.</p></li>
<li><p>Make users include a flag in their code (e.g. a magic comment that can be identified safely without executing the file like <code># *$$ supertool-pythonversion: 2.7 $$*</code>), which Python version the code expects to be run with and use 2.6 compatibility only for the files that have not been flagged with Python 2.7. That way, you can do whatever compatibility hacks are needed to run old files and run new files the way they are. <em>Verdict:</em> Increases complexity, but helps you doing the migration. <strong>Recommended</strong>.</p></li>
</ol>

<p>However, you are in the convenient position of calling Python from C++. So you can control the environment that scripts are run with via the <code>globals</code> and <code>locals</code> dictionary passed to <code>PyEval_EvalCode</code>. In order to implement scenario 3, after checking the compatibility flag from the file, you can put a custom <code>range</code> function which supports <code>float</code> arguments into the gloabls dictionary before calling <code>PyEval_EvalCode</code> to "enable" the compatibility mode.</p>

<p>I am not proficient with Python's C API, but in Python this would look like this (and it is possible to do the same via the C API):</p>

<pre><code>range27 = range

def range26(start=None, stop=None, step=None):
    if start is not None and not isinstance(start, int):
        start = int(start)
    if stop is not None and not isinstance(stop, int):
        stop = int(stop)
    if step is not None and not isinstance(step, int):
        step = int(step)
    return range27(start, stop, step)

def execute_user_code(user_file):
    ...
    src = read(user_file)
    global_dict = {}
    local_dict = {}
    ...

    if check_magic_version_comment(src) in (None, '2.6'):
        global_dict['range'] = range26
        global_dict['range27'] = range27
        # the last line is needed because the call
        # of range27 will be resolved against global_dict
        # when the user code is executed

    eval_code(src, global_dict, local_dict)
    ...
</code></pre>

python python-2.7 python-2.6