Skip to content

Commit

Permalink
Allow docstring to use single quotes and to not be displayed
Browse files Browse the repository at this point in the history
By specifying None for the docstring no docstring is displayed. By
specifying the quotation mark in the docstring the docstring is not
put into triple quotes allowing a docstring in signle quotes.

The implementation puts the responsibility to add the correct quotation
marks to the python side so we can be more flexible.
  • Loading branch information
agoscinski committed Dec 11, 2024
1 parent 3b0e400 commit eea2717
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 19 deletions.
91 changes: 80 additions & 11 deletions example/example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
"execution_count": null,
"execution_count": 2,
"id": "5df2c405",
"metadata": {},
"outputs": [],
Expand All @@ -25,39 +25,84 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 3,
"id": "e74c9c9e",
"metadata": {
"scrolled": true
},
"outputs": [],
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "37da5497bfed438c8626bde64058dca8",
"version_major": 2,
"version_minor": 1
},
"text/plain": [
"WidgetCodeInput(code_theme='basicLight', docstring='\"\"\"\\n Input docstring here.\\n\"\"\"', function_body='# Give…"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 4,
"id": "4d389a14",
"metadata": {},
"outputs": [],
"outputs": [
{
"ename": "CodeValidationError",
"evalue": "SyntaxError in code input: unexpected indent\nFile \"widget_code_input\", line 3\n Input docstring here.\n ^\n",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mIndentationError\u001b[0m Traceback (most recent call last)",
"File \u001b[0;32m~/code/widget-code-input/src/widget_code_input/__init__.py:156\u001b[0m, in \u001b[0;36mWidgetCodeInput.get_function_object\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 154\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 155\u001b[0m exec(\n\u001b[0;32m--> 156\u001b[0m \u001b[38;5;28;43mcompile\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfull_function_code\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;18;43m__name__\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mexec\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdont_inherit\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m)\u001b[49m,\n\u001b[1;32m 157\u001b[0m globals_dict,\n\u001b[1;32m 158\u001b[0m )\n\u001b[1;32m 159\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mSyntaxError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m exc:\n",
"\u001b[0;31mIndentationError\u001b[0m: unexpected indent (widget_code_input, line 3)",
"\nThe above exception was the direct cause of the following exception:\n",
"\u001b[0;31mCodeValidationError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[4], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m my_function \u001b[38;5;241m=\u001b[39m \u001b[43mw\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_function_object\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
"File \u001b[0;32m~/code/widget-code-input/src/widget_code_input/__init__.py:160\u001b[0m, in \u001b[0;36mWidgetCodeInput.get_function_object\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 155\u001b[0m exec(\n\u001b[1;32m 156\u001b[0m \u001b[38;5;28mcompile\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfull_function_code, \u001b[38;5;18m__name__\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mexec\u001b[39m\u001b[38;5;124m\"\u001b[39m, dont_inherit\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m),\n\u001b[1;32m 157\u001b[0m globals_dict,\n\u001b[1;32m 158\u001b[0m )\n\u001b[1;32m 159\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mSyntaxError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m exc:\n\u001b[0;32m--> 160\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m CodeValidationError(\n\u001b[1;32m 161\u001b[0m format_syntax_error_msg(exc), orig_exc\u001b[38;5;241m=\u001b[39mexc\n\u001b[1;32m 162\u001b[0m ) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mexc\u001b[39;00m\n\u001b[1;32m 164\u001b[0m function_object \u001b[38;5;241m=\u001b[39m globals_dict[\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfunction_name]\n\u001b[1;32m 166\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcatch_exceptions\u001b[39m(func):\n",
"\u001b[0;31mCodeValidationError\u001b[0m: SyntaxError in code input: unexpected indent\nFile \"widget_code_input\", line 3\n Input docstring here.\n ^\n"
]
}
],
"source": [
"my_function = w.get_function_object()"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 5,
"id": "2fc2b3ed",
"metadata": {},
"outputs": [],
"outputs": [
{
"ename": "NameError",
"evalue": "name 'my_function' is not defined",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[5], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mmy_function\u001b[49m(\u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m)\n",
"\u001b[0;31mNameError\u001b[0m: name 'my_function' is not defined"
]
}
],
"source": [
"my_function(1, 2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 6,
"id": "e90010bd",
"metadata": {},
"outputs": [],
Expand All @@ -67,10 +112,26 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 7,
"id": "75900629",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "15846da8fc8943bd9cb21bd505ca0174",
"version_major": 2,
"version_minor": 1
},
"text/plain": [
"WidgetCodeInput(code_theme='basicLight', docstring='\"\"\"\\n Input docstring here.\\n\"\"\"', function_body='# Give…"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w2 = WidgetCodeInput(\n",
" function_name = \"my_function\",\n",
Expand All @@ -83,6 +144,14 @@
")\n",
"w2"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cabf4027",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand All @@ -101,7 +170,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.15"
"version": "3.11.10"
}
},
"nbformat": 4,
Expand Down
2 changes: 1 addition & 1 deletion js/widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ function signatureValueChanged() {
// Set the value from python into the CodeMirror widget in the
// frontend.

const newDocstring = '"""' + model.get('docstring') + '"""';
const newDocstring = model.get('docstring');

if (newDocstring !== myDocstringCodeMirror.state.doc.toString()) {
myDocstringCodeMirror.dispatch({
Expand Down
12 changes: 8 additions & 4 deletions src/widget_code_input/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ def _valid_docstring(self, docstring):
"""
Validate that the docstring do not contain triple double quotes
"""
if '"""' in docstring['value']:
raise TraitError('The docstring cannot contain triple double quotes (""")')
return docstring['value']


Expand All @@ -73,7 +71,7 @@ def __init__( # pylint: disable=too-many-arguments
self,
function_name,
function_parameters="",
docstring="\n",
docstring=None,
function_body="",
code_theme="basicLight",
):
Expand All @@ -94,7 +92,13 @@ def __init__( # pylint: disable=too-many-arguments

self.function_name = function_name
self.function_parameters = function_parameters
self.docstring = docstring
if docstring is None:
self.docstring = ""
elif docstring.startswith("\"") and docstring.endswith("\""):
# assume the quotation marks have been added so we do not need to add them
self.docstring = docstring
else:
self.docstring = f"\"\"\"{docstring}\"\"\""
self.function_body = function_body
self.code_theme = code_theme
self.widget_instance_count_trait=f"{WidgetCodeInput.widget_instance_count}"
Expand Down
5 changes: 2 additions & 3 deletions src/widget_code_input/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,11 @@ def build_pre_body(signature, docstring, indent_level=4):
:param docstring: the (unindented) docstring
:param indent_level: integer number of spaces to prepend to the docstring
"""
if '"""' in docstring:
raise ValueError('Triple double quotes (""") not allowed in docstring')

return "{}\n{}".format(
signature,
prepend_indent('"""{}"""'.format(docstring), indent_level=indent_level),
prepend_indent('' if docstring is None else '"""{}"""'.format(docstring),
indent_level=indent_level),
)


Expand Down

0 comments on commit eea2717

Please sign in to comment.