Python Problems: Difference between revisions

From Official Kodi Wiki
Jump to navigation Jump to search
No edit summary
 
(One intermediate revision by one other user not shown)
Line 1: Line 1:
{{Mininav|[[Development]]|[[Add-on development]]|[[About Add-ons]]}}<br />
This page is meant to document Python issues of general interest to Kodi addon developers.
This page is meant to document Python issues of general interest to Kodi addon developers.
== datetime.strptime ==
== datetime.strptime ==
There is an old Python bug (https://bugs.python.org/issue27400) which ONLY impacts embedded python applications, such as the Kodi Python environment. The issue is that datetime.strptime is only initialized once per process and not every time the embedded environment is reinitialized. This causes datetime.strptime to return None and perhaps other strange behavior.
There is an old [[Python debugging|Python bug]]<ref name="bug_27400" /> which ''only'' impacts embedded Python applications, such as the Kodi Python environment. The issue is that <code>datetime.strptime</code><ref name="pydocs_datetime" /> is only initialized once per process, and not every time the embedded environment is reinitialized. This causes <code>datetime.strptime</code> to return <code>None</code> (and perhaps other strange behavior).
 
=== Workaround ===
The workaround is to monkey-patch <code>datetime.strptime</code> so that any user of the Python runtime will use it. It is more voodoo-like, but situations like this are why Python ''natively supports'' [[wikipedia:Monkey patch|monkey patching]], after all. The typically excellent Python documentation manages to be both thorough and concise simultaneously with regards to <code>datetime.strptime</code> and is well worth reviewing before deciding which angle of attack best suits your use case.<ref name="pydocs_strptime" />; it discusses some of the differences between <code>datetime.strptime</code> and <code>time.strptime</code>.<ref name="pydocs_differences" />
 
=== Patch ===
This patch simply replaces <code>datetime.strptime</code> with <code>time.strptime</code> as they are nearly identical in function. The original Kodi-specific implementation and its commit history are available on GitHub as part of <code>script.module.kutils</code>.<ref name="kutils_source" /> Essentially, the patch is:
<syntaxhighlight lang="python">
import datetime
import time
 
 
class proxydt(datetime.datetime):
 
    @classmethod
    def strptime(cls, date_string, format):
        return datetime.datetime(*(time.strptime(date_string, format)[:6]))
 
 
datetime.datetime = proxydt
</syntaxhighlight>
 
== asyncio ==
 
It is a known [https://github.com/python/cpython/issues/91375 issue] that <code>asyncio</code> module or rather its C-based implementation does not support embedded Python environments that use sub-interpreters, such as Kodi Python environment. Essentially it means that only one addon can start the event loop by calling <code>asyncio.run()</code> and others will fail with <code>RuntimeError</code>.
 
=== Workaround ===


One option is for you to replace every reference to datetime.strptime to use a strptime_patch attached to this page. This is less voodoo, but there is always the possibility that some library code uses strptime and there will still be potential for incorrect results or a Kodi crash (script.module.youtube.dl crashed Kodi for a while).
The workaround is to disable C-based <code>asyncio</code> module and use its pure-Python implementation. This can be done by the following code that should be put at the beginning of your addon entrypoint script:
<syntaxhighlight lang="python">
import sys
sys.modules['_asyncio'] = None
</syntaxhighlight>


The other option is to monkey-patch datetime.strptime so that any user of the python runtime will use it. It is voodoo like, but that is why Python supports Monkey patching. See Python documentation on datetime.strptime (https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior). It discusses some of the differences between datetime.strptime and time.strptime.
You will loose possible performance benefits of <code>asyncio</code> but your async Python code won't fail.


This patch simply replaces datetime.strptime with time.strptime. They are nearly identical in function. For more information, see: https://github.com/fbacher/script.module.kutils/blob/master/lib/kutils/strptime_patch.py. Essentially the patch is:
== References ==
<div  class="plainlinks"><references>
<ref name="bug_27400">Weinberg, Denny ({{#Dateformat:2016-06-27|mdy}}). [https://github.com/python/cpython/issues/71587 '''Issue #71587: Datetime NoneType after calling Py_Finalize and Py_Initialize''']. [https://github.com/python/cpython/issues ''Python Issue Tracker''] on [https://github.com/ GitHub].</ref>
<ref name="pydocs_datetime">[https://docs.python.org/3/ <span style="text-decoration: underline;">Python 3 Documentation</span>] ({{#dateformat:2022-08-28|mdy}}). [https://docs.python.org/3/library/index.html The Python Standard Library] » [https://docs.python.org/3/library/datatypes.html Data Types] » [https://docs.python.org/3/library/datetime.html#module-datetime datetime — Basic date and time types] ― <span style="font-weight: 600;">[https://docs.python.org/3/library/datetime.html#datetime.datetime.strptime ''classmethod'' <kbd>datetime.'''strptime'''(''date_string, format'')</kbd>]</span> ― from the source code found in [https://github.com/python/cpython/blob/main/Lib/datetime.py Lib/datetime.py].</ref>
<ref name="pydocs_strptime">[https://docs.python.org/3/ <span style="text-decoration: underline;">Python 3 Documentation</span>] ({{#dateformat:2022-08-28|mdy}}). datetime — Basic date and time types » <span style="font-weight: 600;">[https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior <kbd>strftime()</kbd> and <kbd>strptime()</kbd> Behavior]</span>.</ref>
<ref name="pydocs_differences">[https://docs.python.org/3/ <span style="text-decoration: underline;">Python 3 Documentation</span>] ({{#dateformat:2022-08-28|mdy}}). <kbd>strftime()</kbd> and <kbd>strptime()</kbd> Behavior » <span style="font-weight: 600;">[https://docs.python.org/3.10/library/datetime.html#technical-detail Technical Detail]</span>.</ref>
<ref name="kutils_source"><span style="font-weight: 600;">[https://github.com/fbacher/script.module.kutils/blob/master/lib/kutils/strptime_patch.py <kbd>lib/kutils/strptime_patch.py</kbd>]</span> ({{#dateformat:2022-01-11|mdy}}) in <code>script.module.kutils</code>, ''"A helper module for Kodi development"'' on GitHub.</ref>
</references></div>


  @staticmethod
    def monkey_patch_strptime():
        # Check if problem exists (don't want to stomp on patch applied earlier)
        try:
            datetime.datetime.strptime('0', '%H')
        except TypeError:
            # Globally replace Python's datetime.datetime.strptime with
            # the version here.
            datetime.datetime = StripTimePatch.strptime
    @staticmethod
    def strptime(date_string: str, date_format: str) -> datetime.datetime:
        result: datetime.datetime
        result = datetime.datetime(*(time.strptime(date_string, date_format)[0:6]))
        return result


[[Category:Development]]
[[Category:Python]]

Latest revision as of 19:44, 1 September 2022

Home icon grey.png   ▶ Development ▶ Add-on development ▶ About Add-ons ▶ Python Problems


This page is meant to document Python issues of general interest to Kodi addon developers.

datetime.strptime

There is an old Python bug[1] which only impacts embedded Python applications, such as the Kodi Python environment. The issue is that datetime.strptime[2] is only initialized once per process, and not every time the embedded environment is reinitialized. This causes datetime.strptime to return None (and perhaps other strange behavior).

Workaround

The workaround is to monkey-patch datetime.strptime so that any user of the Python runtime will use it. It is more voodoo-like, but situations like this are why Python natively supports monkey patching, after all. The typically excellent Python documentation manages to be both thorough and concise simultaneously with regards to datetime.strptime and is well worth reviewing before deciding which angle of attack best suits your use case.[3]; it discusses some of the differences between datetime.strptime and time.strptime.[4]

Patch

This patch simply replaces datetime.strptime with time.strptime as they are nearly identical in function. The original Kodi-specific implementation and its commit history are available on GitHub as part of script.module.kutils.[5] Essentially, the patch is:

import datetime
import time


class proxydt(datetime.datetime):

    @classmethod
    def strptime(cls, date_string, format):
        return datetime.datetime(*(time.strptime(date_string, format)[:6]))


datetime.datetime = proxydt

asyncio

It is a known issue that asyncio module or rather its C-based implementation does not support embedded Python environments that use sub-interpreters, such as Kodi Python environment. Essentially it means that only one addon can start the event loop by calling asyncio.run() and others will fail with RuntimeError.

Workaround

The workaround is to disable C-based asyncio module and use its pure-Python implementation. This can be done by the following code that should be put at the beginning of your addon entrypoint script:

import sys
sys.modules['_asyncio'] = None

You will loose possible performance benefits of asyncio but your async Python code won't fail.

References