I'm writing a python tool with modules at different 'levels':
- A low-level module, that can do everything, with a bit of work
- A higher level module, with added "sugar" and helper functions
I would like to be able to share function signatures from the low-level module to the higher one, so that intellisense works with both modules.
In the following examples, I'm using the
width
andheight
parameters as placeholders for a pretty long list of arguments (around 30).
I could do everything explicitly. This works, the interface is what I want, and intellisense works; but it's very tedious, error prone and a nightmare to maintain:
# high level function, wraps/uses the low level one
def create_rectangles(count, width=10, height=10):
return [create_rectangle(width=width, height=height) for _ in range(count)]
# low level function
def create_rectangle(width=10, height=10):
print(f"the rectangle is {width} wide and {height} high")
create_rectangles(3, width=10, height=5)
I could create a class to hold the lower function's parameters. It's very readable, intellisense works, but the interface in clunky:
class RectOptions:
def __init__(self, width=10, height=10) -> None:
self.width = width
self.height = height
def create_rectangles(count, rectangle_options:RectOptions):
return [create_rectangle(rectangle_options) for _ in range(count)]
def create_rectangle(options:RectOptions):
print(f"the rectangle is {options.width} wide and {options.height} high")
# needing to create an instance for a function call feels clunky...
create_rectangles(3, RectOptions(width=10, height=3))
I could simply use **kwargs
. It's concise and allows a good interface, but it breaks intellisense and is not very readable:
def create_rectangles(count, **kwargs):
return [create_rectangle(**kwargs) for _ in range(count)]
def create_rectangle(width, height):
print(f"the rectangle is {width} wide and {height} high")
create_rectangles(3, width=10, height=3)
What I would like is something that has the advantages of kwargs but with better readability/typing/intellisense support:
# pseudo-python
class RectOptions:
def __init__(self, width=10, height=10) -> None:
self.width = width
self.height = height
# The '**' operator would add properties from rectangle_options to the function signature
# We could even 'inherit' parameters from multiple sources, and error in case of conflict
def create_rectangles(count, **rectangle_options:RectOptions):
return [create_rectangle(rectangle_options) for idx in range(count)]
def create_rectangle(options:RectOptions):
print(f"the rectangle is {options.width} wide and {options.height} high")
create_rectangles(3, width=10, height=3)
I could use code generation, but I'm not very familiar with that, and it seems like it would add a lot of complexity.
While looking for a solution, I stumbled upon this reddit post. From what I understand, what I'm looking for is not currently possible, but I really hope I'm wrong about that
I've tried the the docstring_expander pip package, since it looks like it's meant to solve this problem, but it didn't do anything for me (I might be using it wrong...)
I don't think this matters but just in case: I'm using vscode 1.59 and python 3.9.9