44"""
55
66import json
7+ import os
78import re
9+ import subprocess
10+ import tempfile
811from collections import defaultdict
912from pathlib import Path
1013from typing import Any , DefaultDict , Union
1114
12- import black
13- import isort
1415from jinja2 import Environment , FileSystemLoader
1516
16- from bo4e_generator .schema import SchemaMetadata
17+ from bo4e_generator .schema import SchemaMetadata , camel_to_snake
1718
1819
1920def remove_pydantic_field_import (python_code : str ) -> str :
@@ -42,29 +43,32 @@ def adapt_parse_for_sql(
4243 for schema_metadata in namespace .values ():
4344 if schema_metadata .module_path [0 ] != "enum" :
4445 # list of fields which will be replaced by modified versions
45- del_fields = []
46+ del_fields = set ()
4647 for field , val in schema_metadata .schema_parsed ["properties" ].items ():
4748 # type Any field
4849 if "type" not in str (val ):
4950 add_relation , relation_imports = create_sql_any (
5051 field , schema_metadata .class_name , namespace , add_relation , relation_imports
5152 )
52- del_fields .append (field )
53+ del_fields .add (field )
5354 # modify decimal fields
5455 if "number" in str (val ) and "string" in str (val ):
5556 relation_imports [schema_metadata .class_name + "ADD" ]["Decimal" ] = "decimal"
5657 if "array" in str (val ) and "$ref" not in str (val ):
5758 add_relation , relation_imports = create_sql_list (
5859 field , schema_metadata .class_name , namespace , add_relation , relation_imports
5960 )
60- del_fields .append (field )
61+ del_fields .add (field )
6162 if "$ref" in str (val ): # or "array" in str(val):
6263 add_relation , relation_imports = create_sql_field (
6364 field , schema_metadata .class_name , namespace , add_relation , relation_imports
6465 )
65- del_fields .append (field )
66+ del_fields .add (field )
6667 for field in del_fields :
6768 del schema_metadata .schema_parsed ["properties" ][field ]
69+ # delete id field as it is replaced below
70+ if schema_metadata .schema_parsed ["properties" ].get ("_id" ):
71+ del schema_metadata .schema_parsed ["properties" ]["_id" ]
6872 # store the reduced version. The modified fields will be added in the BaseModel.jinja2 schema
6973 schema_metadata .schema_text = json .dumps (schema_metadata .schema_parsed , indent = 2 , ensure_ascii = False )
7074
@@ -104,9 +108,8 @@ def additional_sql_arguments(
104108 if schema_metadata .module_path [0 ] != "enum" :
105109 # add primary key
106110 additional_sql_data [schema_metadata .class_name ]["SQL" ] = {
107- "primary" : schema_metadata .class_name .lower ()
108- + "_sqlid: uuid_pkg.UUID = Field( default_factory=uuid_pkg.uuid4, primary_key=True, index=True, "
109- "nullable=False )"
111+ "primary" : "id: uuid_pkg.UUID = Field( default_factory=uuid_pkg.uuid4, primary_key=True, index=True, "
112+ 'nullable=False, alias="_id", title=" Id" )'
110113 }
111114 if schema_metadata .class_name in add_relation :
112115 additional_sql_data [schema_metadata .class_name ]["SQL" ]["relations" ] = add_relation [
@@ -184,7 +187,7 @@ def create_sql_list(
184187 add_imports [class_name + "ADD" ]["Column, ARRAY" ] = "sqlalchemy"
185188 add_imports [class_name + "ADD" ][sa_type ] = "sqlalchemy"
186189
187- add_fields [class_name ][f"{ field_name } " ] = (
190+ add_fields [class_name ][f"{ camel_to_snake ( field_name ) } " ] = (
188191 f"List[{ type_hint } ] "
189192 + is_optional
190193 + f' = Field({ default } , title="{ field_name } ", sa_column=Column( ARRAY( { sa_type } )))'
@@ -209,12 +212,14 @@ def sql_reference_enum(
209212 returns field which references enums.
210213 """
211214 if is_list :
212- add_fields [class_name ][f"{ field_name } " ] = (
215+ add_fields [class_name ][f"{ camel_to_snake ( field_name ) } " ] = (
213216 f"List[{ reference_name } ]" + is_optional + f" = Field({ default } ,"
214217 f' sa_column=Column( ARRAY( Enum( { reference_name } , name="{ reference_name .lower ()} "))))'
215218 )
216219 else :
217- add_fields [class_name ][f"{ field_name } " ] = f"{ reference_name } " + is_optional + f"= Field({ default } )"
220+ add_fields [class_name ][f"{ camel_to_snake (field_name )} " ] = (
221+ f"{ reference_name } " + is_optional + f"= Field({ default } )"
222+ )
218223
219224 # import enums
220225 if is_list :
@@ -265,23 +270,23 @@ def create_sql_field(
265270 add_fields ["MANY" ][class_name ] = [[reference_name , field_name ]]
266271 elif reference_name not in add_fields ["MANY" ][class_name ]:
267272 add_fields ["MANY" ][class_name ].append ([reference_name , field_name ])
268- add_fields [class_name ][f"{ field_name } " ] = (
273+ add_fields [class_name ][f"{ camel_to_snake ( field_name ) } " ] = (
269274 f'List["{ reference_name } "] ='
270275 f' Relationship(back_populates="{ class_name .lower ()} _{ field_name .lower ()} _link", '
271276 f"link_model={ class_name } { field_name } Link)"
272277 )
273278 add_fields [reference_name ][f"{ class_name .lower ()} _{ field_name .lower ()} _link" ] = (
274279 f'List["{ class_name } "] ='
275- f' Relationship(back_populates="{ field_name } ", '
280+ f' Relationship(back_populates="{ camel_to_snake ( field_name ) } ", '
276281 f"link_model={ class_name } { field_name } Link)"
277282 )
278283 add_imports [class_name + "ADD" ][f"{ class_name } { field_name } Link)" ] = "Link"
279284 add_imports [reference_name + "ADD" ][f"{ class_name } { field_name } Link)" ] = "Link"
280285 else :
281286 # cf. https://github.com/tiangolo/sqlmodel/pull/610
282- add_fields [class_name ][f"{ field_name } _id" ] = (
287+ add_fields [class_name ][f"{ camel_to_snake ( field_name ) } _id" ] = (
283288 "uuid_pkg.UUID " + is_optional + f" = Field(sa_column=Column(UUID(as_uuid=True),"
284- f' ForeignKey("{ reference_name .lower ()} .{ reference_name . lower () } _sqlid "'
289+ f' ForeignKey("{ reference_name .lower ()} .id "'
285290 f', ondelete="SET NULL")))'
286291 )
287292 add_imports [class_name + "ADD" ]["Column" ] = "sqlalchemy"
@@ -291,20 +296,20 @@ def create_sql_field(
291296 # pylint: disable= fixme
292297 # todo: check default
293298
294- add_fields [class_name ][f"{ field_name } " ] = (
299+ add_fields [class_name ][f"{ camel_to_snake ( field_name ) } " ] = (
295300 f'"{ reference_name } " ='
296- f' Relationship(back_populates="{ class_name .lower ()} _{ field_name } ",'
297- f' sa_relationship_kwargs= {{ "foreign_keys":"[{ class_name } .{ field_name } _id]" }})'
301+ f' Relationship(back_populates="{ class_name .lower ()} _{ camel_to_snake ( field_name ) } ",'
302+ f' sa_relationship_kwargs= {{ "foreign_keys":"[{ class_name } .{ camel_to_snake ( field_name ) } _id]" }})'
298303 )
299304
300305 # cf. https://github.com/tiangolo/sqlmodel/issues/10
301306 # https://github.com/tiangolo/sqlmodel/issues/213
302307 # https://dev.to/whchi/disable-sqlmodel-foreign-key-constraint-55kp
303- add_fields [reference_name ][f"{ class_name .lower ()} _{ field_name } " ] = (
304- f'List["{ class_name } "] = Relationship(back_populates="{ field_name } ",'
308+ add_fields [reference_name ][f"{ class_name .lower ()} _{ camel_to_snake ( field_name ) } " ] = (
309+ f'List["{ class_name } "] = Relationship(back_populates="{ camel_to_snake ( field_name ) } ",'
305310 f"sa_relationship_kwargs="
306311 f'{{"primaryjoin":'
307- f' "{ class_name } .{ field_name } _id=={ reference_name } .{ reference_name . lower () } _sqlid ",'
312+ f' "{ class_name } .{ camel_to_snake ( field_name ) } _id=={ reference_name } .id ",'
308313 f' "lazy": "joined"}})'
309314 )
310315 # add_relation_import
@@ -346,11 +351,11 @@ def create_sql_any(
346351 if is_list :
347352 add_imports [class_name + "ADD" ]["List" ] = "typing"
348353 add_imports [class_name + "ADD" ]["ARRAY" ] = "sqlalchemy"
349- add_fields [class_name ][f"{ field_name } " ] = (
354+ add_fields [class_name ][f"{ camel_to_snake ( field_name ) } " ] = (
350355 "List[Any]" + is_optional + f" = Field({ default } ," f" sa_column=Column( ARRAY( PickleType)))"
351356 )
352357 else :
353- add_fields [class_name ][f"{ field_name } " ] = (
358+ add_fields [class_name ][f"{ camel_to_snake ( field_name ) } " ] = (
354359 "Any" + is_optional + f" = Field({ default } ," f" sa_column=Column( PickleType))"
355360 )
356361
@@ -365,13 +370,27 @@ def write_many_many_links(links: dict[str, str]) -> str:
365370 environment = Environment (loader = FileSystemLoader (template_path ))
366371 template = environment .get_template ("ManyLinks.jinja2" )
367372 python_code = template .render ({"class" : links })
368- python_code = format_code (python_code )
373+ # python_code = format_code(python_code)
369374 return python_code
370375
371376
372- def format_code (code : str ) -> str :
377+ def remove_unused_imports (code ) :
373378 """
374- perform isort and black on code
379+ Removes unused imports from the given code using autoflake.
375380 """
376- code = black .format_str (code , mode = black .Mode ())
377- return isort .code (code , known_local_folder = ["borm" ])
381+ # Create a temporary file
382+ with tempfile .NamedTemporaryFile (suffix = ".py" , delete = False ) as tmp_file :
383+ tmp_file_name = tmp_file .name
384+ tmp_file .write (code .encode ("utf-8" ))
385+
386+ # Run autoflake to remove unused imports
387+ subprocess .run (["autoflake" , "--remove-all-unused-imports" , "--in-place" , tmp_file_name ], check = True )
388+
389+ # Read the cleaned code from the temporary file
390+ with open (tmp_file_name , "r" , encoding = "utf-8" ) as tmp_file :
391+ cleaned_code = tmp_file .read ()
392+
393+ # Clean up the temporary file
394+ os .remove (tmp_file_name )
395+
396+ return cleaned_code
0 commit comments