diff --git a/Makefile b/Makefile index a413863..ec4a8ea 100644 --- a/Makefile +++ b/Makefile @@ -63,7 +63,7 @@ tests: testpy testjs ## run the tests .PHONY: lintpy lintjs lint fixpy fixjs fix format lintpy: ## Lint Python with Ruff - python -m ruff jupyterfs setup.py + python -m ruff check jupyterfs setup.py python -m ruff format --check jupyterfs setup.py lintjs: ## Lint Javascript with ESlint @@ -72,7 +72,6 @@ lintjs: ## Lint Javascript with ESlint lint: lintpy lintjs ## run linter fixpy: ## Autoformat Python with Ruff - python -m ruff jupyterfs setup.py --fix python -m ruff format jupyterfs/ setup.py fixjs: ## Autoformat JavaScript with ESlint diff --git a/jupyterfs/auth.py b/jupyterfs/auth.py index a4e2b77..b514976 100644 --- a/jupyterfs/auth.py +++ b/jupyterfs/auth.py @@ -50,11 +50,7 @@ def get_identifiers(self): if named is not None and named not in ids: # add a named group only the first time it appears ids.append(named) - elif ( - named is None - and mo.group("invalid") is None - and mo.group("escaped") is None - ): + elif named is None and mo.group("invalid") is None and mo.group("escaped") is None: # If all the groups are None, there must be # another group we're not expecting raise ValueError("Unrecognized named group in pattern", self.pattern) @@ -75,9 +71,7 @@ def stdin_prompt(url): def substituteAsk(resource): if "tokenDict" in resource: - url = DoubleBraceTemplate(resource["url"]).safe_substitute( - {k: urllib.parse.quote(v) for k, v in resource.pop("tokenDict").items()} - ) + url = DoubleBraceTemplate(resource["url"]).safe_substitute({k: urllib.parse.quote(v) for k, v in resource.pop("tokenDict").items()}) else: url = resource["url"] diff --git a/jupyterfs/config.py b/jupyterfs/config.py index be12ad1..b773156 100644 --- a/jupyterfs/config.py +++ b/jupyterfs/config.py @@ -18,9 +18,7 @@ class JupyterFs(Configurable): root_manager_class = Type( config=True, default_value=LargeFileManager, - help=_i18n( - "the root contents manager class to use. Used by the Jupyterlab default filebrowser and elsewhere" - ), + help=_i18n("the root contents manager class to use. Used by the Jupyterlab default filebrowser and elsewhere"), klass=ContentsManager, ) @@ -40,9 +38,7 @@ class JupyterFs(Configurable): resource_validators = List( config=True, trait=Unicode(), - help=_i18n( - "regular expressions to match against resource URLs. At least one must match" - ), + help=_i18n("regular expressions to match against resource URLs. At least one must match"), ) surface_init_errors = Bool( @@ -56,9 +52,7 @@ class JupyterFs(Configurable): per_key_traits=Dict( { "label": Unicode(help="The designator to show to users"), - "caption": Unicode( - "", help="An optional, longer description to show to users" - ), + "caption": Unicode("", help="An optional, longer description to show to users"), "pattern": Unicode( "", help="A regular expression to match against the full URL of the entry, indicating if this snippet is valid for it", @@ -66,7 +60,5 @@ class JupyterFs(Configurable): "template": Unicode(help="A template string to build up the snippet"), } ), - help=_i18n( - "per entry snippets for how to use it, e.g. a snippet for how to open a file from a given resource" - ), + help=_i18n("per entry snippets for how to use it, e.g. a snippet for how to open a file from a given resource"), ) diff --git a/jupyterfs/extension.py b/jupyterfs/extension.py index 9414a94..0282928 100644 --- a/jupyterfs/extension.py +++ b/jupyterfs/extension.py @@ -41,19 +41,12 @@ def _load_jupyter_server_extension(serverapp): warnings.warn(_mm_config_warning_msg) return - if isinstance(serverapp.contents_manager_class, type) and not issubclass( - serverapp.contents_manager_class, MetaManager - ): + if isinstance(serverapp.contents_manager_class, type) and not issubclass(serverapp.contents_manager_class, MetaManager): serverapp.contents_manager_class = MetaManager - serverapp.log.info( - "Configuring jupyter-fs manager as the content manager class" - ) + serverapp.log.info("Configuring jupyter-fs manager as the content manager class") resources_url = "jupyterfs/resources" - serverapp.log.info( - "Installing jupyter-fs resources handler on path %s" - % url_path_join(base_url, resources_url) - ) + serverapp.log.info("Installing jupyter-fs resources handler on path %s" % url_path_join(base_url, resources_url)) web_app.add_handlers( host_pattern, [ diff --git a/jupyterfs/fsmanager.py b/jupyterfs/fsmanager.py index 7d3081e..38ffbab 100644 --- a/jupyterfs/fsmanager.py +++ b/jupyterfs/fsmanager.py @@ -176,9 +176,7 @@ def _is_path_hidden(self, path, info): import os syspath = self._pyfilesystem_instance.getsyspath(path) - if os.path.exists(syspath) and not os.access( - syspath, os.X_OK | os.R_OK - ): + if os.path.exists(syspath) and not os.access(syspath, os.X_OK | os.R_OK): return True except ResourceNotFound: @@ -313,14 +311,10 @@ def _dir_model(self, path, info, content=True): if content: model["content"] = contents = [] - for dir_entry in self._pyfilesystem_instance.scandir( - path, namespaces=("basic", "access", "details", "stat") - ): + for dir_entry in self._pyfilesystem_instance.scandir(path, namespaces=("basic", "access", "details", "stat")): try: if self.should_list(dir_entry.name): - if self.allow_hidden or not self._is_path_hidden( - dir_entry.make_path(path), dir_entry - ): + if self.allow_hidden or not self._is_path_hidden(dir_entry.make_path(path), dir_entry): contents.append( self.get( path="%s/%s" % (path, dir_entry.name), @@ -335,9 +329,7 @@ def _dir_model(self, path, info, content=True): # us from listing other entries pass except Exception as e: - self.log.warning( - "Error stat-ing %s: %s", dir_entry.make_path(path), e - ) + self.log.warning("Error stat-ing %s: %s", dir_entry.make_path(path), e) model["format"] = "json" return model @@ -443,25 +435,19 @@ def get(self, path, content=True, type=None, format=None, info=None): # gather info - by doing here can minimise further network requests from underlying fs functions if not info: try: - info = self._pyfilesystem_instance.getinfo( - path, namespaces=("basic", "stat", "access", "details") - ) + info = self._pyfilesystem_instance.getinfo(path, namespaces=("basic", "stat", "access", "details")) except Exception: raise web.HTTPError(404, "No such file or directory: %s" % path) if info.is_dir: if type not in (None, "directory"): - raise web.HTTPError( - 400, "%s is a directory, not a %s" % (path, type), reason="bad type" - ) + raise web.HTTPError(400, "%s is a directory, not a %s" % (path, type), reason="bad type") model = self._dir_model(path, content=content, info=info) elif type == "notebook" or (type is None and path.endswith(".ipynb")): model = self._notebook_model(path, content=content, info=info) else: if type == "directory": - raise web.HTTPError( - 400, "%s is not a directory" % path, reason="bad type" - ) + raise web.HTTPError(400, "%s is not a directory" % path, reason="bad type") model = self._file_model(path, content=content, format=format, info=info) return model @@ -519,9 +505,7 @@ def save(self, model, path=""): if chunk and model["type"] != "file": raise web.HTTPError( 400, - 'File type "{}" is not supported for chunked transfer'.format( - model["type"] - ), + 'File type "{}" is not supported for chunked transfer'.format(model["type"]), ) self.log.debug("Saving %s", path) @@ -549,9 +533,7 @@ def save(self, model, path=""): raise except Exception as e: self.log.error("Error while saving file: %s %s", path, e, exc_info=True) - raise web.HTTPError( - 500, "Unexpected error while saving file: %s %s" % (path, e) - ) + raise web.HTTPError(500, "Unexpected error while saving file: %s %s" % (path, e)) validation_message = None if model["type"] == "notebook": @@ -603,9 +585,7 @@ def rename_file(self, old_path, new_path): with self.perm_to_403(new_path): # Should we proceed with the move? - if self._pyfilesystem_instance.exists( - new_path - ): # TODO and not samefile(old_os_path, new_os_path): + if self._pyfilesystem_instance.exists(new_path): # TODO and not samefile(old_os_path, new_os_path): raise web.HTTPError(409, "File already exists: %s" % new_path) # Move the file or directory @@ -620,9 +600,7 @@ def rename_file(self, old_path, new_path): except web.HTTPError: raise except Exception as e: - raise web.HTTPError( - 500, "Unknown error renaming file: %s %s" % (old_path, e) - ) + raise web.HTTPError(500, "Unknown error renaming file: %s %s" % (old_path, e)) class PyFilesystemCheckpoints(GenericFileCheckpoints): diff --git a/jupyterfs/metamanager.py b/jupyterfs/metamanager.py index c99f86a..37a30b1 100644 --- a/jupyterfs/metamanager.py +++ b/jupyterfs/metamanager.py @@ -45,9 +45,7 @@ def __init__(self, **kwargs): self._pyfs_kw = {} self.resources = [] - self._default_root_manager = self._jupyterfsConfig.root_manager_class( - **self._kwargs - ) + self._default_root_manager = self._jupyterfsConfig.root_manager_class(**self._kwargs) self._managers = dict((("", self._default_root_manager),)) # copy kwargs to pyfs_kw, removing kwargs not relevant to pyfs @@ -133,11 +131,7 @@ def initResource(self, *resources, options={}): self._managers = managers if verbose: - print( - "jupyter-fs initialized: {} file system resources, {} managers".format( - len(self.resources), len(self._managers) - ) - ) + print("jupyter-fs initialized: {} file system resources, {} managers".format(len(self.resources), len(self._managers))) return self.resources @@ -242,6 +236,4 @@ async def post(self): else: resources = valid_resources - self.finish( - json.dumps(self.contents_manager.initResource(*resources, options=options)) - ) + self.finish(json.dumps(self.contents_manager.initResource(*resources, options=options))) diff --git a/jupyterfs/pathutils.py b/jupyterfs/pathutils.py index 65b8be7..ad3187d 100644 --- a/jupyterfs/pathutils.py +++ b/jupyterfs/pathutils.py @@ -48,9 +48,7 @@ def _resolve_path(path, manager_dict): raise HTTPError( 404, - "Couldn't find manager {mgrName} for {path}".format( - mgrName=parts[0], path=path - ), + "Couldn't find manager {mgrName} for {path}".format(mgrName=parts[0], path=path), ) else: # Try to find a sub-manager for the first subdirectory. @@ -60,9 +58,7 @@ def _resolve_path(path, manager_dict): raise HTTPError( 404, - "Couldn't find manager {mgrName} for {path}".format( - mgrName=parts[0], path=path - ), + "Couldn't find manager {mgrName} for {path}".format(mgrName=parts[0], path=path), ) @@ -160,9 +156,7 @@ async def _wrapper(self, old_path, new_path, *args, **kwargs): ), ) assert new_prefix == old_prefix - result = getattr(new_mgr, method_name)( - old_mgr_path, new_mgr_path, *args, **kwargs - ) + result = getattr(new_mgr, method_name)(old_mgr_path, new_mgr_path, *args, **kwargs) return result return _wrapper diff --git a/jupyterfs/tests/test_fsmanager.py b/jupyterfs/tests/test_fsmanager.py index 419bb65..1cbe69e 100644 --- a/jupyterfs/tests/test_fsmanager.py +++ b/jupyterfs/tests/test_fsmanager.py @@ -104,11 +104,7 @@ async def test_write_read(self, jp_fetch, resource_uri, jp_server_config): assert test_content == (await cc.get(p))["content"] for p in hidden_paths: - ctx = ( - nullcontext() - if allow_hidden - else pytest.raises(tornado.httpclient.HTTPClientError) - ) + ctx = nullcontext() if allow_hidden else pytest.raises(tornado.httpclient.HTTPClientError) with ctx as c: # save to root and tips await cc.save(p, _test_file_model) @@ -155,8 +151,7 @@ def setup_class(cls): cls._rootDirUtil.delete() @classmethod - def teardown_class(cls): - ... + def teardown_class(cls): ... def setup_method(self, method): self._rootDirUtil.create() @@ -212,8 +207,7 @@ def setup_class(cls): cls._rootDirUtil.delete() @classmethod - def teardown_class(cls): - ... + def teardown_class(cls): ... def setup_method(self, method): # create a root diff --git a/jupyterfs/tests/test_init.py b/jupyterfs/tests/test_init.py index 38a12f5..dfd597b 100644 --- a/jupyterfs/tests/test_init.py +++ b/jupyterfs/tests/test_init.py @@ -35,6 +35,4 @@ def test_open_fs(self, mock_getpass, mock_fs_open_fs): open_fs("osfs://{{foo}}/bar.txt") mock_getpass.assert_called_with("Enter value for 'foo': ") - mock_fs_open_fs.assert_called_with( - "osfs://test%20return%20getpass%20%3C%3E/%7C/bar.txt" - ) + mock_fs_open_fs.assert_called_with("osfs://test%20return%20getpass%20%3C%3E/%7C/bar.txt") diff --git a/jupyterfs/tests/test_metamanager.py b/jupyterfs/tests/test_metamanager.py index cd16f1a..8d5f89c 100644 --- a/jupyterfs/tests/test_metamanager.py +++ b/jupyterfs/tests/test_metamanager.py @@ -57,21 +57,15 @@ def jp_server_config(tmp_path, tmp_osfs_resource, our_config): @pytest.mark.parametrize("our_config", [deny_client_config]) async def test_client_creation_disallowed(tmp_path, jp_fetch, jp_server_config): cc = ContentsClient(jp_fetch) - resources = await cc.set_resources( - [{"name": "test-2", "url": f"osfs://{tmp_path.as_posix()}"}] - ) + resources = await cc.set_resources([{"name": "test-2", "url": f"osfs://{tmp_path.as_posix()}"}]) assert resources == [] @pytest.mark.parametrize("our_config", [deny_client_config]) @pytest.mark.parametrize("tmp_osfs_resource", [True]) -async def test_client_creation_disallowed_retains_server_config( - tmp_path, jp_fetch, jp_server_config -): +async def test_client_creation_disallowed_retains_server_config(tmp_path, jp_fetch, jp_server_config): cc = ContentsClient(jp_fetch) - resources = await cc.set_resources( - [{"name": "test-2", "url": f"osfs://{tmp_path.as_posix()}"}] - ) + resources = await cc.set_resources([{"name": "test-2", "url": f"osfs://{tmp_path.as_posix()}"}]) names = set(map(lambda r: r["name"], resources)) assert names == {"test-server-config"}