How to edit the DocType from python?

Hello beautiful people,

I would like for a custom app to be able to modify a particular DocType at runtime.

If I run:
frappe.db.get_list(“DocType”)

I get an error:

In [71]: frappe.db.get_list("DocType")
---------------------------------------------------------------------------
InterfaceError                            Traceback (most recent call last)
/workspace/development/frappe-bench/apps/frappe/frappe/commands/utils.py in <module>()
----> 1 frappe.db.get_list("DocType")

/workspace/development/frappe-bench/apps/frappe/frappe/database/database.py in get_list(*args, **kwargs)
    530         @staticmethod
    531         def get_list(*args, **kwargs):
--> 532                 return frappe.get_list(*args, **kwargs)
    533 
    534         def get_single_value(self, doctype, fieldname, cache=False):

/workspace/development/frappe-bench/apps/frappe/frappe/__init__.py in get_list(doctype, *args, **kwargs)
   1288         """
   1289         import frappe.model.db_query
-> 1290         return frappe.model.db_query.DatabaseQuery(doctype).execute(None, *args, **kwargs)
   1291 
   1292 def get_all(doctype, *args, **kwargs):

/workspace/development/frappe-bench/apps/frappe/frappe/model/db_query.py in execute(self, query, fields, filters, or_filters, docstatus, group_by, order_by, limit_start, limit_page_length, as_list, with_childnames, debug, ignore_permissions, user, with_comment_count, join, distinct, start, page_length, limit, ignore_ifnull, save_user_settings, save_user_settings_fields, update, add_total_row, user_settings, reference_doctype, return_query, strict)
     94                         result = self.run_custom_query(query)
     95                 else:
---> 96                         result = self.build_and_run()
     97                         if return_query:
     98                                 return result

/workspace/development/frappe-bench/apps/frappe/frappe/model/db_query.py in build_and_run(self)
    108 
    109         def build_and_run(self):
--> 110                 args = self.prepare_args()
    111                 args.limit = self.add_limit()
    112 

/workspace/development/frappe-bench/apps/frappe/frappe/model/db_query.py in prepare_args(self)
    135                 self.extract_tables()
    136                 self.set_optional_columns()
--> 137                 self.build_conditions()
    138 
    139                 args = frappe._dict()

/workspace/development/frappe-bench/apps/frappe/frappe/model/db_query.py in build_conditions(self)
    332                 # match conditions
    333                 if not self.flags.ignore_permissions:
--> 334                         match_conditions = self.build_match_conditions()
    335                         if match_conditions:
    336                                 self.conditions.append("(" + match_conditions + ")")

/workspace/development/frappe-bench/apps/frappe/frappe/model/db_query.py in build_match_conditions(self, as_condition)
    542                 meta = frappe.get_meta(self.doctype)
    543                 role_permissions = frappe.permissions.get_role_permissions(meta, user=self.user)
--> 544                 self.shared = frappe.share.get_shared(self.doctype, self.user)
    545 
    546                 if (not meta.istable and

/workspace/development/frappe-bench/apps/frappe/frappe/share.py in get_shared(doctype, user, rights)
    122                 fields=['share_name'],
    123                 filters=filters,
--> 124                 or_filters=or_filters)
    125 
    126         return [doc.share_name for doc in shared_docs]

/workspace/development/frappe-bench/apps/frappe/frappe/database/database.py in get_all(*args, **kwargs)
    526         @staticmethod
    527         def get_all(*args, **kwargs):
--> 528                 return frappe.get_all(*args, **kwargs)
    529 
    530         @staticmethod

/workspace/development/frappe-bench/apps/frappe/frappe/__init__.py in get_all(doctype, *args, **kwargs)
   1315         if not "limit_page_length" in kwargs:
   1316                 kwargs["limit_page_length"] = 0
-> 1317         return get_list(doctype, *args, **kwargs)
   1318 
   1319 def get_value(*args, **kwargs):

/workspace/development/frappe-bench/apps/frappe/frappe/__init__.py in get_list(doctype, *args, **kwargs)
   1288         """
   1289         import frappe.model.db_query
