OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

Circular import problems for Python typing

  • Thread starter Thread starter HenriChab
  • Start date Start date
H

HenriChab

Guest

Introduction​


I am trying to use a one-to-many relationship in Python but I have some troubles actually implementing because of problems of circular dependencies using Python typing.

I get the following code is a problem, but I spent hours searching for a way of workaround and did not find anything.

Class Diagram​


Let's say I have the following class diagram: enter image description here

What I try to achieve​


I am trying to write such a child of Task:

modules/specific_task.py

Code:
from specific_executor import SpecificExecutor
from task import Task

class SpecificTask(Task[SpecificExecutor]):
    def run(self):
        self.my_executor.function_in_specific_executor()

Knowing the following SpecificExecutor:

Code:
from executor import Executor

class SpecificExecutor(Executor):
    def function_in_specific_executor(self):
        pass

I need self.my_executor to be set to type SpecificExecutor to make sure that I have access to functions from SpecificExecutor.

What it would look w/o circular problems​


I have thus the following files to implement them:

modules/executor.py

Code:
from task import Task
from typing import Generic, TypeVar, List

TaskType = TypeVar("TaskType", bound=Task)

class Executor(Generic[TaskType]):
    def __init__(self, tasks: List[TaskType]):
        self.my_tasks = tasks

    def run_function(self):
        pass

modules/task.py

Code:
from executor import Executor
from typing import Generic, TypeVar

ExecutorType = TypeVar("ExecutorType", bound=Executor)

class Task(Generic[ExecutorType]):
    def __init__(self, executor: ExecutorType):
        self.my_executor = executor

    def do_something(self):
        self.my_executor.run_function()

What I did try​

  • I am aware of the existence of TYPE_CHECKING variable but it does not work when using bound in TypeVar because this is evaluated at running time.
  • It would be possible to use cast(SpecificExecutor, self.executor) every time I use this variable but this is very verbose and I would prefer to avoid that, because I know that for SpecificTask, self.executor will always be SpecificExecutor.
  • I tried to add from __future__ import annotations at the beginning of every file but it does not fix circular import issue
<h2>Introduction</h2>
<p>I am trying to use a one-to-many relationship in Python but I have some troubles actually implementing because of problems of circular dependencies using Python typing.</p>
<p>I get the following code is a problem, but I spent hours searching for a way of workaround and did not find anything.</p>
<h2>Class Diagram</h2>
<p>Let's say I have the following class diagram:
<a href="https://i.sstatic.net/KCdGS.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/KCdGS.png" alt="enter image description here" /></a></p>
<h2>What I try to achieve</h2>
<p>I am trying to write such a child of Task:</p>
<p><em>modules/specific_task.py</em></p>
<pre><code>from specific_executor import SpecificExecutor
from task import Task

class SpecificTask(Task[SpecificExecutor]):
def run(self):
self.my_executor.function_in_specific_executor()
</code></pre>
<p>Knowing the following <code>SpecificExecutor</code>:</p>
<pre class="lang-py prettyprint-override"><code>from executor import Executor

class SpecificExecutor(Executor):
def function_in_specific_executor(self):
pass
</code></pre>
<p>I need <code>self.my_executor</code> to be set to type <code>SpecificExecutor</code> to make sure that I have access to functions from <code>SpecificExecutor</code>.</p>
<h2>What it would look w/o circular problems</h2>
<p>I have thus the following files to implement them:</p>
<p><em>modules/executor.py</em></p>
<pre class="lang-py prettyprint-override"><code>from task import Task
from typing import Generic, TypeVar, List

TaskType = TypeVar("TaskType", bound=Task)

class Executor(Generic[TaskType]):
def __init__(self, tasks: List[TaskType]):
self.my_tasks = tasks

def run_function(self):
pass
</code></pre>
<p><em>modules/task.py</em></p>
<pre class="lang-py prettyprint-override"><code>from executor import Executor
from typing import Generic, TypeVar

ExecutorType = TypeVar("ExecutorType", bound=Executor)

class Task(Generic[ExecutorType]):
def __init__(self, executor: ExecutorType):
self.my_executor = executor

def do_something(self):
self.my_executor.run_function()
</code></pre>
<h2>What I did try</h2>
<ul>
<li>I am aware of the existence of <code>TYPE_CHECKING</code> variable but it does not work when using <code>bound</code> in <code>TypeVar</code> because this is evaluated at running time.</li>
<li>It would be possible to use <code>cast(SpecificExecutor, self.executor)</code> every time I use this variable but this is very verbose and I would prefer to avoid that, because I know that for <code>SpecificTask</code>, <code>self.executor</code> will always be <code>SpecificExecutor</code>.</li>
<li>I tried to add <code>from __future__ import annotations</code> at the beginning of every file but it does not fix circular import issue</li>
</ul>
 

Latest posts

D
Replies
0
Views
1
Damiano Miazzi
D
Top