prestapyt / prestapyt

Prestapyt is a library for Python to interact with the PrestaShop's Web Service API.
GNU Affero General Public License v3.0
89 stars 100 forks source link

Error on Edit: 'NoneType' object has no attribute 'nodeType' #28

Open waltervargas opened 10 years ago

waltervargas commented 10 years ago

Greetings Guewen,

I am have the next error when try to edit a record on prestashop:

2014-10-20 04:14:22,393 12224 ERROR salling openerp.addons.connector.queue.worker: Traceback (most recent call last):
  File "/opt/openerp/addons-connector/connector/queue/worker.py", line 123, in run_job
    job.perform(session)
  File "/opt/openerp/addons-connector/connector/queue/job.py", line 490, in perform
    self.result = self.func(session, *self.args, **self.kwargs)
  File "/opt/openerp/addons-connector/prestashoperpconnect/unit/export_synchronizer.py", line 243, in export_product
    return product_exporter.run(record_id, fields)
  File "/opt/openerp/addons-connector/prestashoperpconnect/unit/export_synchronizer.py", line 81, in run
    result = self._run(*args, **kwargs)
  File "/opt/openerp/addons-connector/prestashoperpconnect/unit/export_synchronizer.py", line 155, in _run
    self._update(record)
  File "/opt/openerp/addons-connector/prestashoperpconnect/unit/export_synchronizer.py", line 131, in _update
    self.backend_adapter.write(self.prestashop_id, data)
  File "/opt/openerp/addons-connector/prestashoperpconnect/unit/backend_adapter.py", line 156, in write
    return api.edit(self._prestashop_model, id, content)
  File "/usr/local/lib/python2.7/dist-packages/prestapyt/prestapyt.py", line 364, in edit
    return self.edit_with_url(full_url, content)
  File "/usr/local/lib/python2.7/dist-packages/prestapyt/prestapyt.py", line 516, in edit_with_url
    xml_content = dict2xml.dict2xml({'prestashop': content})
  File "/usr/local/lib/python2.7/dist-packages/prestapyt/dict2xml.py", line 119, in dict2xml
    root, _ = _process_complex(doc, data.items())
  File "/usr/local/lib/python2.7/dist-packages/prestapyt/dict2xml.py", line 71, in _process_complex
    nodes = _process(doc, tag, value)
  File "/usr/local/lib/python2.7/dist-packages/prestapyt/dict2xml.py", line 49, in _process
    nodelist, attrs = _process_complex(doc, tag_value.items())
  File "/usr/local/lib/python2.7/dist-packages/prestapyt/dict2xml.py", line 71, in _process_complex
    nodes = _process(doc, tag, value)
  File "/usr/local/lib/python2.7/dist-packages/prestapyt/dict2xml.py", line 51, in _process
    node.appendChild(child)
  File "/usr/lib/python2.7/xml/dom/minidom.py", line 112, in appendChild
    if node.nodeType == self.DOCUMENT_FRAGMENT_NODE:
AttributeError: 'NoneType' object has no attribute 'nodeType'

I am doing this for edit a record on prestashoperpconnect.unit.backend_adapter:

    def write(self, id, attributes=None):                                                                                                                                                        
        """ Update records on the external system """                                                                                                                                            
        api = self.connect()                                                                                                                                                                     
        attributes['id'] = id                                                                                                                                                                    
        content = api.get(self._prestashop_model, resource_id=id)                                                                                                                                
        key = content.items()[0][0]                                                                                                                                                              
        content.get(key).update(attributes)                                                                                                                                                      
        return api.edit(self._prestashop_model, id, content) 

Please help when you have time, I will try to fix it tomorrow, some advice ?

Thanks. Best Regards.

mohitg1312 commented 10 years ago

See #27 (comment)

hailangvn commented 3 years ago

Good day All, I encountered similar issue.

