Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

string values with single quotes break function calls #607

Open
jacksund opened this issue Sep 27, 2023 · 1 comment
Open

string values with single quotes break function calls #607

jacksund opened this issue Sep 27, 2023 · 1 comment

Comments

@jacksund
Copy link
Contributor

summary

Whenever I have a mixture of quotes, paratheses, and numbers in a string, django-unicorn fails to parse the string on the backend. An example string where this fails would be:

"Chloro(2-dicyclohexylphosphino-3,6-dimethoxy-2',4',6'-tri-i-propyl-1,1'-biphenyl)(2'-amino-1,1'-biphenyl-2-yl)palladium(II)"

Based on the error traceback, it looks like the quote aren't wrapped properly via JSON serialization, which then cause the value
to be broken up / buggy in python:

set_new_catalyst('Chloro(2-dicyclohexylphosphino-3,6-dimethoxy-2',4',6'-tri-i-propyl-1,1'-biphenyl)(2'-amino-1,1'-biphenyl-2-yl)palladium(II)')

code

(only the relevant code blocks are shown for simplicity)

python

class ExampleView(UnicornView):
    class Meta:
        javascript_exclude = (
            "catalyst_options",
            # ... plus others
        )

    catalysts = []
    new_catalyst = None
    new_catalyst_equiv = None

    @property
    def catalyst_options(self):
        # This method normally pulls from a database model, but I just put a
        # list as an example
        return [
            "APhos Pd G3",
            "Bis(1,5-cyclooctadiene)nickel(0)",
            # SELECTING THIS STRING FAILS WITH ERROR SHOWN BELOW <------------------------- !!!!
            "Chloro(2-dicyclohexylphosphino-3,6-dimethoxy-2',4',6'-tri-i-propyl-1,1'-biphenyl)(2'-amino-1,1'-biphenyl-2-yl)palladium(II)",  
        ]

    def set_new_catalyst(self, new_catalyst):
        self.new_catalyst = new_catalyst

    def add_new_catalyst(self):
        new_catalyst = [self.new_catalyst, self.new_catalyst_equiv]
        self.catalysts.append(new_catalyst)
        # reset for next addition
        self.new_catalyst = None
        self.new_catalyst_equiv = None

    def remove_catalyst(self, remove_idx):
        self.catalysts.pop(remove_idx)

django html template

The key line where the error happens:

onchange="Unicorn.call('screeningrequest-new', 'set_new_catalyst', $('#new_catalyst').val());"

The full section for this variable:

<div class="col-sm">
    <label class="form-label">Catalysts</label>
    <table class="table table-centered mb-0">
        <thead>
            <tr>
                <th>
                    <small>Compound</small>
                </th>
                <th>
                    <small>Equivalents</small>
                </th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            {% for entry in catalysts %}
                <tr>
                    <td>{{ entry.0 }}</td>
                    <td>{{ entry.1 }}</td>
                    <td>
                        <button unicorn:click="remove_catalyst({{ forloop.counter0 }})"
                                type="button"
                                class="btn btn-danger btn-sm">
                            <i class="mdi mdi-minus"></i>
                        </button>
                    </td>
                </tr>
            {% endfor %}
            {# Add New Catalyst #}
            <tr>
                <td>
                    <div unicorn:ignore class="my-2">
                        <select id="new_catalyst"
                                class="select2 form-control"
                                data-toggle="select2"
                                data-placeholder="Choose one ..."
                                onchange="Unicorn.call('screeningrequest-new', 'set_new_catalyst', $('#new_catalyst').val());">
                            <option value="NONE">Choose one...</option>
                            {% for catalyst in catalyst_options %}<option value="{{ catalyst }}">{{ catalyst }}</option>{% endfor %}
                        </select>
                    </div>
                </td>
                {# Expected Equivalents #}
                <td>
                    <input unicorn:model.defer="new_catalyst_equiv"
                            type="number"
                            id="new_catalyst_equiv"
                            class="form-control"
                            placeholder="0.123">
                </td>
                {# Add button #}
                <td>
                    <button unicorn:click="add_new_catalyst"
                            type="button"
                            class="btn btn-success btn-sm">
                        <i class="mdi mdi-plus"></i>
                    </button>
                </td>
            </tr>
        </tbody>
    </table>
</div>

The error traceback

Internal Server Error: /unicorn/message/screeningrequest-new
Traceback (most recent call last):
  File "C:\Users\nxj625\AppData\Local\anaconda3\envs\simmate_dev\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nxj625\AppData\Local\anaconda3\envs\simmate_dev\Lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<decorator-gen-43>", line 2, in message
  File "C:\Users\nxj625\AppData\Local\anaconda3\envs\simmate_dev\Lib\site-packages\django_unicorn\decorators.py", line 21, in timed
    result = func(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nxj625\AppData\Local\anaconda3\envs\simmate_dev\Lib\site-packages\django_unicorn\views\__init__.py", line 44, in wrapped_view
    return view_func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nxj625\AppData\Local\anaconda3\envs\simmate_dev\Lib\site-packages\django\utils\decorators.py", line 134, in _wrapper_view
    response = view_func(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nxj625\AppData\Local\anaconda3\envs\simmate_dev\Lib\site-packages\django\views\decorators\http.py", line 43, in inner
    return func(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nxj625\AppData\Local\anaconda3\envs\simmate_dev\Lib\site-packages\django_unicorn\views\__init__.py", line 535, in message
    json_result = _handle_component_request(request, component_request)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nxj625\AppData\Local\anaconda3\envs\simmate_dev\Lib\site-packages\django_unicorn\views\__init__.py", line 381, in _handle_component_request
    return _process_component_request(request, component_request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nxj625\AppData\Local\anaconda3\envs\simmate_dev\Lib\site-packages\django_unicorn\views\__init__.py", line 123, in _process_component_request
    ) = call_method.handle(component_request, component, action.payload)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nxj625\AppData\Local\anaconda3\envs\simmate_dev\Lib\site-packages\django_unicorn\views\action_parsers\call_method.py", line 22, in handle
    (method_name, args, kwargs) = parse_call_method_name(call_method_name)
                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nxj625\AppData\Local\anaconda3\envs\simmate_dev\Lib\site-packages\django_unicorn\call_method_parser.py", line 158, in parse_call_method_name
    tree = ast.parse(method_name, "eval")
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nxj625\AppData\Local\anaconda3\envs\simmate_dev\Lib\ast.py", line 50, in parse
    return compile(source, filename, mode, flags,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "eval", line 1
    set_new_catalyst('Chloro(2-dicyclohexylphosphino-3,6-dimethoxy-2',4',6'-tri-i-propyl-1,1'-biphenyl)(2'-amino-1,1'-biphenyl-2-yl)palladium(II)')
                                                                      ^^^^^^^^^^^^^^^^^^^^
SyntaxError: invalid syntax. Perhaps you forgot a comma?
@adamghill
Copy link
Owner

Thanks for this issue, I'll take a look when I can.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants