Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-jupyter-server-fileid for openSUSE:Factory checked in at 2024-11-08 11:59:53 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-jupyter-server-fileid (Old) and /work/SRC/openSUSE:Factory/.python-jupyter-server-fileid.new.2017 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-jupyter-server-fileid" Fri Nov 8 11:59:53 2024 rev:6 rq:1222549 version:0.9.3 Changes: -------- --- /work/SRC/openSUSE:Factory/python-jupyter-server-fileid/python-jupyter-server-fileid.changes 2024-03-07 18:32:41.260256480 +0100 +++ /work/SRC/openSUSE:Factory/.python-jupyter-server-fileid.new.2017/python-jupyter-server-fileid.changes 2024-11-08 12:04:21.857939844 +0100 @@ -1,0 +2,11 @@ +Thu Nov 7 17:56:29 UTC 2024 - Ben Greiner <c...@bnavigator.de> + +- Update to 0.9.3 + * Don't commit when garbage-collected in a different thread #81 + (@davidbrochart) +- Release 0.9.2 + * Check for ID before creating a new record #78 (@Zsailer) + * Use a context manager for all write actions to prevent + indefinite database locks #77 (@Zsailer) + +------------------------------------------------------------------- Old: ---- jupyter_server_fileid-0.9.1.tar.gz New: ---- jupyter_server_fileid-0.9.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-jupyter-server-fileid.spec ++++++ --- /var/tmp/diff_new_pack.uJ6Ff2/_old 2024-11-08 12:04:22.269957097 +0100 +++ /var/tmp/diff_new_pack.uJ6Ff2/_new 2024-11-08 12:04:22.269957097 +0100 @@ -16,8 +16,8 @@ # -%define pyversion 0.9.1 -%define distversion 0.9.1 +%define pyversion 0.9.3 +%define distversion 0.9.3 %if 0%{?suse_version} > 1500 %bcond_without libalternatives %else @@ -89,13 +89,7 @@ %check # flaky on obs donttest="test_get_path_oob_move_nested" -export PYTHONDONTWRITEBYTECODE=1 -%{python_expand # don't test anything on python39: no jupyter-server-test anymore -export PYTHONPATH=%{buildroot}%{$python_sitelib} -if [ ${python_flavor} != "python39" ]; then - $python -m pytest -k "not ($donttest)" -fi -} +%pytest -k "not ($donttest)" %pre %python_libalternatives_reset_alternative jupyter-fileid ++++++ jupyter_server_fileid-0.9.1.tar.gz -> jupyter_server_fileid-0.9.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_server_fileid-0.9.1/.github/workflows/prep-release.yml new/jupyter_server_fileid-0.9.3/.github/workflows/prep-release.yml --- old/jupyter_server_fileid-0.9.1/.github/workflows/prep-release.yml 2020-02-02 01:00:00.000000000 +0100 +++ new/jupyter_server_fileid-0.9.3/.github/workflows/prep-release.yml 2020-02-02 01:00:00.000000000 +0100 @@ -12,6 +12,10 @@ post_version_spec: description: "Post Version Specifier" required: false + silent: + description: "Set a placeholder in the changelog and don't publish the release." + required: false + type: boolean since: description: "Use PRs with activity since this date or git reference" required: false @@ -22,6 +26,8 @@ jobs: prep_release: runs-on: ubuntu-latest + permissions: + contents: write steps: - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 @@ -29,9 +35,11 @@ id: prep-release uses: jupyter-server/jupyter_releaser/.github/actions/prep-release@v2 with: - token: ${{ secrets.ADMIN_GITHUB_TOKEN }} + token: ${{ secrets.GITHUB_TOKEN }} version_spec: ${{ github.event.inputs.version_spec }} + silent: ${{ github.event.inputs.silent }} post_version_spec: ${{ github.event.inputs.post_version_spec }} + target: ${{ github.event.inputs.target }} branch: ${{ github.event.inputs.branch }} since: ${{ github.event.inputs.since }} since_last_stable: ${{ github.event.inputs.since_last_stable }} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_server_fileid-0.9.1/.github/workflows/publish-changelog.yml new/jupyter_server_fileid-0.9.3/.github/workflows/publish-changelog.yml --- old/jupyter_server_fileid-0.9.1/.github/workflows/publish-changelog.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/jupyter_server_fileid-0.9.3/.github/workflows/publish-changelog.yml 2020-02-02 01:00:00.000000000 +0100 @@ -0,0 +1,34 @@ +name: "Publish Changelog" +on: + release: + types: [published] + + workflow_dispatch: + inputs: + branch: + description: "The branch to target" + required: false + +jobs: + publish_changelog: + runs-on: ubuntu-latest + environment: release + steps: + - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + + - uses: actions/create-github-app-token@v1 + id: app-token + with: + app-id: ${{ vars.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + + - name: Publish changelog + id: publish-changelog + uses: jupyter-server/jupyter_releaser/.github/actions/publish-changelog@v2 + with: + token: ${{ steps.app-token.outputs.token }} + branch: ${{ github.event.inputs.branch }} + + - name: "** Next Step **" + run: | + echo "Merge the changelog update PR: ${{ steps.publish-changelog.outputs.pr_url }}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_server_fileid-0.9.1/.github/workflows/publish-release.yml new/jupyter_server_fileid-0.9.3/.github/workflows/publish-release.yml --- old/jupyter_server_fileid-0.9.1/.github/workflows/publish-release.yml 2020-02-02 01:00:00.000000000 +0100 +++ new/jupyter_server_fileid-0.9.3/.github/workflows/publish-release.yml 2020-02-02 01:00:00.000000000 +0100 @@ -15,28 +15,32 @@ jobs: publish_release: runs-on: ubuntu-latest + environment: release + permissions: + id-token: write steps: - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + - uses: actions/create-github-app-token@v1 + id: app-token + with: + app-id: ${{ vars.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + - name: Populate Release id: populate-release uses: jupyter-server/jupyter_releaser/.github/actions/populate-release@v2 with: - token: ${{ secrets.ADMIN_GITHUB_TOKEN }} + token: ${{ steps.app-token.outputs.token }} branch: ${{ github.event.inputs.branch }} release_url: ${{ github.event.inputs.release_url }} steps_to_skip: ${{ github.event.inputs.steps_to_skip }} - name: Finalize Release id: finalize-release - env: - PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} - PYPI_TOKEN_MAP: ${{ secrets.PYPI_TOKEN_MAP }} - TWINE_USERNAME: __token__ - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - uses: jupyter-server/jupyter-releaser/.github/actions/finalize-release@v2 + uses: jupyter-server/jupyter_releaser/.github/actions/finalize-release@v2 with: - token: ${{ secrets.ADMIN_GITHUB_TOKEN }} + token: ${{ steps.app-token.outputs.token }} release_url: ${{ steps.populate-release.outputs.release_url }} - name: "** Next Step **" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_server_fileid-0.9.1/.github/workflows/test-python.yml new/jupyter_server_fileid-0.9.3/.github/workflows/test-python.yml --- old/jupyter_server_fileid-0.9.1/.github/workflows/test-python.yml 2020-02-02 01:00:00.000000000 +0100 +++ new/jupyter_server_fileid-0.9.3/.github/workflows/test-python.yml 2020-02-02 01:00:00.000000000 +0100 @@ -84,8 +84,9 @@ uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 with: python_version: "3.7" - - name: Install miniumum versions - uses: jupyterlab/maintainer-tools/.github/actions/install-minimums@v1 + dependency_type: minimum + - name: Install + run: pip install -e ".[test]" - name: Run the unit tests run: | pytest -vv -W default || pytest -vv -W default --lf diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_server_fileid-0.9.1/CHANGELOG.md new/jupyter_server_fileid-0.9.3/CHANGELOG.md --- old/jupyter_server_fileid-0.9.1/CHANGELOG.md 2020-02-02 01:00:00.000000000 +0100 +++ new/jupyter_server_fileid-0.9.3/CHANGELOG.md 2020-02-02 01:00:00.000000000 +0100 @@ -2,6 +2,41 @@ <!-- <START NEW CHANGELOG ENTRY> --> +## 0.9.3 + +([Full Changelog](https://github.com/jupyter-server/jupyter_server_fileid/compare/v0.9.2...7ee71f63fd6fce6535f8f99f9d47199cd934bb31)) + +### Merged PRs + +- Don't commit when garbage-collected in a different thread [#81](https://github.com/jupyter-server/jupyter_server_fileid/pull/81) ([@davidbrochart](https://github.com/davidbrochart)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_fileid/graphs/contributors?from=2024-04-18&to=2024-09-06&type=c)) + +[@davidbrochart](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_fileid+involves%3Adavidbrochart+updated%3A2024-04-18..2024-09-06&type=Issues) + +<!-- <END NEW CHANGELOG ENTRY> --> + +## 0.9.2 + +([Full Changelog](https://github.com/jupyter-server/jupyter_server_fileid/compare/v0.9.1...501a1230ac2e934c70bbb7267144f16fe6ed3484)) + +### Bugs fixed + +- Check for ID before creating a new record [#78](https://github.com/jupyter-server/jupyter_server_fileid/pull/78) ([@Zsailer](https://github.com/Zsailer)) +- Use a context manager for all write actions to prevent indefinite database locks [#77](https://github.com/jupyter-server/jupyter_server_fileid/pull/77) ([@Zsailer](https://github.com/Zsailer)) + +### Maintenance and upkeep improvements + +- Update Release Scripts [#79](https://github.com/jupyter-server/jupyter_server_fileid/pull/79) ([@blink1073](https://github.com/blink1073)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/jupyter-server/jupyter_server_fileid/graphs/contributors?from=2023-12-19&to=2024-04-18&type=c)) + +[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_fileid+involves%3Ablink1073+updated%3A2023-12-19..2024-04-18&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_fileid+involves%3Awelcome+updated%3A2023-12-19..2024-04-18&type=Issues) | [@Zsailer](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_fileid+involves%3AZsailer+updated%3A2023-12-19..2024-04-18&type=Issues) + ## 0.9.1 ([Full Changelog](https://github.com/jupyter-server/jupyter_server_fileid/compare/v0.9.0...a5e65c99791a20e4684c55f631d2d7fef3c3fdad)) @@ -22,8 +57,6 @@ [@cmd-ntrf](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_fileid+involves%3Acmd-ntrf+updated%3A2023-04-09..2023-12-19&type=Issues) | [@codecov](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_fileid+involves%3Acodecov+updated%3A2023-04-09..2023-12-19&type=Issues) | [@dlqqq](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_fileid+involves%3Adlqqq+updated%3A2023-04-09..2023-12-19&type=Issues) | [@stonebig](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_fileid+involves%3Astonebig+updated%3A2023-04-09..2023-12-19&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_fileid+involves%3Awelcome+updated%3A2023-04-09..2023-12-19&type=Issues) | [@Zsailer](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server_fileid+involves%3AZsailer+updated%3A2023-04-09..2023-12-19&type=Issues) -<!-- <END NEW CHANGELOG ENTRY> --> - ## 0.9.0 ([Full Changelog](https://github.com/jupyter-server/jupyter_server_fileid/compare/v0.8.0...505806162b4df60b4cbb461cfec1266b81df32ce)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_server_fileid-0.9.1/PKG-INFO new/jupyter_server_fileid-0.9.3/PKG-INFO --- old/jupyter_server_fileid-0.9.1/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 +++ new/jupyter_server_fileid-0.9.3/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ -Metadata-Version: 2.1 +Metadata-Version: 2.3 Name: jupyter_server_fileid -Version: 0.9.1 +Version: 0.9.3 Summary: Jupyter Server extension providing an implementation of the File ID service. Project-URL: Home, https://github.com/jupyter-server/jupyter_server_fileid Author-email: "David L. Qiu" <da...@qiu.dev> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_server_fileid-0.9.1/jupyter_server_fileid/__init__.py new/jupyter_server_fileid-0.9.3/jupyter_server_fileid/__init__.py --- old/jupyter_server_fileid-0.9.1/jupyter_server_fileid/__init__.py 2020-02-02 01:00:00.000000000 +0100 +++ new/jupyter_server_fileid-0.9.3/jupyter_server_fileid/__init__.py 2020-02-02 01:00:00.000000000 +0100 @@ -1,7 +1,7 @@ """A Jupyter Server extension providing an implementation of the File ID service.""" from .extension import FileIdExtension -__version__ = "0.9.1" +__version__ = "0.9.3" def _jupyter_server_extension_points(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_server_fileid-0.9.1/jupyter_server_fileid/manager.py new/jupyter_server_fileid-0.9.3/jupyter_server_fileid/manager.py --- old/jupyter_server_fileid-0.9.1/jupyter_server_fileid/manager.py 2020-02-02 01:00:00.000000000 +0100 +++ new/jupyter_server_fileid-0.9.3/jupyter_server_fileid/manager.py 2020-02-02 01:00:00.000000000 +0100 @@ -312,23 +312,22 @@ def _create(self, path: str) -> str: path = self._normalize_path(path) - id = self._uuid() - self.con.execute("INSERT INTO Files (id, path) VALUES (?, ?)", (id, path)) - return id - - def index(self, path: str) -> str: - path = self._normalize_path(path) row = self.con.execute("SELECT id FROM Files WHERE path = ?", (path,)).fetchone() existing_id = row and row[0] if existing_id: return existing_id - # create new record - id = self._create(path) - self.con.commit() + id = self._uuid() + self.con.execute("INSERT INTO Files (id, path) VALUES (?, ?)", (id, path)) return id + def index(self, path: str) -> str: + # create new record + with self.con: + id = self._create(path) + return id + def get_id(self, path: str) -> Optional[str]: path = self._normalize_path(path) row = self.con.execute("SELECT id FROM Files WHERE path = ?", (path,)).fetchone() @@ -340,37 +339,36 @@ return self._from_normalized_path(path) def move(self, old_path: str, new_path: str) -> None: - old_path = self._normalize_path(old_path) - new_path = self._normalize_path(new_path) - row = self.con.execute("SELECT id FROM Files WHERE path = ?", (old_path,)).fetchone() - id = row and row[0] - - if id: - self.con.execute("UPDATE Files SET path = ? WHERE path = ?", (new_path, old_path)) - self._move_recursive(old_path, new_path, posixpath) - else: - id = self._create(new_path) + with self.con: + old_path = self._normalize_path(old_path) + new_path = self._normalize_path(new_path) + row = self.con.execute("SELECT id FROM Files WHERE path = ?", (old_path,)).fetchone() + id = row and row[0] + + if id: + self.con.execute("UPDATE Files SET path = ? WHERE path = ?", (new_path, old_path)) + self._move_recursive(old_path, new_path, posixpath) + else: + id = self._create(new_path) - self.con.commit() - return id + return id def copy(self, from_path: str, to_path: str) -> Optional[str]: - from_path = self._normalize_path(from_path) - to_path = self._normalize_path(to_path) + with self.con: + from_path = self._normalize_path(from_path) + to_path = self._normalize_path(to_path) - id = self._create(to_path) - self._copy_recursive(from_path, to_path, posixpath) + id = self._create(to_path) + self._copy_recursive(from_path, to_path, posixpath) - self.con.commit() - return id + return id def delete(self, path: str) -> None: - path = self._normalize_path(path) + with self.con: + path = self._normalize_path(path) - self.con.execute("DELETE FROM Files WHERE path = ?", (path,)) - self._delete_recursive(path, posixpath) - - self.con.commit() + self.con.execute("DELETE FROM Files WHERE path = ?", (path,)) + self._delete_recursive(path, posixpath) def save(self, path: str) -> None: return @@ -388,8 +386,14 @@ """Cleans up `ArbitraryFileIdManager` by committing any pending transactions and closing the connection.""" if hasattr(self, "con"): - self.con.commit() - self.con.close() + # If garbage collection happens in a different thread than the thread where + # the SQLite object was created, committing will fail anyway. We just ignore + # the exception if this is the case. + try: + self.con.commit() + self.con.close() + except sqlite3.ProgrammingError: + pass class LocalFileIdManager(BaseFileIdManager): @@ -626,6 +630,7 @@ # otherwise update existing record with new path, moving any indexed # children if necessary. then return its id self._update(id, path=path) + if stat_info.is_dir and old_path != path: self._move_recursive(old_path, path) self._update_cursor = True @@ -672,6 +677,17 @@ dangerous and may throw a runtime error if the file is not guaranteed to have a unique `ino`. """ + # If the path exists + existing_id, ino = None, None + row = self.con.execute("SELECT id, ino FROM Files WHERE path = ?", (path,)).fetchone() + if row: + existing_id, ino = row + + # If the file ID already exists and the current file matches our records + # return the file ID instead of creating a new one. + if existing_id and stat_info.ino == ino: + return existing_id + id = self._uuid() self.con.execute( "INSERT INTO Files (id, path, ino, crtime, mtime, is_dir) VALUES (?, ?, ?, ?, ?, ?)", @@ -718,39 +734,38 @@ def index(self, path, stat_info=None, commit=True): """Returns the file ID for the file at `path`, creating a new file ID if one does not exist. Returns None only if file does not exist at path.""" - path = self._normalize_path(path) - stat_info = stat_info or self._stat(path) - if not stat_info: - return None + with self.con: + path = self._normalize_path(path) + stat_info = stat_info or self._stat(path) + if not stat_info: + return None - # if file is symlink, then index the path it refers to instead - if stat_info.is_symlink: - return self.index(os.path.realpath(path)) + # if file is symlink, then index the path it refers to instead + if stat_info.is_symlink: + return self.index(os.path.realpath(path)) + + # sync file at path and return file ID if it exists + id = self._sync_file(path, stat_info) + if id is not None: + return id - # sync file at path and return file ID if it exists - id = self._sync_file(path, stat_info) - if id is not None: + # otherwise, create a new record and return the file ID + id = self._create(path, stat_info) return id - # otherwise, create a new record and return the file ID - id = self._create(path, stat_info) - if commit: - self.con.commit() - return id - def get_id(self, path): """Retrieves the file ID associated with a file path. Returns None if the file has not yet been indexed or does not exist at the given path.""" - path = self._normalize_path(path) - stat_info = self._stat(path) - if not stat_info: - return None + with self.con: + path = self._normalize_path(path) + stat_info = self._stat(path) + if not stat_info: + return None - # then sync file at path and retrieve id, if any - id = self._sync_file(path, stat_info) - self.con.commit() - return id + # then sync file at path and retrieve id, if any + id = self._sync_file(path, stat_info) + return id def get_path(self, id): """Retrieves the file path associated with a file ID. The file path is @@ -795,26 +810,26 @@ def move(self, old_path, new_path): """Handles file moves by updating the file path of the associated file ID. Returns the file ID. Returns None if file does not exist at new_path.""" - old_path = self._normalize_path(old_path) - new_path = self._normalize_path(new_path) + with self.con: + old_path = self._normalize_path(old_path) + new_path = self._normalize_path(new_path) - # verify file exists at new_path - stat_info = self._stat(new_path) - if stat_info is None: - return None + # verify file exists at new_path + stat_info = self._stat(new_path) + if stat_info is None: + return None - # sync the file and see if it was already indexed - # - # originally this method did not call _sync_file() for performance - # reasons, but this is needed to handle an edge case: - # https://github.com/jupyter-server/jupyter_server_fileid/issues/62 - id = self._sync_file(new_path, stat_info) - if id is None: - # if no existing record, create a new one - id = self._create(new_path, stat_info) + # sync the file and see if it was already indexed + # + # originally this method did not call _sync_file() for performance + # reasons, but this is needed to handle an edge case: + # https://github.com/jupyter-server/jupyter_server_fileid/issues/62 + id = self._sync_file(new_path, stat_info) + if id is None: + # if no existing record, create a new one + id = self._create(new_path, stat_info) - self.con.commit() - return id + return id def _copy_recursive(self, from_path: str, to_path: str, _: str = "") -> None: """Copy all children of a given directory at `from_path` to a new @@ -859,13 +874,13 @@ def delete(self, path): """Handles file deletions by deleting the associated record in the File table. Returns None.""" - path = self._normalize_path(path) + with self.con: + path = self._normalize_path(path) - if os.path.isdir(path): - self._delete_recursive(path) + if os.path.isdir(path): + self._delete_recursive(path) - self.con.execute("DELETE FROM Files WHERE path = ?", (path,)) - self.con.commit() + self.con.execute("DELETE FROM Files WHERE path = ?", (path,)) def save(self, path): """Handles file saves (edits) by updating recorded stat info. @@ -878,21 +893,21 @@ JupyterLab. This would (wrongly) preserve the association b/w the old file ID and the current path rather than create a new file ID. """ - path = self._normalize_path(path) + with self.con: + path = self._normalize_path(path) - # look up record by ino and path - stat_info = self._stat(path) - row = self.con.execute( - "SELECT id FROM Files WHERE ino = ? AND path = ?", (stat_info.ino, path) - ).fetchone() - # if no record exists, return early - if row is None: - return - - # otherwise, update the stat info - (id,) = row - self._update(id, stat_info) - self.con.commit() + # look up record by ino and path + stat_info = self._stat(path) + row = self.con.execute( + "SELECT id FROM Files WHERE ino = ? AND path = ?", (stat_info.ino, path) + ).fetchone() + # if no record exists, return early + if row is None: + return + + # otherwise, update the stat info + (id,) = row + self._update(id, stat_info) def get_handlers_by_action(self) -> Dict[str, Optional[Callable[[Dict[str, Any]], Any]]]: return {