def run(document: papis.document.Document, wait: bool = True, git: bool = False) -> None: database = papis.database.get() info_file_path = document.get_info_file() if not info_file_path: raise Exception(papis.strings.no_folder_attached_to_document) papis.utils.general_open(info_file_path, "editor", wait=wait) document.load() database.update(document) if git: papis.git.add_and_commit_resource( str(document.get_main_folder()), info_file_path, "Update information for '{0}'".format( papis.document.describe(document)))
def run(document: papis.document.Document, wait: bool = True, git: bool = False) -> None: logger = logging.getLogger('run:edit') info_file_path = document.get_info_file() if not info_file_path: raise Exception(papis.strings.no_folder_attached_to_document) _old_dict = papis.document.to_dict(document) papis.utils.general_open(info_file_path, "editor", wait=wait) document.load() _new_dict = papis.document.to_dict(document) # If nothing changed there is nothing else to be done if _old_dict == _new_dict: logger.debug("old and new are equal, doing nothing") return papis.database.get().update(document) papis.hooks.run("on_edit_done") if git: papis.git.add_and_commit_resource( str(document.get_main_folder()), info_file_path, "Update information for '{0}'".format( papis.document.describe(document)))
def main(self): if papis.config.in_mode("contact"): self.init_contact_mode() lib_dir = os.path.expanduser(papis.config.get('dir')) data = dict() # The folder name of the new document that will be created out_folder_name = None # The real paths of the documents to be added in_documents_paths = self.args.document # The basenames of the documents to be added in_documents_names = [] # The folder name of the temporary document to be created temp_dir = tempfile.mkdtemp("-"+self.args.lib) if self.args.from_lib: doc = self.pick( papis.api.get_documents_in_lib(self.get_args().from_lib) ) if doc: self.args.from_folder = doc.get_main_folder() if self.args.from_folder: original_document = papis.document.Document(self.args.from_folder) self.args.from_yaml = original_document.get_info_file() in_documents_paths = original_document.get_files() if self.args.from_url: url_data = papis.downloaders.utils.get(self.args.from_url) data.update(url_data["data"]) in_documents_paths.extend(url_data["documents_paths"]) # If no data was retrieved and doi was found, try to get # information with the document's doi if not data and url_data["doi"] is not None and\ not self.args.from_doi: self.logger.warning( "I could not get any data from %s" % self.args.from_url ) self.args.from_doi = url_data["doi"] if self.args.from_bibtex: bib_data = papis.bibtex.bibtex_to_dict(self.args.from_bibtex) if len(bib_data) > 1: self.logger.warning( 'Your bibtex file contains more than one entry,' ' I will be taking the first entry' ) data.update(bib_data[0]) if self.args.from_pmid: self.logger.debug( "I'll try using PMID %s via HubMed" % self.args.from_pmid ) hubmed_url = "http://pubmed.macropus.org/articles/"\ "?format=text%%2Fbibtex&id=%s" % self.args.from_pmid bibtex_data = papis.downloaders.utils.get_downloader( hubmed_url, "get" ).get_document_data().decode("utf-8") bibtex_data = papis.bibtex.bibtex_to_dict(bibtex_data) if len(bibtex_data): data.update(bibtex_data[0]) if "doi" in data and not self.args.from_doi: self.args.from_doi = data["doi"] else: self.logger.error( "PMID %s not found or invalid" % self.args.from_pmid ) if self.args.from_doi: self.logger.debug("I'll try using doi %s" % self.args.from_doi) data.update(papis.utils.doi_to_data(self.args.from_doi)) if len(self.get_args().document) == 0 and \ papis.config.get('doc-url-key-name') in data.keys(): doc_url = data[papis.config.get('doc-url-key-name')] self.logger.info( 'I am trying to download the document from %s' % doc_url ) down = papis.downloaders.utils.get_downloader( doc_url, 'get' ) file_name = tempfile.mktemp() with open(file_name, 'wb+') as fd: fd.write(down.get_document_data()) self.logger.info('Opening the file') papis.api.open_file(file_name) if papis.utils.confirm('Do you want to use this file?'): self.args.document.append(file_name) if self.args.from_yaml: self.logger.debug("Yaml input file = %s" % self.args.from_yaml) data.update(papis.utils.yaml_to_data(self.args.from_yaml)) if self.args.from_vcf: data.update(papis.utils.vcf_to_data(self.args.from_vcf)) in_documents_names = [ papis.utils.clean_document_name(doc_path) for doc_path in in_documents_paths ] # Decide if we are adding the documents to an already existing document # or it is a new document if self.args.to: self.logger.debug( "Searching for the document where to add the files" ) documents = papis.api.get_documents_in_dir( lib_dir, self.args.to ) document = self.pick(documents) if not document: return 0 document.update( data, interactive=self.args.interactive ) document.save() data = document.to_dict() in_documents_paths = document.get_files() + in_documents_paths data["files"] = [os.path.basename(f) for f in in_documents_paths] # set out folder name the folder of the found document out_folder_name = document.get_main_folder_name() out_folder_path = document.get_main_folder() else: document = papis.document.Document(temp_dir) if not papis.config.in_mode("contact"): if len(in_documents_paths) == 0: if not self.get_args().no_document: self.logger.error("No documents to be added") return 1 else: in_documents_paths = [document.get_info_file()] # We need the names to add them in the file field # in the info file in_documents_names = [papis.utils.get_info_file_name()] # Save document to create the info file document.update( data, force=True, interactive=self.args.interactive ) document.save() data["title"] = self.args.title or self.get_default_title( data, in_documents_paths[0] ) data["author"] = self.args.author or self.get_default_author( data, in_documents_paths[0] ) self.logger.debug("Author = % s" % data["author"]) self.logger.debug("Title = % s" % data["title"]) if not self.args.name: self.logger.debug("Getting an automatic name") out_folder_name = self.get_hash_folder( data, in_documents_paths[0] ) else: temp_doc = papis.document.Document(data=data) out_folder_name = papis.utils.format_doc( self.args.name, temp_doc ) out_folder_name = papis.utils.clean_document_name( out_folder_name ) del temp_doc if len(out_folder_name) == 0: self.logger.error('The output folder name is empty') return 1 data["files"] = in_documents_names out_folder_path = os.path.join( lib_dir, self.args.dir, out_folder_name ) self.logger.debug("Folder name = % s" % out_folder_name) self.logger.debug("Folder path = % s" % out_folder_path) self.logger.debug("File(s) = % s" % in_documents_paths) # Create folders if they do not exists. if not os.path.isdir(temp_dir): self.logger.debug("Creating directory '%s'" % temp_dir) os.makedirs(temp_dir, mode=papis.config.getint('dir-umask')) # Check if the user wants to edit before submitting the doc # to the library if self.args.edit: document.update( data, force=True, interactive=self.args.interactive ) document.save() self.logger.debug("Editing file before adding it") papis.api.edit_file(document.get_info_file()) self.logger.debug("Loading the changes made by editing") document.load() data = document.to_dict() # First prepare everything in the temporary directory for i in range(min(len(in_documents_paths), len(data["files"]))): in_doc_name = data["files"][i] in_file_path = in_documents_paths[i] assert(os.path.exists(in_file_path)) endDocumentPath = os.path.join( document.get_main_folder(), in_doc_name ) if os.path.exists(endDocumentPath): self.logger.debug( "%s already exists, ignoring..." % endDocumentPath ) continue if not self.args.no_document: self.logger.debug( "[CP] '%s' to '%s'" % (in_file_path, endDocumentPath) ) shutil.copy(in_file_path, endDocumentPath) # Duplication checking self.logger.debug("Check if the added document is already existing") found_document = papis.utils.locate_document( document, papis.api.get_documents_in_lib(papis.api.get_lib()) ) if found_document is not None: self.logger.warning("DUPLICATION WARNING") self.logger.warning( "This document seems to be already in your libray: \n\n" + found_document.dump() ) self.logger.warning( "Use the update command if you just want to update the info." ) self.args.confirm = True document.update(data, force=True) if self.get_args().open: for d_path in in_documents_paths: papis.api.open_file(d_path) if self.args.confirm: if not papis.utils.confirm('Really add?'): return 0 document.save() if self.args.to: return 0 self.logger.debug( "[MV] '%s' to '%s'" % (document.get_main_folder(), out_folder_path) ) shutil.move(document.get_main_folder(), out_folder_path) # Let us chmod it because it might come from a temp folder # and temp folders are per default 0o600 os.chmod(out_folder_path, papis.config.getint('dir-umask')) papis.api.clear_lib_cache() if self.args.commit and papis.utils.lib_is_git_repo(self.args.lib): subprocess.call(["git", "-C", out_folder_path, "add", "."]) subprocess.call( ["git", "-C", out_folder_path, "commit", "-m", "Add document"] )
def run(paths, data=dict(), name=None, file_name=None, subfolder=None, interactive=False, from_bibtex=None, from_yaml=None, from_folder=None, from_url=None, from_doi=None, from_pmid=None, confirm=False, open_file=False, edit=False, commit=False, no_document=False): """ :param paths: Paths to the documents to be added :type paths: [] :param data: Data for the document to be added. If more data is to be retrieved from other sources, the data dictionary will be updated from these sources. :type data: dict :param name: Name of the folder where the document will be stored :type name: str :param file_name: File name of the document's files to be stored. :type file_name: str :param subfolder: Folder within the library where the document's folder should be stored. :type subfolder: str :param interactive: Wether or not interactive functionality of this command should be activated. :type interactive: bool :param from_bibtex: Filepath where to find a file containing bibtex info. :type from_bibtex: str :param from_yaml: Filepath where to find a file containing yaml info. :type from_yaml: str :param from_folder: Filepath where to find a papis document (folder + info file) to be added to the library. :type from_folder: str :param from_url: Url to try to download information and files from. :type from_url: str :param from_url: doi number to try to download information from. :type from_url: str :param from_url: pmid number to try to download information from. :type from_url: str :param confirm: Wether or not to ask user for confirmation before adding. :type confirm: bool :param open_file: Wether or not to ask user for opening file before adding. :type open_file: bool :param edit: Wether or not to ask user for editing the infor file before adding. :type edit: bool :param commit: Wether or not to ask user for committing before adding, in the case of course that the library is a git repository. :type commit: bool :param no_document: Wether or not the document has no files attached. :type no_document: bool """ logger = logging.getLogger('add:run') # The folder name of the new document that will be created out_folder_name = None # The real paths of the documents to be added in_documents_paths = paths # The basenames of the documents to be added in_documents_names = [] # The folder name of the temporary document to be created temp_dir = tempfile.mkdtemp() if from_folder: original_document = papis.document.Document(from_folder) from_yaml = original_document.get_info_file() in_documents_paths = original_document.get_files() if from_url: url_data = papis.downloaders.utils.get(from_url) data.update(url_data["data"]) in_documents_paths.extend(url_data["documents_paths"]) # If no data was retrieved and doi was found, try to get # information with the document's doi if not data and url_data["doi"] is not None and\ not from_doi: logger.warning("I could not get any data from %s" % from_url) from_doi = url_data["doi"] if from_bibtex: bib_data = papis.bibtex.bibtex_to_dict(from_bibtex) if len(bib_data) > 1: logger.warning('Your bibtex file contains more than one entry,' ' I will be taking the first entry') data.update(bib_data[0]) if from_pmid: logger.debug("I'll try using PMID %s via HubMed" % from_pmid) hubmed_url = "http://pubmed.macropus.org/articles/"\ "?format=text%%2Fbibtex&id=%s" % from_pmid bibtex_data = papis.downloaders.utils.get_downloader( hubmed_url, "get").get_document_data().decode("utf-8") bibtex_data = papis.bibtex.bibtex_to_dict(bibtex_data) if len(bibtex_data): data.update(bibtex_data[0]) if "doi" in data and not from_doi: from_doi = data["doi"] else: logger.error("PMID %s not found or invalid" % from_pmid) if from_doi: logger.debug("I'll try using doi %s" % from_doi) data.update(papis.utils.doi_to_data(from_doi)) if len(paths) == 0 and \ papis.config.get('doc-url-key-name') in data.keys(): doc_url = data[papis.config.get('doc-url-key-name')] logger.info('I am trying to download the document from %s' % doc_url) down = papis.downloaders.utils.get_downloader(doc_url, 'get') file_name = tempfile.mktemp() with open(file_name, 'wb+') as fd: fd.write(down.get_document_data()) logger.info('Opening the file') papis.api.open_file(file_name) if papis.utils.confirm('Do you want to use this file?'): paths.append(file_name) if from_yaml: logger.debug("Yaml input file = %s" % from_yaml) data.update(papis.utils.yaml_to_data(from_yaml)) for p in in_documents_paths: if not os.path.exists(p): raise IOError('Document %s not found' % p) in_documents_names = [ papis.utils.clean_document_name(doc_path) for doc_path in in_documents_paths ] document = papis.document.Document(temp_dir) if len(in_documents_paths) == 0: if not no_document: logger.error("No documents to be added") return status.file_not_found else: in_documents_paths = [document.get_info_file()] # We need the names to add them in the file field # in the info file in_documents_names = [papis.utils.get_info_file_name()] # Save document to create the info file document.update(data, force=True, interactive=interactive) document.save() if not name: logger.debug("Getting an automatic name") if not os.path.isfile(in_documents_paths[0]): return status.file_not_found out_folder_name = get_hash_folder(data, in_documents_paths[0]) else: temp_doc = papis.document.Document(data=data) out_folder_name = papis.utils.format_doc(name, temp_doc) out_folder_name = papis.utils.clean_document_name(out_folder_name) del temp_doc if len(out_folder_name) == 0: logger.error('The output folder name is empty') return status.file_not_found data["files"] = in_documents_names out_folder_path = os.path.expanduser( os.path.join(papis.config.get('dir'), subfolder or '', out_folder_name)) logger.debug("Folder name = % s" % out_folder_name) logger.debug("Folder path = % s" % out_folder_path) logger.debug("File(s) = % s" % in_documents_paths) # First prepare everything in the temporary directory g = papis.utils.create_identifier(ascii_lowercase) string_append = '' if file_name is not None: # Use args if set papis.config.set("file-name", file_name) new_file_list = [] for i in range(min(len(in_documents_paths), len(data["files"]))): in_file_path = in_documents_paths[i] if not os.path.exists(in_file_path): return status.file_not_found # Rename the file in the staging area new_filename = papis.utils.clean_document_name( get_file_name(data, in_file_path, suffix=string_append)) new_file_list.append(new_filename) endDocumentPath = os.path.join(document.get_main_folder(), new_filename) string_append = next(g) # Check if the absolute file path is > 255 characters if len(os.path.abspath(endDocumentPath)) >= 255: logger.warning('Length of absolute path is > 255 characters. ' 'This may cause some issues with some pdf viewers') if os.path.exists(endDocumentPath): logger.debug("%s already exists, ignoring..." % endDocumentPath) continue if not no_document: logger.debug("[CP] '%s' to '%s'" % (in_file_path, endDocumentPath)) shutil.copy(in_file_path, endDocumentPath) data['files'] = new_file_list # Check if the user wants to edit before submitting the doc # to the library if edit: document.update(data, force=True, interactive=interactive) document.save() logger.debug("Editing file before adding it") papis.api.edit_file(document.get_info_file(), wait=True) logger.debug("Loading the changes made by editing") document.load() data = papis.document.to_dict(document) # Duplication checking logger.debug("Check if the added document is already existing") found_document = papis.utils.locate_document( document, papis.api.get_documents_in_lib(papis.api.get_lib())) if found_document is not None: logger.warning('\n' + papis.document.dump(found_document)) print("\n\n") logger.warning("DUPLICATION WARNING") logger.warning( "The document above seems to be already in your library: \n\n") logger.warning( "(Hint) Use the update command if you just want to update" " the info.") confirm = True document.update(data, force=True) if open_file: for d_path in in_documents_paths: papis.api.open_file(d_path) if confirm: if not papis.utils.confirm('Really add?'): return status.success document.save() logger.debug("[MV] '%s' to '%s'" % (document.get_main_folder(), out_folder_path)) papis.document.move(document, out_folder_path) papis.database.get().add(document) if commit and papis.utils.lib_is_git_repo(papis.config.get_lib()): subprocess.call(["git", "-C", out_folder_path, "add", "."]) subprocess.call( ["git", "-C", out_folder_path, "commit", "-m", "Add document"]) return status.success