Traceback (most recent call last):
  File "/media/trobz/c2c/rensales_odoo/odoo/external-src/queue/queue_job/controllers/main.py", line 73, in runjob
    self._try_perform_job(env, job)
  File "/media/trobz/c2c/rensales_odoo/odoo/external-src/queue/queue_job/controllers/main.py", line 32, in _try_perform_job
    job.perform()
  File "/media/trobz/c2c/rensales_odoo/odoo/external-src/queue/queue_job/job.py", line 505, in perform
    self.result = self.func(*tuple(self.args), **self.kwargs)
  File "/media/trobz/c2c/rensales_odoo/odoo/external-src/connector-prestashop/connector_prestashop/models/binding/common.py", line 66, in export_record
    return exporter.run(self, fields)
  File "/media/trobz/c2c/rensales_odoo/odoo/external-src/connector-prestashop/connector_prestashop/components/exporter.py", line 51, in run
    result = self._run(*args, **kwargs)
  File "/media/trobz/c2c/rensales_odoo/odoo/external-src/connector-prestashop/connector_prestashop/components/exporter.py", line 333, in _run
    self.prestashop_id = self._create(record)
  File "/media/trobz/c2c/rensales_odoo/odoo/external-src/connector-prestashop/connector_prestashop_catalog_manager/models/product_template/exporter.py", line 37, in _create
    res = super()._create(record)
  File "/media/trobz/c2c/rensales_odoo/odoo/external-src/connector-prestashop/connector_prestashop/components/exporter.py", line 256, in _create
    return self.backend_adapter.create(data)
  File "/media/trobz/c2c/rensales_odoo/odoo/external-src/connector-prestashop/connector_prestashop/components/backend_adapter.py", line 232, in create
    res = self.client.add(
  File "/opt/odoo/14_env/lib/python3.8/site-packages/prestapyt/prestapyt.py", line 348, in add
    return self.add_with_url(full_url, content, files)
  File "/opt/odoo/14_env/lib/python3.8/site-packages/prestapyt/prestapyt.py", line 636, in add_with_url
    xml_content = dict2xml.dict2xml({'prestashop': content})
  File "/opt/odoo/14_env/lib/python3.8/site-packages/prestapyt/dict2xml.py", line 124, in dict2xml
    root, _ = _process_complex(doc, list(data.items()))
  File "/opt/odoo/14_env/lib/python3.8/site-packages/prestapyt/dict2xml.py", line 76, in _process_complex
    nodes = _process(doc, tag, value)
  File "/opt/odoo/14_env/lib/python3.8/site-packages/prestapyt/dict2xml.py", line 54, in _process
    nodelist, attrs = _process_complex(doc, list(tag_value.items()))
  File "/opt/odoo/14_env/lib/python3.8/site-packages/prestapyt/dict2xml.py", line 76, in _process_complex
    nodes = _process(doc, tag, value)
  File "/opt/odoo/14_env/lib/python3.8/site-packages/prestapyt/dict2xml.py", line 56, in _process
    node.appendChild(child)
  File "/usr/lib/python3.8/xml/dom/minidom.py", line 114, in appendChild
    if node.nodeType == self.DOCUMENT_FRAGMENT_NODE:
AttributeError: 'NoneType' object has no attribute 'nodeType'

That was because _process_complex could not process this piece of data 'available_date': datetime.date(2021, 5, 24) thus the node was None. Current fix is to convert the date to string before sending out.

# connector_prestashop_catalog_manager/models/product_template/exporter.py
class ProductTemplateExporter(Component):
    # ...
    @mapping
    def available_date(self, record):
        if record.available_date:
            return {"available_date": record.available_date.strftime('%Y-%m-%d')}
        return {}

The proposed solution is to add simple process for date and time as below.

# prestapyt/dict2xml.py
def _process(doc, tag, tag_value):
    # ...
    # Create a new node for simple values
    fmt = []
    if isinstance(tag_value, (datetime, date)):
        fmt.append('%Y-%m-%d')
    if isinstance(tag_value, (datetime, time)):
        fmt.append('%H:%M:%S')
    if fmt:
        tag_value = tag_value.strftime(' '.join(fmt))
    if (isinstance(tag_value, (float, int)) or
            isinstance(tag_value, basestring)):
        return _process_simple(doc, tag, tag_value)
    # ...