diff --git a/README.md b/README.md index 615a1d168d2b0e82a6fb3438414e0de4d0933a93..f7515316ed7f3ae7e8a1b9f5a51d6df46fc40bdc 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ The requirements in the ```requirements.sh``` file correspond to certain python To install the requirements, open the terminal and execute the following commands: Change directory: - ``` cd git_zenodo_tutorial``` + ``` cd git_zenodo_assistant``` Run the requirements file to install the libraries: ``` sh requirements.sh ``` diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/git_assistant/__init__.py b/git_assistant/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/git_assistant/git_tools/__init__.py b/git_assistant/git_tools/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/git_assistant/git_tools/git_more.py b/git_assistant/git_tools/git_more.py new file mode 100644 index 0000000000000000000000000000000000000000..ce2bdfe3c00d547db73592619a6b7704497ef095 --- /dev/null +++ b/git_assistant/git_tools/git_more.py @@ -0,0 +1,152 @@ +def git_review(): + + # Tools + import tkinter as tk + import tkinter.ttk + + # Messages for windows + + message0 = """ + Git is more than a website, Git is a control version software, which is + a software made for tracking changes in any set of files in a directory. + Managing changes of your documents, data, notebooks and coding scripts is + essential when you do research.\n + As you probably have learned by now, just copying your files and renaming + them as "myProjectUpdateFinalTrueFinalPrint.ipynb" is not the most + efficient way to do so. Git makes it easier by providing an online + plataform for Version Control of personal and collaborative projects. + """ + + message1 = """ + The Git software stores and save files to a directory called repository, + also shorten as repo. A Git repository allows various operations to create + different versions of the files in it.\n + A Git repository can be local (placed in your computer) or remote + (hosted on the Internet, or in a different server).\n + By installing git to your computer, and creating a GitHub or GitLab + account you can start your Version Control with git. + """ + + message2 = """ + From Github or Gitlab you can Fork and Clone repositories.\n + A git fork is an operation of copying a repository to your git account.\n + A git clone is an operation of copying a repository to your local machine.\n + Maybe you knew all of this already. In fact, you probably have this program + running because you did a git clone to your computer (or Virtual Machine, + for that matter).\n + One more thing before you continue: remember than you can only push to git + repositories where you have permissions to do so. If you need to clone a + repo that you do not own and need to make changes, fork the repo first and + then you can clone it. + """ + + message3 = """ + You can obtain a Git repository by either cloning a Git repository + or by converting a local directory to a Git repository, using git init.\n + It does not matter if the directory is a new local directory, or an + already existent local directory, the command git init works in both + cases.\n + And you can also git init a git repository, is it safe to do so, + it will not overwrite files that are already there. + """ + + message4 = """ + Git push is an operation to publish new local commits on a remote server.\n + When you want to update your changes (could be a new file in the directory, + or a change in an already existing file)to your Git account, you need to git + push.\n + But before a git push, you have to git add (to add your new or modified + files to your git repo), git commit (to save these changes) and then you + can execute your git push command.\n + There could be more commands that you need to execute before a git push. + This is only a basic review, and although the tutorial will include some new + steps. You can learn more in the documentation and you should. + """ + + # Creating window + root = tk.Tk() + root.title("Review of Git") + root.geometry("250x200") + root.config(background = "#F5F5F5") + root.eval('tk::PlaceWindow . center') + label = tk.Label(root, text ="Select an option and\n review some concepts") + label.pack(pady = 10) + + + # Open window functions + def open_window_0(): + + window_0 = tk.Toplevel(root) + window_0.title("Git and Version Control") + window_0.geometry("530x200") + window_0.config(background = "#F5F5F5") + # Texts + title = tk.Label(window_0, text ="\n\nWhat is Git?", bg= "#F5F5F5").pack() + text = tk.Label(window_0, text =message0, bg= "#F5F5F5", anchor="e", justify="left", width=100).pack() + + return + + def open_window_1(): + + window_1 = tk.Toplevel(root) + window_1.title("Git Repository") + window_1.geometry("540x200") + window_1.config(background = "#F5F5F5") + title = tk.Label(window_1, text ="\n\nWhat is a Git repository?", bg= "#F5F5F5").pack() + text = tk.Label(window_1, text = message1, bg= "#F5F5F5", anchor="e", justify="left", width=100).pack() + + return + + def open_window_2(): + + window_2 = tk.Toplevel(root) + window_2.title("git fork/git clone") + window_2.geometry("550x250") + window_2.config(background = "#F5F5F5") + title = tk.Label(window_2, text ="\n\nWhat does a git fork/git clone do?", bg= "#F5F5F5").pack() + text = tk.Label(window_2, text =message2, bg= "#F5F5F5", anchor="e", justify="left", width=100).pack() + + def open_window_3(): + + window_3 = tk.Toplevel(root) + window_3.title("git init") + window_3.geometry("510x200") + window_3.config(background = "#F5F5F5") + title = tk.Label(window_3, text ="\n\nWhat does a git init do?", bg= "#F5F5F5").pack() + text = tk.Label(window_3, text =message3, bg= "#F5F5F5", anchor="e", justify="left", width=100).pack() + return + + def open_window_4(): + + window_4 = tk.Toplevel(root) + window_4.title("git add/git commit/git push") + window_4.geometry("560x230") + window_4.config(background = "#F5F5F5") + title = tk.Label(window_4, text ="\n\nGit push and the previous steps", bg= "#F5F5F5").pack() + text = tk.Label(window_4, text =message4, bg= "#F5F5F5", anchor="e", justify="left", width=100).pack() + return + + # Buttons that open windows and destroy the root window. + + button_0 = tk.Button(root, text ="Git and Version Control", bg="#B0E0E6", command=open_window_0) + button_0.pack(side="top") + + button_1 = tk.Button(root, text= "Git Repository", bg="#B0E0E6", command=open_window_1) + button_1.pack(side="top") + + button_2 = tk.Button(root, text= "git fork/git clone", bg="#B0E0E6", command=open_window_2) + button_2.pack(side="top") + + button_3 = tk.Button(root, text ="git init", bg="#B0E0E6", command=open_window_3) + button_3.pack(side="top") + + button_4 = tk.Button(root, text= "git add/git commit/git push", bg="#B0E0E6", command=open_window_4) + button_4.pack(side="top") + + button_done = tk.Button(root, text = "Done", bg="#FF6347", command=root.destroy) + button_done.pack(side="bottom") + + # mainloop, runs infinitely, unless root.destroy + root.mainloop() + + return diff --git a/git_assistant/git_tools/git_search.py b/git_assistant/git_tools/git_search.py new file mode 100644 index 0000000000000000000000000000000000000000..9a255c8014fe0597849215b40e65381d84becd35 --- /dev/null +++ b/git_assistant/git_tools/git_search.py @@ -0,0 +1,33 @@ +def path_input(): + + # Tools + import tkinter as tk + from tkinter import filedialog + from termcolor import colored, cprint + + # Function to select directory and store path + def select_dir(): + done = colored('Done', 'red') + global path + path = tk.filedialog.askdirectory() + print(f"Selected directory: {path}\n" + f"\nClick {done} or change your selection.\n") + return + + # Creating window + root = tk.Tk() + root.title("File browser") + root.geometry("250x60") + root.config(background = "#F5F5F5") + root.eval('tk::PlaceWindow . center') + + # Buttons that execute the function and destroy the loop + button_explore = tk.Button(root, text="Explore", bg="#B0E0E6", command=select_dir) + button_done = tk.Button(root, text = "Done", bg="#FF6347", command=root.destroy) + + button_explore.pack(side="top") + button_done.pack(side="top") + + root.mainloop() + + return path diff --git a/git_assistant/git_tutorial.py b/git_assistant/git_tutorial.py new file mode 100644 index 0000000000000000000000000000000000000000..6331b3363d07ff924503360e4350743b9c907132 --- /dev/null +++ b/git_assistant/git_tutorial.py @@ -0,0 +1,247 @@ +# Tools +import os +import time +from termcolor import colored, cprint +from git_assistant.git_tools.git_search import path_input +from git_assistant.git_tools.git_more import git_review + +# Hello world + +git = colored('Git', 'cyan') +enter = colored('Enter', 'cyan') +init = colored('init', 'cyan') +fork = colored('fork', 'cyan') +clone = colored('clone', 'cyan') +add = colored('add', 'cyan') +allfiles = colored('--all', 'cyan') +log = colored('log', 'cyan') +commit = colored('commit', 'cyan') +push = colored('push', 'cyan') +remote = colored('remote add origin', 'cyan') +select = colored('Select', 'cyan') +submit = colored('Submit', 'cyan') +explore = colored('Explore', 'cyan') +done = colored('Done', 'red') +password = colored('password', 'cyan') +token = colored('token', 'cyan') +gitlab = colored('GitLab', 'cyan') +github = colored('GitHub', 'cyan') +copy = colored("COPY", "green", attrs=['reverse']) +paste = colored("PASTE", "green", attrs=['reverse']) + +welcome_message = f""" +Hello! Welcome to this {git} tutorial, where you will upload a file to +your {git} remote repository, and learn some basic commands of git to +type them in the terminal the next time, without using this program.\n +Here, you will have to paste the URL of your {git} repository, provide the name +of the file you want to upload, a commit message and finally, your username and +password/token. You will not execute the commands yourself, the programm will do it +for you. +""" + +print(welcome_message) +input(f"When you are ready, press {enter} to start and learn about {git}.") + +more_message = f""" +This tutorial is not intented to teach you ALL about git, but to help +you to {git} {add}, {git} {commit} and {git} {push} a file to your git +repository by teaching some important things along the way.\n +You do not have to understand it all by the end, altough we hope +that if one day you need to {git} {remote}, you will remember +that you saw it here first.\n +Before starting the tutorial, you should already be a little bit +familiarized with {git}. If you are not, do not worry. We have created +a review of some important concepts, in case you need it. +""" + +print(more_message) +input(f"Press {enter} to see the review. Click {done} when you finish.") +git_review() + +input(f"Excellent! Let's start the tutorial. Press {enter}") + +browser_message = f""" +Before executing your {git} commands, you should be located (pwd) in the +directory that you want to {git} {init}, {git} {push}, etc... This is, you +should change directories (cd). But you will not need to exit the program! +Let me help you to do it. +""" + +print(browser_message) +input(f"Press {enter} to open the Directory Browser to {select} and {submit} the " + "path of the directory that you want.\n") +open_browser = True +while open_browser == True: + try: + git_path = path_input() + break + except: + print(f"You did not {submit} any directory. Try again: click {explore}, pick your directory and then {done}.\n") + try: + git_path = path_input() + break + except: + print(f"You did not {submit} any directory. Try again: click {explore}, pick your directory and then {done}.\n") + open_browser = True + +input(f"The path to your directory has been stored. Press {enter} to continue.\n") +print("Changing directory...\n") +time.sleep(2) +os.chdir(git_path) +input(f"Done! Press {enter} to continue.\n") + + +# Git init + +init_message = f""" +If you try to execute {git} commands in a non-git directory, you will +encounter a fatal error: not a git repository.\n +To avoid this error, first you have to {git} {init}. And if, by accident, +your directory was already a {git} repository, there is no problem, +it wil not overwrite anything. +""" +print(init_message) +cprint("command0: git init ", "green") +input(f"\nPress {enter} to execute your command...") +os.system("git init") + +# Remove origin + +rm_message = f""" +A {git} remote origin is the name for the remote repository of a {git} +directory. If you try to execute {git} commands in the wrong remote +repository, you will encounter errors. To make sure this do not +happen while running the tutorial, we are going to remove the previous +origin. +""" + +print(rm_message) +cprint("command1: git remote rm origin ", "green") +input(f"\nPress {enter} to execute your command...") +os.system("git remote rm origin") + +# Add origin + +origin_message = f""" +Now, let's add a new origin. You will need to provide the url of the +{git} repo where you want to you {git} {push}. +""" + +print(origin_message) +url = input(str(f"Paste the url of your {git} repository: ")) +print(f"Please, check the url: {url}\n") +url_answer = input(str("Is that the right url? y/n: ")) +while url_answer != "y": + if url_answer == "n": + url = input(str(f"\nNo problem! Let's try again\nPaste the url of your {git} repository: ")) + print(f"Please, check the url: {url}\n") + url_answer = input(str("Is that the right url? y/n: ")) + else: + print("\nInvalid option. Try again.\n") + print(f"Please, check the url: {url}\n") + url_answer = input(str("Is that the right url? y/n: ")) +if url_answer == "y": + print(f"Excellent!\n. To {add} the origin we will use the next command.\n") + +cprint(f"command2: git remote add origin {url}", "green") +input(f"\nPress {enter} to execute the command...") +os.system(f"git remote add origin {url}") + +# Check the new origin +print("\nAnd you can check the new origin by doing: \n") +cprint("command3: git remote -v ", "green") +input(f"\nPress {enter} to execute the command...") +os.system("git remote -v") + +# Git status +status_message = f""" +{git} status shows the current state of your {git} working directory +and staging area. Green shows file is in {git} repository and +committed with latest changes. Red shows file is in {git} repository +but latest changes has not been committed. If you do not {add} the +red files before committing, these files will not be included in +your {commit}. +""" + +print(status_message) +cprint("command4: git status", "green") +input(f"\n{press} Enter to execute the command...") +os.system("git status") + +# Git add +print(f"\nTo {git} {add}, you have to pick a file in red from the list above and copy the name.") +file = input(str("Paste the name of your file and do not forget the extension (example.ipynb)\n" + "or type {allfiles} to add all the files in the directory: ")) +print(f"Please, check the name of your file: {file}\n") +file_answer = input(str("Is that the right name and extension? y/n: ")) +while file_answer != "y": + if file_answer == "n": + file = input(str(f"\nNo problem! Let's try again.\n" + f"Paste the name of the file (example.ipynb) or type {allfiles}: ")) + print(f"Please, check the name of your file: {file}\n") + file_answer = input(str("Is that the right name and extension? y/n: ")) + else: + print("\nInvalid option. Try again.\n") + print(f"Please, check the name of your file: {file}\n") + file_answer = input(str("Is that the right name and extension? y/n: ")) + +if file_answer == "y": + print("Excellent!\n By adding a new file, you choose which changes you want to save\n") +cprint(f"command5: git add {file}", "green") +input(f"\nPress {enter} to execute the command...") +os.system(f"git add {file}") + +# Git commit +print(f"\nWhen you {commit}, you save these changes. To identify these changes, you can write a {commit} message") +commit = input(f"Type a {commit} message. Make it short and simple: ") +cprint("command6: git commit -m", "green") +input(f"\nPress {enter} to execute the command...") +os.system(f"git commit -m {commit}") + +# Git log +print(f"\nAnd you can see the record of commits that you have done using {git} {log}.") +cprint("command6: git log", "green") +input(f"\nPress {enter} to execute the command...") +os.system("git log") + +# Git push +push_message = f""" +Finally, {push} to your repository by executing the next command. Note that +you will need to enter your {git} username and password/token. Do not worry if +you do not see your password in the console when you type it! +It is to protect your data.\n +To access your {gitlab} account, you need your {password}.\n +To access your {github} account, you need a {token}.\n +You can generate a token by logging in to your {git} account +and going into this page: +{colored('https://github.com/settings/tokens', 'cyan')}\n +Select only the repo scopes.\n +Remember to {copy} the token so you can {paste} it here. +Press {enter} when you are ready. +""" + +input(push_message) +cprint(f"command6: git push {url}", "green") +input(f"\nPress {enter} to execute the command...") +os.system(f"git push {url}") + +# Check the git push +print(f"Go to:\n{url}\nto see if the {push} was successful.") +push_answer = input(str("Has your file been pushed correctly? y/n: ")) + +while push_answer =="n": + push_error = input(str("\nYou probably had an Authentication Error.\n Do you want to:\n" + f"a) try to {push} again?\n" + "b) Exit and try the tutorial later?\n")) + if push_error == "a": + cprint(f"command6: git push {url}", "green") + input(f"\nPress {enter} to execute the command...") + os.system(f"git push {url}") + print(f"Go to:\n{url}\nto see if the {push} was successful.") + push_answer = input(str("Has your file been pushed correctly? y/n: ")) + elif push_error == "b": + push_answer = "y" + +# End of tutorial +if push_answer == "y": + print("\nAlright! You have reached the end of this tutorial.\n") diff --git a/images_tutorial/git001.png b/images_tutorial/git001.png new file mode 100644 index 0000000000000000000000000000000000000000..3f1e34e9911a7b0323110045bd0bcd5323e0c376 Binary files /dev/null and b/images_tutorial/git001.png differ diff --git a/images_tutorial/git002.png b/images_tutorial/git002.png new file mode 100644 index 0000000000000000000000000000000000000000..ed3731eb27e9c9bae656d87f637dd76461fcc416 Binary files /dev/null and b/images_tutorial/git002.png differ diff --git a/images_tutorial/git003.png b/images_tutorial/git003.png new file mode 100644 index 0000000000000000000000000000000000000000..53c9fa9447d02f01a185140290cc9b2c97afaacc Binary files /dev/null and b/images_tutorial/git003.png differ diff --git a/images_tutorial/git004.png b/images_tutorial/git004.png new file mode 100644 index 0000000000000000000000000000000000000000..544bcbc6efb2a52edf2473966448d7402f2fc629 Binary files /dev/null and b/images_tutorial/git004.png differ diff --git a/images_tutorial/git005.png b/images_tutorial/git005.png new file mode 100644 index 0000000000000000000000000000000000000000..a3d73f31a71f77215e9a0fbccea701a888be4aff Binary files /dev/null and b/images_tutorial/git005.png differ diff --git a/images_tutorial/git006.png b/images_tutorial/git006.png new file mode 100644 index 0000000000000000000000000000000000000000..3e1377c49baaca36129fc755167fb5905ed06c5b Binary files /dev/null and b/images_tutorial/git006.png differ diff --git a/images_tutorial/git007.png b/images_tutorial/git007.png new file mode 100644 index 0000000000000000000000000000000000000000..7b5f74044c07e219e8ecba63228745167eb8118e Binary files /dev/null and b/images_tutorial/git007.png differ diff --git a/images_tutorial/git_image.png b/images_tutorial/git_image.png new file mode 100644 index 0000000000000000000000000000000000000000..d7ec7ce6e53fec7ab2563ca735687989bcdebd5b Binary files /dev/null and b/images_tutorial/git_image.png differ diff --git a/images_tutorial/repo_image.png b/images_tutorial/repo_image.png new file mode 100644 index 0000000000000000000000000000000000000000..2430a0489b78de1cac9b835c4563be34ac83e791 Binary files /dev/null and b/images_tutorial/repo_image.png differ diff --git a/images_tutorial/zenodo001.png b/images_tutorial/zenodo001.png new file mode 100644 index 0000000000000000000000000000000000000000..72ab0faea1e94e7b44d77fce977506ceda3bc75d Binary files /dev/null and b/images_tutorial/zenodo001.png differ diff --git a/images_tutorial/zenodo002.png b/images_tutorial/zenodo002.png new file mode 100644 index 0000000000000000000000000000000000000000..798407ef9dd1c84dea37f93ec7a95734fc9d754a Binary files /dev/null and b/images_tutorial/zenodo002.png differ diff --git a/images_tutorial/zenodo003.png b/images_tutorial/zenodo003.png new file mode 100644 index 0000000000000000000000000000000000000000..b2866ebb3147f66ab0144d285e03488b5b4b39f6 Binary files /dev/null and b/images_tutorial/zenodo003.png differ diff --git a/images_tutorial/zenodo_image.png b/images_tutorial/zenodo_image.png new file mode 100644 index 0000000000000000000000000000000000000000..63ed165cb03c43f5768afc153526750c5f7ccdd1 Binary files /dev/null and b/images_tutorial/zenodo_image.png differ diff --git a/requirements.sh b/requirements.sh new file mode 100644 index 0000000000000000000000000000000000000000..228d2a3de0ac2aa584757c95a45c00b1e0c6db82 --- /dev/null +++ b/requirements.sh @@ -0,0 +1,7 @@ +pip install --upgrade pip +pip3 install requests +pip3 install termcolor +pip3 install pandas +sudo apt-get install python3-tk +pip3 install tkcalendar + diff --git a/test_tutorial/test.txt b/test_tutorial/test.txt new file mode 100644 index 0000000000000000000000000000000000000000..882c3a8eaaa59ab6504fc60ae5cfe1eea5e83fef --- /dev/null +++ b/test_tutorial/test.txt @@ -0,0 +1,12 @@ + + +************************************************* +This file was uploaded to test the code from the +Git&Zenodo Assistant, a program designed as a part +of the final project: "OP1: Scientific Computing" +in LA-CoNGA Physics' Data Science Module. +This project was done by: +-Andrea Tugores (UCV, Venezuela) +-Jonatan Vignatti (UNMSM, Peru) +-Maria Ramos (ULA, Venezuela) +************************************************* diff --git a/tutorial.py b/tutorial.py new file mode 100644 index 0000000000000000000000000000000000000000..4593c9c4559da677d2479fab42f09c26a19c4aef --- /dev/null +++ b/tutorial.py @@ -0,0 +1,125 @@ +import os +import time +from termcolor import colored, cprint + +def start_git(): + answer = input(f"\nPress any key to start the {c_Git} Tutorial.\n" + "\nPress x to take you back to the main menu.") + if answer in ("x", "X"): + print(f"\nGoing back to main menu...\n") + time.sleep(2) + return + else: + print(f"\nStarting {c_Git} Tutorial...\n") + time.sleep(2) + from git_assistant import git_tutorial + input("Press any key to take you back to the main menu.\n") + print(f"Going back to main menu...\n") + time.sleep(2) + return + +# Start zenodo tutorial +def start_zenodo(): + answer = input(f"\nPress any key to start the {c_Zenodo} Assistant.\n" + "\nPress x to take you back to the main menu.") + if answer in ("x", "X"): + print(f"\nGoing back to main menu...\n") + time.sleep(2) + else: + print(f"\nStarting {c_Zenodo} Assistant...\n") + time.sleep(2) + from zenodo_assistant import zenodo_tutorial + input("Press any key to take you back to the main menu.\n") + print(f"Going back to main menu...\n") + time.sleep(2) + return + +# Access Git Documentation +def about_git(): + print(f"\nTo learn more about {c_Git}:\n\n" + f"Github: {colored('https://github.com/', 'blue')} \n" + f"Gitlab: {colored('https://about.gitlab.com/', 'blue')}\n" + f"Documentation: {colored('https://git-scm.com/doc','blue')} \n") + input("Press any key to take you back to the main menu.\n") + print(f"Going back to main menu...\n") + time.sleep(2) + return + +# Access Zenodo Documentation +def about_zenodo(): + print(f"\nTo learn more about {c_Zenodo}:\n\n" + "Zenodo: https://zenodo.org/ \n" + "Zenodo REST API: https://developers.zenodo.org/ \n") + input("Press any key to take you back to the main menu.\n") + print(f"Going back to main menu...\n") + time.sleep(2) + return + +c_assistant = colored("Git&Zenodo Assistant", "cyan") +c_atlas = colored("ATLAS Virtual Machine", "cyan") +c_Git = colored("Git", "cyan") +c_Github = colored("GitHub", "cyan") +c_Gitlab = colored("GitLab", "cyan") +c_Zenodo = colored("Zenodo", "cyan") +c_README = colored("README.md", "cyan") +c_test = colored("test_tutorial", "cyan") +c_NOTE = colored("NOTE", "cyan", attrs=["reverse"]) + + +# Welcome message +main_message = f""" +\nWelcome to your {c_assistant}.\n +I will help you to start your journey in Open Science by uploading +your own files created in the {c_atlas} to your {c_Git} account +and/or {c_Zenodo} account.\n +If you do not have already an account in {c_Github}, {c_Gitlab} or +{c_Zenodo}, consult the documentation, where you can find links +to their respective websites.\n + {c_NOTE}\n +**Please, read the {c_README} file before starting the assistant, +you will find helpful information in there** \n +**If you are only testing this program, the {c_test} folder +contains a text file you can use to try the {c_Git} push and the +{c_Zenodo} upload.** +""" +print(main_message) + + +input("Press any key to start the main menu...\n") +print(f"Starting main menu...\n") +time.sleep(2) + +# Main Menu +str_menu = ("Do you wish to:\n" + f"a) Upload a file to your {c_Git} repository?\n" + f"b) Upload a file to your {c_Zenodo} account?\n" + f"c) Consult the {c_Git} Documentation\n" + f"d) Consult the {c_Zenodo} Documentation\n" + "e) Exit\n") +print(str_menu) +menu = input(str()) + +while menu != "e" and menu != "E": + if menu in ("a", "A"): + start_git() + print(str_menu) + menu = input(str()) + elif menu in ("b", "B"): + start_zenodo() + print(str_menu) + menu = input(str()) + elif menu in ("c", "C"): + about_git() + print(str_menu) + menu = input(str()) + elif menu in ("d", "D"): + about_zenodo() + print(str_menu) + menu = input(str()) + else: + print("\nSorry, that was not a valid option. " + "Check again and choose a valid option\n") + print(str_menu) + menu = input(str()) +if menu in ("e", "E"): + print("\nOk, see you later. Keep researching!\n") diff --git a/zenodo_assitant/__init__.py b/zenodo_assitant/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/zenodo_assitant/zenodo_tools/__init__.py b/zenodo_assitant/zenodo_tools/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/zenodo_assitant/zenodo_tools/zenodo_date.py b/zenodo_assitant/zenodo_tools/zenodo_date.py new file mode 100644 index 0000000000000000000000000000000000000000..3744dbfe8e6896ff04988125fe5abdb4657f9c94 --- /dev/null +++ b/zenodo_assitant/zenodo_tools/zenodo_date.py @@ -0,0 +1,38 @@ +def date_input(): + + # Tools + import tkinter as tk + from tkcalendar import Calendar, DateEntry + from termcolor import colored, cprint + + # Function to open calendar and get date + def select_date(): + done = colored('Done', 'red') + global pub_date_input + pub_date_input = cal.selection_get() + print(f"You selected: {pub_date_input}. Click {done} or change your selection.") + return + + # Create window + root= tk.Tk() + root.title("Calendar") + root.geometry("250x250") + root.config(background = "#F5F5F5") + root.eval('tk::PlaceWindow . center') + + # Generate Calendar + cal= Calendar(root, selectmode="day",year= 2021, month=5, day=10, cursor="hand1") + cal.pack(fill="both", expand=True) + + # Create Buttons + button_date= tk.Button(root, text= "Select the Date", bg="#B0E0E6", command=select_date) + button_date.pack(side="top") + + button_done = tk.Button(root, text = "Done", bg="#FF6347", command=root.destroy) + button_done.pack(side="bottom") + + # Generate loop + selected_date = None + root.mainloop() + + return pub_date_input diff --git a/zenodo_assitant/zenodo_tools/zenodo_functions.py b/zenodo_assitant/zenodo_tools/zenodo_functions.py new file mode 100644 index 0000000000000000000000000000000000000000..134197fc775cb25c314c65caec7fdc7167796344 --- /dev/null +++ b/zenodo_assitant/zenodo_tools/zenodo_functions.py @@ -0,0 +1,126 @@ + +# Title function +def type_title(): + + from termcolor import cprint, colored + enter = colored('Enter', 'cyan') + + title = input(str("Type the title of your work: ")) + print(f"\nCheck the title: {title}") + title_answer = input(str("\nIs the title correct? (y/n): ")) + + # Change the title + while title_answer not in ("y", "yes", "YES"): + + if title_answer in ("n", "no", "NO"): + title = input(str("\nPlease, type the title of your work again: ")) + print(f"\nCheck the title: {title}") + title_answer = input(str("\nIs the title correct? (y/n): ")) + else: + print(f"\nInvalid option. Check the title: {title}") + title_answer = input(str("\nIs the title correct? (y/n): ")) + + # Store the title as variable + if title_answer in ("y", "yes", "YES"): + input(f"\nThe title has been stored. Press {enter} to continue.\n") + + return title + +# Description function +def type_description(): + + from termcolor import cprint, colored + enter = colored('Enter', 'cyan') + + description = input(str("Type or paste the description of your work: ")) + print(f"\nCheck the description:\n{description}") + description_answer = input(str("\nIs the description correct? (y/n): ")) + + # Change description + while description_answer not in ("y", "yes", "YES"): + + if description_answer in ("n", "no", "NO"): + description = input(str("\nPlease, type or paste the description of your work again: ")) + print(f"\nCheck the description:\n{description}") + description_answer = input(str("\nIs the description correct? (y/n): ")) + else: + print(f"\nInvalid option. Check the description:\n{description}") + description_answer = input(str("\nIs the description correct? (y/n): ")) + + # Store description as variable + if description_answer in ("y", "yes", "YES"): + input(f"\nThe description has been stored. Press {enter} to continue.\n") + + return description + + +# Creators function +def creators_dict(): + + from termcolor import cprint, colored + enter = colored('Enter', 'cyan') + + # Create array + creators = [] + + # Add creator + author_i = input(str("Type the name of the author (format: Ramos, Maria): ")) + affiliation_i = input(str("\nType their affiliation: ")) + creator_i = author_check(author_i, affiliation_i) + creators.append(creator_i) + input(f"\nThe author's information has been stored. Press {enter} to continue.\n") + + # Add more creators + creators_answer = input(str("Do you want to add another author? (y/n): ")) + + while creators_answer not in ("n", "no", "NO"): + + if creators_answer in ("y", "yes", "YES"): + author_i = input(str("\nType the name of the author (format: Ramos, Maria): ")) + affiliation_i = input(str("\nType their affiliation: ")) + creator_i = author_check(author_i, affiliation_i) + creators.append(creator_i) + input(f"\nThe author's information has been stored. Press {enter} to continue.\n") + creators_answer = input(str("Do you want to add another author? (y/n): ")) + else: + creators_answer = input(str("Invalid option. Do you want to add another author? (y/n): ")) + + # Stop adding authors + if creators_answer in ("n", "no", "NO"): + print("\nThe creators data has been stored.\n") + + return creators + +# Check author's information +def author_check(author_i, affiliation_i): + + print(f"\nCheck the author's information:\n" + f"Name: {author_i}\n" + f"Affiliation: {affiliation_i}") + author_answer = input(str("\nIs the information correct? (y/n): ")) + + # Change the author's information + while author_answer not in ("y", "yes", "YES"): + + if author_answer in ("n", "no", "NO"): + author_i = input(str("\nPlease, type the name of the author again (format: Ramos, Maria): ")) + affiliation_i = input(str("\nType their affiliation: ")) + print(f"\nCheck the author's information:\n" + f"Name: {author_i}\n" + f"Affiliation: {affiliation_i}") + author_answer = input(str("\nIs the information correct? (y/n): ")) + else: + print(f"\nInvalid option. Check the author's information:\n" + f"Name: {author_i}\n" + f"Affiliation: {affiliation_i}") + author_answer = input(str("\nIs the information correct? (y/n): ")) + + # Store the author's information as a dictionary to add in the array + if author_answer in ("y", "yes", "YES"): + creator_i = {'name': f'{author_i}', + 'affiliation': f'{affiliation_i}'} + + return creator_i + + + diff --git a/zenodo_assitant/zenodo_tools/zenodo_images.py b/zenodo_assitant/zenodo_tools/zenodo_images.py new file mode 100644 index 0000000000000000000000000000000000000000..e68ba688128a437cca5ea08bd9ffdc441080bb7c --- /dev/null +++ b/zenodo_assitant/zenodo_tools/zenodo_images.py @@ -0,0 +1,46 @@ +def image_options(): + + # Tools + import tkinter as tk + from termcolor import colored, cprint + + # Create window + root = tk.Tk() + root.title("Image options") + root.geometry('250x200') + root.config(background = "#F5F5F5") + root.eval('tk::PlaceWindow . center') + + # List of image options + options_list = ["Figure", "Plot", "Drawing", "Diagram", "Photo", "Other"] + + # Variable to keep track of the option + # selected in OptionMenu + value_inside = tk.StringVar(root) + + # Set the default value of the variable + value_inside.set("Select an Option") + + # Create the optionmenu + question_menu = tk.OptionMenu(root, value_inside, *options_list) + question_menu.pack() + + # Function to get and print the submitted option + def pick_image_type(): + done = colored('Done', 'red') + global image_type + image_type = value_inside.get() + print(f"You selected: {image_type}. Click {done} or change your selection.") + return + + # Create buttons to sumbit the option (print and store) and close the window + submit_button = tk.Button(root, text='Submit', bg="#B0E0E6", command=pick_image_type) + submit_button.pack(padx=15, pady=35) + + button_done = tk.Button(root, text = "Done", bg="#FF6347", command=root.destroy) + button_done.pack() + + # Generate loop + root.mainloop() + + return image_type diff --git a/zenodo_assitant/zenodo_tools/zenodo_metadata.py b/zenodo_assitant/zenodo_tools/zenodo_metadata.py new file mode 100644 index 0000000000000000000000000000000000000000..90847bdaba6d0c03d5c00135030993151f8b138f --- /dev/null +++ b/zenodo_assitant/zenodo_tools/zenodo_metadata.py @@ -0,0 +1,104 @@ +# Find controlled vocabulary for upload type +def upload_metadata(upload_input): + import pandas as pd + # Generate dataframe from the upload type options + upload_md = pd.read_csv("metadata/upload_type.csv", header=0, dtype="str") + # Find the controlled vocabulary of that option + try: + find_upload = upload_md[upload_md.eq(upload_input).any(axis=1)] + upload = find_upload.iloc[0]["upload_MD"] + except: + upload = "other" + return upload + + +# Find controlled vocabulary for publication type +def pub_metadata(pub_input): + import pandas as pd + # Generate dataframe from the publication type options + pub_md = pd.read_csv("metadata/publication_type.csv", header=0, dtype="str") + # Find the controlled vocabulary of that option + try: + find_publication = pub_md[pub_md.eq(pub_input).any(axis=1)] + publication = find_publication.iloc[0]["publication_MD"] + except: + publication = "other" + return publication + + +# Find controlled vocabulary for image type +def image_metadata(image_input): + import pandas as pd + # Generate dataframe from the image type options + image_md = pd.read_csv("metadata/image_type.csv", header=0, dtype="str") + # Find the controlled vocabulary of that option + try: + find_image = image_md[image_md.eq(image_input).any(axis=1)] + image = find_image.iloc[0]["image_MD"] + except: + image = "other" + return image + + +# Generate the metadata: a dictionary from the variables +def generate_md(title, description, publication_date, upload, image, publication, creators): + + if publication != "None": + data = {'metadata': {'title': f'{title}', + 'description': f'{description}', + 'publication_date': f'{publication_date}', + 'upload_type': f'{upload}', + 'publication_type': f'{publication}', + 'creators': creators}} + + print("The metadata has been stored.\n" + "You can always change it in Zenodo's website after you upload.") + + elif image != "None": + data = {'metadata': {'title': f'{title}', + 'description': f'{description}', + 'publication_date': f'{publication_date}', + 'upload_type': f'{upload}', + 'image_type': f'{image}', + 'creators': creators}} + + print("The metadata has been stored.\n" + "You can always change it in Zenodo's website after you upload.") + + else: + data = {'metadata': {'title': f'{title}', + 'description': f'{description}', + 'publication_date': f'{publication_date}', + 'upload_type': f'{upload}', + 'creators': creators}} + + print("The metadata has been stored.\n" + "You can always change it in Zenodo's website after you upload.\n") + + return data + +# Dataframe from the metadata +def print_md(data): + import pandas as pd + df = pd.DataFrame.from_dict(data['metadata'], orient='index', columns=["Metadata"]) + return df + + + + + + + + + + + + + + + + + + + + diff --git a/zenodo_assitant/zenodo_tools/zenodo_publication.py b/zenodo_assitant/zenodo_tools/zenodo_publication.py new file mode 100644 index 0000000000000000000000000000000000000000..fec9506dbc415bbab272588a4b53f46ba727cb1a --- /dev/null +++ b/zenodo_assitant/zenodo_tools/zenodo_publication.py @@ -0,0 +1,50 @@ +def pub_options(): + + # Tools + import tkinter as tk + from termcolor import colored, cprint + + # Create window + root = tk.Tk() + root.title("Publication options") + root.geometry('250x200') + root.config(background = "#F5F5F5") + root.eval('tk::PlaceWindow . center') + + # Create the list of publication options + options_list = ["Annotation collection", "Book", "Book section", "Conference paper", + "Data management plan", "Journal article", "Patent", "Preprint", + "Project deliverable", "Project milestone", "Proposal", "Report", + "Software documentation", "Taxonomic treatment", "Technical note", + "Thesis", "Working paper", "Other"] + + # Variable to keep track of the option + # selected in OptionMenu + value_inside = tk.StringVar(root) + + # Set the default value of the variable + value_inside.set("Select an Option") + + # Create the optionmenu + question_menu = tk.OptionMenu(root, value_inside, *options_list) + question_menu.pack() + + # Function to store and print the submitted option + def pick_pub_type(): + done = colored('Done', 'red') + global pub_type + pub_type = value_inside.get() + print(f"You selected: {pub_type}. Click {done} or change your selection.") + return + + # Buttons to print and submit the option and close the window + submit_button = tk.Button(root, text='Submit', bg="#B0E0E6", command=pick_pub_type) + submit_button.pack(padx=15, pady=35) + + button_done = tk.Button(root, text = "Done", bg="#FF6347", command=root.destroy) + button_done.pack() + + # Generate loop + root.mainloop() + + return pub_type diff --git a/zenodo_assitant/zenodo_tools/zenodo_put.py b/zenodo_assitant/zenodo_tools/zenodo_put.py new file mode 100644 index 0000000000000000000000000000000000000000..6582c30d5584e0723f6dafe3a0a69ef99077086c --- /dev/null +++ b/zenodo_assitant/zenodo_tools/zenodo_put.py @@ -0,0 +1,72 @@ +def upload_to_zenodo(path, filename, data): + + # Tools + import time + import requests + import json + + # Ask for token + ACCESS_TOKEN = input(str("Please, paste your token: ")) + input("Press Enter to start the uploading process. Note this can take some time.") + print("Requesting access to your acount...") + + # Access the API + params = {'access_token': ACCESS_TOKEN} + r_0 = requests.get('https://zenodo.org/api/deposit/depositions', params=params) + r0_status = r_0.status_code + + # In case of errors + while r0_status not in (200, 201, 202, 204): + if r0_status in (400, 401, 403): + error_message = f"""{r0_status}: Request failed. The access to your account was forbidden. + The reason for this error is a missing or invalid token. + Check your token or generate a new one from: + https://zenodo.org/account/settings/applications/tokens/new/ + """ + print(error_message) + input("When you are ready, press Enter.") + ACCESS_TOKEN = input(str("Please, paste your token: ")) + input("Press Enter to start the uploading process. Note this can take some time.") + print("Requesting access to your acount...") + + # Access the API + params = {'access_token': ACCESS_TOKEN} + r_0 = requests.get('https://zenodo.org/api/deposit/depositions', params=params) + r0_status = r_0.status_code + else: + input("We are sorry to inform that there is troubling accesing " + "to the Zenodo servers right now. We will have to take you " + "back to the main menu. Please, press enter.") + return + + # Acces: Success + if r0_status in (200, 201, 202, 204): + print(f"{r0_status}: Request succeeded. The access to your account was granted. Please wait...\n") + + # Create empty upload + headers = {"Content-Type": "application/json"} + + r_1 = requests.post('https://zenodo.org/api/deposit/depositions', params=params, json={}, headers=headers) + r1_status = r_1.status_code + + print(f"{r1_status}: Request succeeded. An empty upload was created. Please wait...\n") + + bucket_url = r_1.json()["links"]["bucket"] + deposition_id = r_1.json()['id'] + + # Put + with open(path, "rb") as fp: + r_2 = requests.put("%s/%s" % (bucket_url, filename), data=fp, params=params) + r2_status = r_2.status_code + + print(f"{r2_status}: Request succeeded. Access granted. Your file was uploaded...\n") + + + # Post + r_3 = requests.put('https://zenodo.org/api/deposit/depositions/%s' % deposition_id, + params=params, data=json.dumps(data), headers=headers) + r3_status = r_3.status_code + + print(f"{r3_status}: Request succeeded. Access granted. The metadata was updated. \n") + + return diff --git a/zenodo_assitant/zenodo_tools/zenodo_search.py b/zenodo_assitant/zenodo_tools/zenodo_search.py new file mode 100644 index 0000000000000000000000000000000000000000..68dc3049b60861265127fa59246ffed8d1c69628 --- /dev/null +++ b/zenodo_assitant/zenodo_tools/zenodo_search.py @@ -0,0 +1,39 @@ +def filename_input(): + + # Tools + import os + import tkinter as tk + from tkinter import filedialog + from termcolor import colored, cprint + + # Function to open File Browser + def upload_file(): + done = colored('Done', 'red') + global path + global filename + path = filedialog.askopenfilename() + filename = os.path.basename(path) + print(f"You selected: \n" + f"File: {filename}\n" + f"Path: {path}\n" + f"\nClick {done} or change your selection.\n") + return + + # Create window + root = tk.Tk() + root.title("File browser") + root.geometry("250x60") + root.config(background = "#F5F5F5") + root.eval('tk::PlaceWindow . center') + + # Buttons to open the File Browser and end loop + button_explore = tk.Button(root, text="Explore", bg="#B0E0E6", command=upload_file) + button_done = tk.Button(root, text = "Done", bg="#FF6347", command=root.destroy) + + button_explore.pack(side="top") + button_done.pack(side="top") + + # Generate loop + root.mainloop() + + return path, filename diff --git a/zenodo_assitant/zenodo_tools/zenodo_upload.py b/zenodo_assitant/zenodo_tools/zenodo_upload.py new file mode 100644 index 0000000000000000000000000000000000000000..8b42af3b492f42365d621c83cd8aaed31d2d6dfa --- /dev/null +++ b/zenodo_assitant/zenodo_tools/zenodo_upload.py @@ -0,0 +1,47 @@ +def upload_options(): + + # Tools + import tkinter as tk + from termcolor import colored, cprint + + # Create window + root = tk.Tk() + root.title("Upload options") + root.geometry('250x200') + root.config(background = "#F5F5F5") + root.eval('tk::PlaceWindow . center') + + # Create the list of upload options + options_list = ["Publication", "Poster", "Presentation", "Dataset", "Image", + "Video", "Audio", "Software", "Lesson", "Physical object", "Other"] + + # Variable to keep track of the option + # selected in OptionMenu + value_inside = tk.StringVar(root) + + # Set the default value of the variable + value_inside.set("Select an Option") + + # Create the optionmenu from list + question_menu = tk.OptionMenu(root, value_inside, *options_list) + question_menu.pack() + + # Function to store and print the submitted option + def pick_upload_type(): + done = colored('Done', 'red') + global upload_type + upload_type = value_inside.get() + print(f"You selected: {upload_type}. Click {done} or change your selection.") + return + + # Buttons to print and submit the option and to destroy loop + submit_button = tk.Button(root, text='Submit', bg="#B0E0E6", command=pick_upload_type) + submit_button.pack(padx=15, pady=35) + + button_done = tk.Button(root, text = "Done", bg="#FF6347", command=root.destroy) + button_done.pack() + + # Generate loop + root.mainloop() + + return upload_type diff --git a/zenodo_assitant/zenodo_tutorial.py b/zenodo_assitant/zenodo_tutorial.py new file mode 100644 index 0000000000000000000000000000000000000000..67a57d38123f8cc55434a9a290dd61f93b7636b8 --- /dev/null +++ b/zenodo_assitant/zenodo_tutorial.py @@ -0,0 +1,200 @@ +import time +from termcolor import cprint, colored + +# Libraries to run Zenodo code +import requests +import json + +# Library to generate metadata +import pandas as pd + +# Libraries to obtain data +import tkinter as tk + +from zenodo_assistant.zenodo_tools.zenodo_search import filename_input +from zenodo_assistant.zenodo_tools.zenodo_functions import type_title, type_description, creators_dict, author_check +from zenodo_assistant.zenodo_tools.zenodo_date import date_input +from zenodo_assistant.zenodo_tools.zenodo_upload import upload_options +from zenodo_assistant.zenodo_tools.zenodo_images import image_options +from zenodo_assistant.zenodo_tools.zenodo_publication import pub_options +from zenodo_assistant.zenodo_tools.zenodo_metadata import upload_metadata, image_metadata, pub_metadata, generate_md, print_md +from zenodo_assistant.zenodo_tools.zenodo_put import upload_to_zenodo + + +# Colored messages +zenodo = colored('Zenodo', 'cyan') +enter = colored('Enter', 'cyan') +select = colored('Select', 'cyan') +submit = colored('Submit', 'cyan') +explore = colored('Explore', 'cyan') +done = colored('Done', 'red') +copy = colored("COPY", "green", attrs=['reverse']) +paste = colored("PASTE", "green", attrs=['reverse']) + +# Welcome +welcome_message = f""" +Welcome to your {zenodo} assistant.\n +From here, you can upload a file to your {zenodo} account. +""" +print(welcome_message) + +# Submit file +input(f"Press {enter} to open the File Browser to {select} and {submit} the file that you want to upload.\n") + +open_browser = True +while open_browser == True: + try: + path, filename = filename_input() + break + except: + print(f"You did not {submit} any file. Try again: click {explore}, pick your file and then {done}.\n") + try: + path, filename = filename_input() + break + except: + print(f"You did not {submit} any file. Try again: click {explore}, pick your file and then {done}.\n") + open_browser = True + + +input(f"The file has been stored. Press {enter} to continue.") + +# Fill metadata +metadata_message = f""" +To upload a file to your {zenodo} account, you will need to provide some basic +information about the work you will upload to generate the metadata. +Do not worry, you can always change later it in the website.\n +""" +print(metadata_message) + +input(f"Press {enter} to start filling the information.\n") +time.sleep(1) + +# Title +title = type_title() + +# Description +description = type_description() + +# Publication Date +input(f"Press {enter} to open the Calendar to {select} the Publication date.\n") +publication_date = date_input() +input(f"\nThe date has been stored. Press {enter} to continue.\n") + +# Creators +creators_message = """ +Now, you will have to fill the creators information, one by one. +Be careful of the format. +""" +print(creators_message) +input(f"Press {enter} to continue.\n") +creators = creators_dict() + +# Upload type +input(f"Press {enter} to open the options menu to {select} and {submit} the type of file.\n") +open_type = True +while open_type == True: + try: + upload_input = upload_options() + break + except: + print(f"You did not {submit} any option. Try again.\n") + try: + upload_input = upload_options() + break + except: + print(f"You did not {submit} any option. Try again.\n") + open_type = True +upload = upload_metadata(upload_input) +input(f"\nThe upload type has been stored. Press {enter} to continue.\n") + +# Image type +if upload_input == "Image": + input(f"Press {enter} to open the options menu to {select} and {submit} the type of image.\n") + open_image = True + while open_image == True: + try: + image_input = image_options() + break + except: + print(f"You did not {submit} any option. Try again.\n") + try: + image_input = image_options() + except: + print(f"You did not {submit} any option. Try again.\n") + open_image = True + + image = image_metadata(image_input) + publication = "None" + input(f"\nThe image type has been stored. Press {enter} to continue.") + +# Publication type +elif upload_input == "Publication": + input(f"Press {enter} to open the options menu to {select} and {submit} the type of publication.\n") + open_pub = True + while open_pub == True: + try: + pub_input = pub_options() + break + except: + print(f"You did not {submit} any option. Try again.\n") + try: + pub_input = pub_options() + break + except: + print(f"You did not {submit} any option. Try again.\n") + open_pub = True + publication = pub_metadata(pub_input) + image = "None" + input(f"\nThe publication type has been stored. Press {enter} to continue.") + +# In case of different type of upload +else: + publication = "None" + image = "None" + +# Generate metadata and show it to the user +input(f"\nYou have filled all the necessary information. " + f"Press {enter} to generate the metadata.\n") + +data = generate_md(title, description, publication_date, upload, image, publication, creators) +time.sleep(1) +md_message = """ +The metadata has been generated.\n +This is the metadata corresponding to the information you just provided.\n +""" +print(md_message) +df = print_md(data) +print(df) + +input(f"\nPress {enter} to continue.") + +# Upload file to Zenodo +upload_message = f""" +To upload your file, you need an authentication token. If you do not have one already, +you have to create one by logging in to your {zenodo} account and going into this page: + +{colored('https://zenodo.org/account/settings/applications/tokens/new/', 'cyan')} + +You will only need a deposit:write token, but you can select all the scopes. +Remember to {copy} the token so you can {paste} it here. + +When you are ready, press {enter}. + +""" +input(upload_message) +upload_to_zenodo(path, filename, data) + +# End message +success_message= f""" +Your file and its metadata were successfully uploaded to your {zenodo} account. +You can check it out here: + +{colored('https://zenodo.org/deposit', 'cyan')} + +This program does not support the publication of files. By publishing a file in {zenodo}, +it will go straight online and once it is published, you can no longer delete it. +My advice? I would check out my file and its metadata in the {zenodo} website carefully +before publishing. +""" + +print(success_message)