Where And How To Write and Run a Python Script

So, I’m working on a script that maps tables stored in a SQL Express database to DocTypes, which the script creates if they don’t exist yet (or updates if they do).

Now, I need to know how to make sure that the script works with the currently running site.

Here’s the problem, fellas: so, I’ve been encountering an error that occurs when the interpreter hits the line that calls and passes a dictionary object to frappe.get_doc. The error, the traceback for which I’ll provide later once I’ll be on the computer, is RuntimeError('no object bound to %s' % self.__name__)

According to one source, “associating” the script with your site should solve the problem like so:

frappe.init_site(sitename) frappe.connect()

Sadly, of course, this doesn’t work for me. I get some error that says AttributeError: conf.

Please help. I have invested so much this and want my family to be happy, including kids who aren’t even mine (I forgive you, Hannah…)

Alright. Let me wipe the snot off my sleeve and think about something good for once—like someone being nice enough to come here and save the day for some erratic stranger who seems to be unable to do something as simple as map data together. Jesus Lord Mother of God have mercy…

That should ideally work. Share the full trace of your error… Also share your script!

:laughing:

1 Like

@rmehta

Yo! Glad you enjoyed my tear-stained letter.

Alright, so the AttributeError is gone (for now)… At the beginning of the file I have frappe.init_site('frappe.local.erptest')

When I run the script, which I’ll paste once I’m on my computer, I get that pesky “no object bound to db” error again, and the traceback starts with the line that calls get_doc.

What’s really goddamned weird is that when I call frappe.connect(‘frappe.local.erptest’), I’m told that the site doesn’t exist (even though there are no complaints about init_site). Interesting…

Would be better if you paste the traceback here

Will definitely do later today.

Alright! Here it is:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "sql2doctype.py", line 49, in sync
    add_doc(fields)
  File "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 29, in get_controller
    module_name, custom = frappe.db.get_value("DocType", doctype, ["module", "custom"]) \
  File "/home/vongol/frappe-bench/env/local/lib/python2.7/site-packages/werkzeug/local.py", line 347, in __getattr__
    return getattr(self._get_current_object(), name)
  File "/home/vongol/frappe-bench/env/local/lib/python2.7/site-packages/werkzeug/local.py", line 310, in _get_current_object
    raise RuntimeError('no object bound to %s' % self.__name__)
RuntimeError: no object bound to db

And here’s what happens when I try to “solve” that “no object bound to db” problem by including frappe.connect() at the beginning of the script:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "sql2doctype.py", line 6, in <module>
    frappe.connect()
  File "/home/vongol/frappe-bench/apps/frappe/frappe/__init__.py", line 170, in connect
    local.db = Database(user=db_name or local.conf.db_name)
  File "/home/vongol/frappe-bench/env/local/lib/python2.7/site-packages/werkzeug/local.py", line 72, in __getattr__
    raise AttributeError(name)
AttributeError: conf
import frappe
from frappe.model.document import Document
import pyodbc

frappe.init_site('frappe.local.test')
frappe.connect()

### 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)

Update:

So, I managed to finally circumvent this problem by figuring out how to execute the script via bench. But, since frappe is no fun without constant errors around every corner, I gotta deal with a new AttributeError:

You might also want to try GitHub - frappe/frappe-client: Python library to use Frappe API

Else put your script in a custom app and call it with bench --site [sitename] execute [path.to.method]

Yep, I made a custom app and called it with bench, so I am no longer experiencing the original problem stated here.

However, a new problem has popped up, and I enclosed a link to it above. I’ll take a look at the link you just included.