So, I’m working on a script that maps SQL data to DocTypes, which it creates if they don’t exist yet and updates if they do.
The strange error above occurs after the interpreter reaches the line in the code that creates a new DocType using the SQL data, which is stored in a dictionary. The bottom of the traceback shows the culprit: the String replace() method being run:
File “/home/vongol/frappe-bench/apps/frappe/frappe/init.py”, line 692, in scrub
return txt.replace(’ ‘,’‘).replace(’-', '').lower()
Here’s the whole traceback and the code:
Traceback (most recent call last):
File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
exec code in run_globals
File "/home/vongol/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 94, in <module>
main()
File "/home/vongol/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 18, in main
click.Group(commands=commands)(prog_name='bench')
File "/home/vongol/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py", line 722, in __call__
return self.main(*args, **kwargs)
File "/home/vongol/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py", line 697, in main
rv = self.invoke(ctx)
File "/home/vongol/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py", line 1066, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/vongol/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py", line 1066, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/vongol/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py", line 895, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/vongol/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py", line 535, in invoke
return callback(*args, **kwargs)
File "/home/vongol/frappe-bench/env/local/lib/python2.7/site-packages/click/decorators.py", line 17, in new_func
return f(get_current_context(), *args, **kwargs)
File "/home/vongol/frappe-bench/apps/frappe/frappe/commands/__init__.py", line 24, in _func
ret = f(frappe._dict(ctx.obj), *args, **kwargs)
File "/home/vongol/frappe-bench/apps/frappe/frappe/commands/utils.py", line 113, in execute
ret = frappe.get_attr(method)(*args, **kwargs)
File "/home/vongol/frappe-bench/apps/sql2doctype/sql2doctype/sql2doctype/sql2doctype.py", line 51, in sync
add_doc(fields)
File "/home/vongol/frappe-bench/apps/sql2doctype/sql2doctype/sql2doctype/sql2doctype.py", line 17, in add_doc
doc = frappe.get_doc(fields, fields['LAST_NAME'])
File "/home/vongol/frappe-bench/apps/frappe/frappe/__init__.py", line 622, in get_doc
return frappe.model.document.get_doc(arg1, arg2)
File "/home/vongol/frappe-bench/apps/frappe/frappe/model/document.py", line 49, in get_doc
controller = get_controller(doctype)
File "/home/vongol/frappe-bench/apps/frappe/frappe/model/base_document.py", line 35, in get_controller
module = load_doctype_module(doctype, module_name)
File "/home/vongol/frappe-bench/apps/frappe/frappe/modules/utils.py", line 179, in load_doctype_module
module_name = get_module_name(doctype, module, prefix, suffix)
File "/home/vongol/frappe-bench/apps/frappe/frappe/modules/utils.py", line 193, in get_module_name
doctype = scrub(doctype),
File "/home/vongol/frappe-bench/apps/frappe/frappe/modules/utils.py", line 133, in scrub
return frappe.scrub(txt)
File "/home/vongol/frappe-bench/apps/frappe/frappe/__init__.py", line 692, in scrub
return txt.replace(' ','_').replace('-', '_').lower()
AttributeError: 'NoneType' object has no attribute 'replace'
import frappe
from frappe.model.document import Document
import pyodbc
frappe.init_site('frappe.local.test')
#frappe.connect(frappe.conf.get("db_name"))
### Initialize connection and cursor ###
cnxn = pyodbc.connect('DRIVER={ODBC Driver 13 For SQL Server}; SERVER=localhost; DATABASE=testdb; UID=SA; PWD=xyzzy209!')
cursor = cnxn.cursor()
### Query functions ###
# Add a DocType by passing a dictionary to the get_doc function.
def add_doc(fields):
doc = frappe.get_doc(fields, fields['LAST_NAME'])
doc.insert()
# "Synchronize" function. Maps SQL data in table to DocTypes, adding new DocTypes and/or upgrading them when applicable.
def sync(query):
#query = 'SELECT * FROM \"%s\"' % table
#cursor.execute(query, table)
cursor.execute(query)
doctypes = []
records = []
columns = [column[0] for column in cursor.description]
# Iterate through each row and pass a dictionary containing its column names as keys and respective values to add_doc.
# Use id field to designate each SQL table and ease searching and updating.
for row in cursor.fetchall():
count = 0
fields = dict(zip(columns, row))
'''
if doctypes is not None:
for doctype in doctypes:
if fields["ID"] == doctype["ID"] and fields != doctype:
for field in fields:
doc_field = getattr(doctype, field)
db_field = fields[field]
if doc_field != db_field:
pass
else:
'''
add_doc(fields)
count += 1
print("Added %d doc" % count)