Skip to content

Commit eea2717

Browse files
committed
Allow docstring to use single quotes and to not be displayed
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.
1 parent 3b0e400 commit eea2717

File tree

4 files changed

+91
-19
lines changed

4 files changed

+91
-19
lines changed

example/example.ipynb

+80-11
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"cells": [
33
{
44
"cell_type": "code",
5-
"execution_count": null,
5+
"execution_count": 2,
66
"id": "5df2c405",
77
"metadata": {},
88
"outputs": [],
@@ -25,39 +25,84 @@
2525
},
2626
{
2727
"cell_type": "code",
28-
"execution_count": null,
28+
"execution_count": 3,
2929
"id": "e74c9c9e",
3030
"metadata": {
3131
"scrolled": true
3232
},
33-
"outputs": [],
33+
"outputs": [
34+
{
35+
"data": {
36+
"application/vnd.jupyter.widget-view+json": {
37+
"model_id": "37da5497bfed438c8626bde64058dca8",
38+
"version_major": 2,
39+
"version_minor": 1
40+
},
41+
"text/plain": [
42+
"WidgetCodeInput(code_theme='basicLight', docstring='\"\"\"\\n Input docstring here.\\n\"\"\"', function_body='# Give…"
43+
]
44+
},
45+
"execution_count": 3,
46+
"metadata": {},
47+
"output_type": "execute_result"
48+
}
49+
],
3450
"source": [
3551
"w"
3652
]
3753
},
3854
{
3955
"cell_type": "code",
40-
"execution_count": null,
56+
"execution_count": 4,
4157
"id": "4d389a14",
4258
"metadata": {},
43-
"outputs": [],
59+
"outputs": [
60+
{
61+
"ename": "CodeValidationError",
62+
"evalue": "SyntaxError in code input: unexpected indent\nFile \"widget_code_input\", line 3\n Input docstring here.\n ^\n",
63+
"output_type": "error",
64+
"traceback": [
65+
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
66+
"\u001b[0;31mIndentationError\u001b[0m Traceback (most recent call last)",
67+
"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",
68+
"\u001b[0;31mIndentationError\u001b[0m: unexpected indent (widget_code_input, line 3)",
69+
"\nThe above exception was the direct cause of the following exception:\n",
70+
"\u001b[0;31mCodeValidationError\u001b[0m Traceback (most recent call last)",
71+
"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",
72+
"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",
73+
"\u001b[0;31mCodeValidationError\u001b[0m: SyntaxError in code input: unexpected indent\nFile \"widget_code_input\", line 3\n Input docstring here.\n ^\n"
74+
]
75+
}
76+
],
4477
"source": [
4578
"my_function = w.get_function_object()"
4679
]
4780
},
4881
{
4982
"cell_type": "code",
50-
"execution_count": null,
83+
"execution_count": 5,
5184
"id": "2fc2b3ed",
5285
"metadata": {},
53-
"outputs": [],
86+
"outputs": [
87+
{
88+
"ename": "NameError",
89+
"evalue": "name 'my_function' is not defined",
90+
"output_type": "error",
91+
"traceback": [
92+
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
93+
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
94+
"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",
95+
"\u001b[0;31mNameError\u001b[0m: name 'my_function' is not defined"
96+
]
97+
}
98+
],
5499
"source": [
55100
"my_function(1, 2)"
56101
]
57102
},
58103
{
59104
"cell_type": "code",
60-
"execution_count": null,
105+
"execution_count": 6,
61106
"id": "e90010bd",
62107
"metadata": {},
63108
"outputs": [],
@@ -67,10 +112,26 @@
67112
},
68113
{
69114
"cell_type": "code",
70-
"execution_count": null,
115+
"execution_count": 7,
71116
"id": "75900629",
72117
"metadata": {},
73-
"outputs": [],
118+
"outputs": [
119+
{
120+
"data": {
121+
"application/vnd.jupyter.widget-view+json": {
122+
"model_id": "15846da8fc8943bd9cb21bd505ca0174",
123+
"version_major": 2,
124+
"version_minor": 1
125+
},
126+
"text/plain": [
127+
"WidgetCodeInput(code_theme='basicLight', docstring='\"\"\"\\n Input docstring here.\\n\"\"\"', function_body='# Give…"
128+
]
129+
},
130+
"execution_count": 7,
131+
"metadata": {},
132+
"output_type": "execute_result"
133+
}
134+
],
74135
"source": [
75136
"w2 = WidgetCodeInput(\n",
76137
" function_name = \"my_function\",\n",
@@ -83,6 +144,14 @@
83144
")\n",
84145
"w2"
85146
]
147+
},
148+
{
149+
"cell_type": "code",
150+
"execution_count": null,
151+
"id": "cabf4027",
152+
"metadata": {},
153+
"outputs": [],
154+
"source": []
86155
}
87156
],
88157
"metadata": {
@@ -101,7 +170,7 @@
101170
"name": "python",
102171
"nbconvert_exporter": "python",
103172
"pygments_lexer": "ipython3",
104-
"version": "3.10.15"
173+
"version": "3.11.10"
105174
}
106175
},
107176
"nbformat": 4,

js/widget.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ function signatureValueChanged() {
225225
// Set the value from python into the CodeMirror widget in the
226226
// frontend.
227227

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

230230
if (newDocstring !== myDocstringCodeMirror.state.doc.toString()) {
231231
myDocstringCodeMirror.dispatch({

src/widget_code_input/__init__.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ def _valid_docstring(self, docstring):
6262
"""
6363
Validate that the docstring do not contain triple double quotes
6464
"""
65-
if '"""' in docstring['value']:
66-
raise TraitError('The docstring cannot contain triple double quotes (""")')
6765
return docstring['value']
6866

6967

@@ -73,7 +71,7 @@ def __init__( # pylint: disable=too-many-arguments
7371
self,
7472
function_name,
7573
function_parameters="",
76-
docstring="\n",
74+
docstring=None,
7775
function_body="",
7876
code_theme="basicLight",
7977
):
@@ -94,7 +92,13 @@ def __init__( # pylint: disable=too-many-arguments
9492

9593
self.function_name = function_name
9694
self.function_parameters = function_parameters
97-
self.docstring = docstring
95+
if docstring is None:
96+
self.docstring = ""
97+
elif docstring.startswith("\"") and docstring.endswith("\""):
98+
# assume the quotation marks have been added so we do not need to add them
99+
self.docstring = docstring
100+
else:
101+
self.docstring = f"\"\"\"{docstring}\"\"\""
98102
self.function_body = function_body
99103
self.code_theme = code_theme
100104
self.widget_instance_count_trait=f"{WidgetCodeInput.widget_instance_count}"

src/widget_code_input/utils.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,11 @@ def build_pre_body(signature, docstring, indent_level=4):
4747
:param docstring: the (unindented) docstring
4848
:param indent_level: integer number of spaces to prepend to the docstring
4949
"""
50-
if '"""' in docstring:
51-
raise ValueError('Triple double quotes (""") not allowed in docstring')
5250

5351
return "{}\n{}".format(
5452
signature,
55-
prepend_indent('"""{}"""'.format(docstring), indent_level=indent_level),
53+
prepend_indent('' if docstring is None else '"""{}"""'.format(docstring),
54+
indent_level=indent_level),
5655
)
5756

5857

0 commit comments

Comments
 (0)