-> 1290         return frappe.model.db_query.DatabaseQuery(doctype).execute(None, *args, **kwargs)
   1291 
   1292 def get_all(doctype, *args, **kwargs):

/workspace/development/frappe-bench/apps/frappe/frappe/model/db_query.py in execute(self, query, fields, filters, or_filters, docstatus, group_by, order_by, limit_start, limit_page_length, as_list, with_childnames, debug, ignore_permissions, user, with_comment_count, join, distinct, start, page_length, limit, ignore_ifnull, save_user_settings, save_user_settings_fields, update, add_total_row, user_settings, reference_doctype, return_query, strict)
     94                         result = self.run_custom_query(query)
     95                 else:
---> 96                         result = self.build_and_run()
     97                         if return_query:
     98                                 return result

/workspace/development/frappe-bench/apps/frappe/frappe/model/db_query.py in build_and_run(self)
    128                         return query
    129                 else:
--> 130                         return frappe.db.sql(query, as_dict=not self.as_list, debug=self.debug, update=self.update)
    131 
    132         def prepare_args(self):

/workspace/development/frappe-bench/apps/frappe/frappe/database/database.py in sql(self, query, values, as_dict, as_list, formatted, debug, ignore_ddl, as_utf8, auto_commit, update, explain)
    169                                         frappe.log(">>>>")
    170 
--> 171                                 self._cursor.execute(query)
    172 
    173                                 if frappe.flags.in_migrate:

/workspace/development/frappe-bench/env/lib/python3.7/site-packages/pymysql/cursors.py in execute(self, query, args)
    168         query = self.mogrify(query, args)
    169 
--> 170         result = self._query(query)
    171         self._executed = query
    172         return result

/workspace/development/frappe-bench/env/lib/python3.7/site-packages/pymysql/cursors.py in _query(self, q)
    326         self._last_executed = q
    327         self._clear_result()
--> 328         conn.query(q)
    329         self._do_get_result()
    330         return self.rowcount

/workspace/development/frappe-bench/env/lib/python3.7/site-packages/pymysql/connections.py in query(self, sql, unbuffered)
    514             else:
    515                 sql = sql.encode(self.encoding, 'surrogateescape')
--> 516         self._execute_command(COMMAND.COM_QUERY, sql)
    517         self._affected_rows = self._read_query_result(unbuffered=unbuffered)
    518         return self._affected_rows

/workspace/development/frappe-bench/env/lib/python3.7/site-packages/pymysql/connections.py in _execute_command(self, command, sql)
    748         """
    749         if not self._sock:
--> 750             raise err.InterfaceError("(0, '')")
    751 
    752         # If the last query was unbuffered, make sure it finishes before

Do you know what is the correct way to use Python API to edit a DocType?

explain your use case,

I am working on an app to manage libraries of electronic components. Electronic softwares are very dumb, and require a table in the following format:

Component Name, Supplier 1, Supplier Part Number 1, Supplier 2, Supplier Part Number 2, etc etc

A “Component” has a child table with Suppliers and Supplier Part Numbers.
As such, I would like to update a DocType dinamically, so that, for example, new culumns “Supplier 3” and “Supplier Part Number 3” are added automatically when necessary and removed when necessary.

The resulting DocType would then be available over API as usual.

@dfermiumlabs it’s not a good idea change the doctype during runtime

The issue you are facing, is because you are trying to read an table, at the same transation that is trying to alter the table.

When you create a doctype, it changes the another table, not the doctype table itself, so, you never will perceive that issue.

It’s not one issue from frappe, but an integrity feature from the database itself.

I’ll suggest you to find other ways to store your data, like in a JSON, that can be searched in the database queries, using the native JSON functions.

https://mariadb.com/kb/en/json-functions/