I'm trying to implement a simple ORM in python. I'm facing a code duplication issue and I do not know how to solve it. Here is a simplified example of a class in my project:
class Person:
TABLE_NAME = 'person'
FIELDS = [
('name', 'VARCHAR(50)'),
('age', 'INTEGER')
]
# CODE DUPLICATION: the two next lines shoudl be genereated with FIELDS not hard coded...
name: str
age: int
def __init__(self, **kwargs):
self.__dict__ = kwargs
@classmethod
def create_sql_table(cls):
# use TABLE_NAME and FIELDS to create sql table
pass
alice = Person(name='Alice', age=25)
print(alice.name)
If I remove the two lines name: str
and age: int
I lose auto-completion and I get a mypy error on the print line (Error: Person has no attribute name)
But If I keep it, I have code duplication (I write twice each field name).
Is there a way to avoid the code duplication (by generating this two lines using FIELDS variable for instance) ?
Or another way to implement this class that avoid code duplication (without mypy error and auto-completion loss) ?
CodePudding user response:
In the class Person try to add data type in constructor
CodePudding user response:
Ok, I ended up with that
class Person:
# this is not full, you need to fill other types you use it with the correct relationship
types = {
str: 'VARCHAR(50)',
int: 'INTEGER',
} # you should extract that out if you use it elsewhere
TABLE_NAME = 'person'
# NOTE: the only annotated fields should be these. if you annotate anything else, It will break
name: str
age: int
def __init__(self, **kwargs):
self.__dict__ = kwargs
@property
def FIELDS(cls):
return [(key, cls.types[value]) for key, value in cls.__annotations__.items()]
alice = Person(name='Alice', age=25)
print(alice.FIELDS) # [('name', 'VARCHAR(50)'), ('age', 'INTEGER')]
And
>>> mypy <module>
>>> Success: no issues found in 1 source file