diff --git a/README.md b/README.md index 0ac7112..ab995a1 100644 --- a/README.md +++ b/README.md @@ -73,27 +73,29 @@ from obiba_opal import OpalClient, HTTPError, Formatter, ImportCSVCommand, TaskS # if 2-factor auth is enabled, user will be asked for the secret code # Personal access token authentication is also supported (and recommended) -client = OpalClient.buildWithAuthentication(server='https://opal-demo.obiba.org', user='administrator', password='password') +client = OpalClient.buildWithAuthentication( + server="https://opal-demo.obiba.org", user="administrator", password="password" +) try: # upload a local CSV data file into Opal file system fs = FileService(client) - fs.upload_file('./data.csv', '/tmp') + fs.upload_file("./data.csv", "/tmp") # import this CSV file into a project - task = ImportCSVCommand(client).import_data('/tmp/data.csv', 'CNSIM') - status = TaskService(client).wait_task(task['id']) - + task = ImportCSVCommand(client).import_data("/tmp/data.csv", "CNSIM") + status = TaskService(client).wait_task(task["id"]) + # clean data file from Opal - fs.delete_file('/tmp/data.csv') + fs.delete_file("/tmp/data.csv") - if status == 'SUCCEEDED': + if status == "SUCCEEDED": dico = DictionaryService(client) - table = dico.get_table('CNSIM', 'data') + table = dico.get_table("CNSIM", "data") # do something ... - dico.delete_tables('CNSIM', ['data']) + dico.delete_tables("CNSIM", ["data"]) else: - print('Import failed!') + print("Import failed!") # do something ... except HTTPError as e: Formatter.print_json(e.error, True) diff --git a/obiba_opal/commands.py b/obiba_opal/commands.py index 3353a19..b4dd536 100644 --- a/obiba_opal/commands.py +++ b/obiba_opal/commands.py @@ -134,12 +134,21 @@ def project_command( None, "--name", "-n", help="Project name. Not specifying the project name, will get the list of the projects." ), database: str | None = typer.Option( - None, "--database", "-db", help="Project database name. If not provided only views can be added." + None, + "--database", + "-db", + help="Project database name. If not provided and internal is False, only views can be added.", ), title: str | None = typer.Option(None, "--title", "-t", help="Project title."), description: str | None = typer.Option(None, "--description", "-dc", help="Project description."), tags: list[str] | None = typer.Option(None, "--tags", "-tg", help="Tags to apply to the project."), export_folder: str | None = typer.Option(None, "--export-folder", "-ex", help="Project preferred export folder."), + internal: bool = typer.Option( + False, + "--internal", + "-i", + help="Create the project using an internal database. Ignored if database is provided.", + ), add: bool = typer.Option(False, "--add", "-a", help="Add a project (requires at least a project name)."), delete: bool = typer.Option(False, "--delete", "-de", help="Delete a project (requires at least a project name)."), force: bool = typer.Option(False, "--force", "-f", help="Skip confirmation on project deletion"), @@ -162,6 +171,7 @@ def project_command( description=description, tags=tags, export_folder=export_folder, + internal=internal, add=add, delete=delete, force=force, diff --git a/obiba_opal/file.py b/obiba_opal/file.py index 5269463..24561d6 100755 --- a/obiba_opal/file.py +++ b/obiba_opal/file.py @@ -119,7 +119,15 @@ def download_file(self, path: str, fd: int | os.PathLike, download_password: str bundle_request = self.client.new_request().fail_on_error() if self.verbose: bundle_request.verbose() - response = bundle_request.post().resource("/shell/commands/_file-bundle").accept_json().content_type_json().content(json.dumps(options)).send() + response = ( + bundle_request + .post() + .resource("/shell/commands/_file-bundle") + .accept_json() + .content_type_json() + .content(json.dumps(options)) + .send() + ) task = response.from_json() task_service = TaskService(self.client) try: @@ -210,9 +218,7 @@ def get_ws(self): return f"/files{self.path}" def make_bundle_options(self, download_password): - options = { - "paths": [self.path] - } + options = {"paths": [self.path]} if download_password: options["password"] = download_password return options diff --git a/obiba_opal/project.py b/obiba_opal/project.py index cfe776d..865229b 100755 --- a/obiba_opal/project.py +++ b/obiba_opal/project.py @@ -32,7 +32,7 @@ def add_arguments(cls, parser): "--database", "-db", required=False, - help="Project database name. If not provided only views can be added.", + help="Project database name. If not provided and internal is False, only views can be added.", ) parser.add_argument("--title", "-t", required=False, help="Project title.") parser.add_argument("--description", "-dc", required=False, help="Project description.") @@ -49,7 +49,12 @@ def add_arguments(cls, parser): required=False, help="Project preferred export folder.", ) - + parser.add_argument( + "--internal", + "-i", + action="store_true", + help="Create the project using an internal database. Ignored if database is provided.", + ) parser.add_argument( "--add", "-a", @@ -94,6 +99,7 @@ def do_command(cls, args): args.description, args.tags, args.export_folder, + args.internal, ) elif args.delete: if not args.name: @@ -154,17 +160,22 @@ def add_project( description: str = None, tags: list = None, export_folder: str = None, + internal: bool = False, ): """ Add a project. :param name: The project name - :param database: The project database name. If not provided only views can be added. See - get_databases() for the list of databases available for storage. + :param database: The project database name. If not provided and internal is False, + only views can be added. See get_databases() for the list of databases available + for storage. :param title: The project title :param description: The project description :param tags: The list of project tags :param export_folder: The project's preferred export folder + :param internal: If True, the project will be created using an internal database. Ignored + if database is provided. If False, the project will be created without a database. Default + is False. """ if not name: raise ValueError("The project name is required.") @@ -173,6 +184,8 @@ def add_project( project = {"name": name} if database: project["database"] = database + elif internal: + project["internalDatabase"] = True if title: project["title"] = title else: diff --git a/obiba_opal/system.py b/obiba_opal/system.py index 9ebe375..5ddcff2 100644 --- a/obiba_opal/system.py +++ b/obiba_opal/system.py @@ -453,7 +453,7 @@ def cancel_task(self, id: str | int): request.put().resource(f"/shell/command/{id}/status").send() def wait_task(self, id: str | int, silently: bool = False): - """ Wait for the task to complete or being canceled, and return its status. """ + """Wait for the task to complete or be canceled, and return its status.""" task = self.get_task(id) while task["status"] not in ["SUCCEEDED", "CANCELED", "FAILED", "CANCEL_PENDING"]: if not silently: diff --git a/pyproject.toml b/pyproject.toml index 7f6a202..96699d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "obiba-opal" -version = "6.1.0" +version = "6.2.0" description = "OBiBa/Opal python client." authors = [ {name = "Yannick Marcon", email = "yannick.marcon@obiba.org"} diff --git a/uv.lock b/uv.lock index bf34e75..e77f5f2 100644 --- a/uv.lock +++ b/uv.lock @@ -245,7 +245,7 @@ wheels = [ [[package]] name = "obiba-opal" -version = "6.1.0" +version = "6.2.0" source = { editable = "." } dependencies = [ { name = "requests" },