I'm pretty new to Python 3 and type-hints and I'm wondering if it's possible to do this in PyCharm or other IDE's.
Here's a simplified example of the code.
import dataclasses
from typing import Type
@dataclasses.dataclass()
class BasePlugin:
version: str
arguments: str = None
@dataclasses.dataclass()
class PythonPlugin(BasePlugin):
version: str = 3.7
script: str = None
@dataclasses.dataclass()
class MayaPlugin(BasePlugin):
version: str = 2022
scene_file: str = None
script_job: str = None
class Job:
def __init__(self, plugin: Type[BasePlugin]):
self.options = plugin()
job_a = Job(plugin=PythonPlugin)
Ideally, I want to be able to create an instance of Job
and use dot-notation to modify the options
fields.
e.g. job_a.options.script = 'c:\test\do_stuff.py'
With the input type-hint, code completion only shows the available attributes of the base class.
Code sample:
class Job:
def __init__(self, plugin: Type[BasePlugin]):
self.options = plugin()
job_a = Job(plugin=PythonPlugin)
job_a.options.
Result: Code completion with input type-hint
Without the type-hint, code completion shows nothing, as expected.
Code sample:
class Job:
def __init__(self, plugin):
self.options = plugin()
job_a = Job(plugin=PythonPlugin)
job_a.options.
Result: Code completion without input type-hint
What I want is the code completion for the specific subclass I'm providing on instantiation.
In the example below, I'm overriding self.options
with the plugin to show the desired result.
Code sample:
class Job:
def __init__(self, plugin: Type[BasePlugin]):
self.options = PythonPlugin() # Overriding to simulate the desired result.
job_a = Job(plugin=PythonPlugin)
job_a.options.
Result: Code completion as desired
class Job:
options: BasePlugin
...
class PythonJob(Job):
options: PythonPlugin = PythonPlugin()
...
class MayaJob(Job):
options: MayaPlugin = MayaPlugin()
...
Any help is much appreciated.
You can do this with TypeVars and Generics:
import dataclasses
from typing import Generic, Type, TypeVar
BP = TypeVar("BP")
@dataclasses.dataclass()
class BasePlugin:
version: str
arguments: str = None
@dataclasses.dataclass()
class PythonPlugin(BasePlugin):
version: str = 3.7
script: str = None
@dataclasses.dataclass()
class MayaPlugin(BasePlugin):
version: str = 2022
scene_file: str = None
script_job: str = None
class Job(Generic[BP]):
def __init__(self, plugin: Type[BP]):
self.options: BP = plugin()
job_a = Job(plugin=PythonPlugin)
job_a.options.script # auto-completes
job_b = Job(plugin=MayaPlugin)
job_b.options.scene_file # auto-completes