Skip to content

Commit ecd5b1f

Browse files
Wh1isperfcollonval
andauthored
Change md5 to hash and hash_algorithm, fix incompatibility (#1367)
Co-authored-by: Frédéric Collonval <[email protected]>
1 parent 8e5d766 commit ecd5b1f

File tree

12 files changed

+509
-221
lines changed

12 files changed

+509
-221
lines changed

.github/workflows/downstream.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,23 @@ jobs:
107107
test_command: pip install pytest-jupyter[server] && pytest -vv -raXxs -W default --durations 10 --color=yes
108108
package_name: jupyter_server_terminals
109109

110+
jupytext:
111+
runs-on: ubuntu-latest
112+
timeout-minutes: 10
113+
114+
steps:
115+
- name: Checkout
116+
uses: actions/checkout@v4
117+
118+
- name: Base Setup
119+
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
120+
121+
- name: Test jupytext
122+
uses: jupyterlab/maintainer-tools/.github/actions/downstream-test@v1
123+
with:
124+
package_name: jupytext
125+
test_command: pip install pytest-jupyter[server] gitpython pre-commit && python -m ipykernel install --name jupytext-dev --user && pytest -vv -raXxs -W default --durations 10 --color=yes --ignore=tests/test_doc_files_are_notebooks.py --ignore=tests/test_changelog.py
126+
110127
downstream_check: # This job does nothing and is only used for the branch protection
111128
if: always()
112129
needs:
@@ -115,6 +132,7 @@ jobs:
115132
- jupyterlab_server
116133
- notebook
117134
- nbclassic
135+
- jupytext
118136
runs-on: ubuntu-latest
119137
steps:
120138
- name: Decide whether the needed jobs succeeded or failed

docs/source/developers/contents.rst

Lines changed: 52 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -33,40 +33,48 @@ which we refer to as **models**.
3333

3434
Models may contain the following entries:
3535

36-
+--------------------+-----------+------------------------------+
37-
| Key | Type |Info |
38-
+====================+===========+==============================+
39-
|**name** |unicode |Basename of the entity. |
40-
+--------------------+-----------+------------------------------+
41-
|**path** |unicode |Full |
42-
| | |(:ref:`API-style<apipaths>`) |
43-
| | |path to the entity. |
44-
+--------------------+-----------+------------------------------+
45-
|**type** |unicode |The entity type. One of |
46-
| | |``"notebook"``, ``"file"`` or |
47-
| | |``"directory"``. |
48-
+--------------------+-----------+------------------------------+
49-
|**created** |datetime |Creation date of the entity. |
50-
+--------------------+-----------+------------------------------+
51-
|**last_modified** |datetime |Last modified date of the |
52-
| | |entity. |
53-
+--------------------+-----------+------------------------------+
54-
|**content** |variable |The "content" of the entity. |
55-
| | |(:ref:`See |
56-
| | |Below<modelcontent>`) |
57-
+--------------------+-----------+------------------------------+
58-
|**mimetype** |unicode or |The mimetype of ``content``, |
59-
| |``None`` |if any. (:ref:`See |
60-
| | |Below<modelcontent>`) |
61-
+--------------------+-----------+------------------------------+
62-
|**format** |unicode or |The format of ``content``, |
63-
| |``None`` |if any. (:ref:`See |
64-
| | |Below<modelcontent>`) |
65-
+--------------------+-----------+------------------------------+
66-
|**md5** |unicode or |The md5 of the contents. |
67-
| |``None`` | |
68-
| | | |
69-
+--------------------+-----------+------------------------------+
36+
+--------------------+------------+-------------------------------+
37+
| Key | Type | Info |
38+
+====================+============+===============================+
39+
| **name** | unicode | Basename of the entity. |
40+
+--------------------+------------+-------------------------------+
41+
| **path** | unicode | Full |
42+
| | | (:ref:`API-style<apipaths>`) |
43+
| | | path to the entity. |
44+
+--------------------+------------+-------------------------------+
45+
| **type** | unicode | The entity type. One of |
46+
| | | ``"notebook"``, ``"file"`` or |
47+
| | | ``"directory"``. |
48+
+--------------------+------------+-------------------------------+
49+
| **created** | datetime | Creation date of the entity. |
50+
+--------------------+------------+-------------------------------+
51+
| **last_modified** | datetime | Last modified date of the |
52+
| | | entity. |
53+
+--------------------+------------+-------------------------------+
54+
| **content** | variable | The "content" of the entity. |
55+
| | | (:ref:`See |
56+
| | | Below<modelcontent>`) |
57+
+--------------------+------------+-------------------------------+
58+
| **mimetype** | unicode or | The mimetype of ``content``, |
59+
| | ``None`` | if any. (:ref:`See |
60+
| | | Below<modelcontent>`) |
61+
+--------------------+------------+-------------------------------+
62+
| **format** | unicode or | The format of ``content``, |
63+
| | ``None`` | if any. (:ref:`See |
64+
| | | Below<modelcontent>`) |
65+
+--------------------+------------+-------------------------------+
66+
| [optional] | | |
67+
| **hash** | unicode or | The hash of the contents. |
68+
| | ``None`` | It cannot be null if |
69+
| | | ``hash_algorithm`` is |
70+
| | | defined. |
71+
+--------------------+------------+-------------------------------+
72+
| [optional] | | |
73+
| **hash_algorithm** | unicode or | The algorithm used to compute |
74+
| | ``None`` | hash value. |
75+
| | | It cannot be null |
76+
| | | if ``hash`` is defined. |
77+
+--------------------+------------+-------------------------------+
7078

7179
.. _modelcontent:
7280

@@ -80,8 +88,9 @@ model. There are three model types: **notebook**, **file**, and **directory**.
8088
:class:`nbformat.notebooknode.NotebookNode` representing the .ipynb file
8189
represented by the model. See the `NBFormat`_ documentation for a full
8290
description.
83-
- The ``md5`` field a hexdigest string of the md5 value of the notebook
84-
file.
91+
- The ``hash`` field a hexdigest string of the hash value of the file.
92+
If ``ContentManager.get`` not support hash, it should always be ``None``.
93+
- ``hash_algorithm`` is the algorithm used to compute the hash value.
8594

8695
- ``file`` models
8796
- The ``format`` field is either ``"text"`` or ``"base64"``.
@@ -91,14 +100,16 @@ model. There are three model types: **notebook**, **file**, and **directory**.
91100
file models, ``content`` simply contains the file's bytes after decoding
92101
as UTF-8. Non-text (``base64``) files are read as bytes, base64 encoded,
93102
and then decoded as UTF-8.
94-
- The ``md5`` field a hexdigest string of the md5 value of the file.
103+
- The ``hash`` field a hexdigest string of the hash value of the file.
104+
If ``ContentManager.get`` not support hash, it should always be ``None``.
105+
- ``hash_algorithm`` is the algorithm used to compute the hash value.
95106

96107
- ``directory`` models
97108
- The ``format`` field is always ``"json"``.
98109
- The ``mimetype`` field is always ``None``.
99110
- The ``content`` field contains a list of :ref:`content-free<contentfree>`
100111
models representing the entities in the directory.
101-
- The ``md5`` field is always ``None``.
112+
- The ``hash`` field is always ``None``.
102113

103114
.. note::
104115

@@ -115,7 +126,7 @@ model. There are three model types: **notebook**, **file**, and **directory**.
115126

116127
.. code-block:: python
117128
118-
# Notebook Model with Content
129+
# Notebook Model with Content and Hash
119130
{
120131
"content": {
121132
"metadata": {},
@@ -137,7 +148,8 @@ model. There are three model types: **notebook**, **file**, and **directory**.
137148
"path": "foo/a.ipynb",
138149
"type": "notebook",
139150
"writable": True,
140-
"md5": "7e47382b370c05a1b14706a2a8aff91a",
151+
"hash": "f5e43a0b1c2e7836ab3b4d6b1c35c19e2558688de15a6a14e137a59e4715d34b",
152+
"hash_algorithm": "sha256",
141153
}
142154
143155
# Notebook Model without Content

jupyter_server/services/api/api.yaml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ paths:
106106
in: query
107107
description: "Return content (0 for no content, 1 for return content)"
108108
type: integer
109-
- name: md5
109+
- name: hash
110110
in: query
111-
description: "Return md5 hexdigest string of content (0 for no md5, 1 for return md5)"
111+
description: "May return hash hexdigest string of content and the hash algorithm (0 for no hash - default, 1 for return hash). It may be ignored by the content manager."
112112
type: integer
113113
responses:
114114
404:
@@ -889,7 +889,7 @@ definitions:
889889
kernel:
890890
$ref: "#/definitions/Kernel"
891891
Contents:
892-
description: "A contents object. The content and format keys may be null if content is not contained. The md5 maybe null if md5 is not contained. If type is 'file', then the mimetype will be null."
892+
description: "A contents object. The content and format keys may be null if content is not contained. The hash maybe null if hash is not required. If type is 'file', then the mimetype will be null."
893893
type: object
894894
required:
895895
- type
@@ -901,7 +901,6 @@ definitions:
901901
- mimetype
902902
- format
903903
- content
904-
- md5
905904
properties:
906905
name:
907906
type: string
@@ -939,9 +938,12 @@ definitions:
939938
format:
940939
type: string
941940
description: Format of content (one of null, 'text', 'base64', 'json')
942-
md5:
941+
hash:
943942
type: string
944-
description: "The md5 hexdigest string of content, if requested (otherwise null)."
943+
description: "[optional] The hexdigest hash string of content, if requested (otherwise null). It cannot be null if hash_algorithm is defined."
944+
hash_algorithm:
945+
type: string
946+
description: "[optional] The algorithm used to produce the hash, if requested (otherwise null). It cannot be null if hash is defined."
945947
Checkpoints:
946948
description: A checkpoint object.
947949
type: object

jupyter_server/services/contents/filecheckpoints.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ def get_file_checkpoint(self, checkpoint_id, path):
252252
if not os.path.isfile(os_checkpoint_path):
253253
self.no_such_checkpoint(path, checkpoint_id)
254254

255-
content, format = self._read_file(os_checkpoint_path, format=None)
255+
content, format = self._read_file(os_checkpoint_path, format=None) # type: ignore[misc]
256256
return {
257257
"type": "file",
258258
"content": content,
@@ -318,7 +318,7 @@ async def get_file_checkpoint(self, checkpoint_id, path):
318318
if not os.path.isfile(os_checkpoint_path):
319319
self.no_such_checkpoint(path, checkpoint_id)
320320

321-
content, format = await self._read_file(os_checkpoint_path, format=None)
321+
content, format = await self._read_file(os_checkpoint_path, format=None) # type: ignore[misc]
322322
return {
323323
"type": "file",
324324
"content": content,

0 commit comments

Comments
 (0)