def update(self): """ Calls git pull origin <branch> in order to update SiCKRAGE. Returns a bool depending on the call's success. """ if sickrage.app.config.git_reset: self.reset() if not self.upgrade_pip(): return False if not self.install_requirements(self.current_branch): return False __, __, exit_status = self._git_cmd( self._git_path, 'pull -f {} {}'.format(sickrage.app.config.git_remote, self.current_branch)) if exit_status == 0: sickrage.app.log.info("Updating SiCKRAGE from GIT servers") sickrage.app.alerts.message( _('Updater'), _('Updating SiCKRAGE from GIT servers')) Notifiers.mass_notify_version_update(self.get_newest_version) return True return False
def download_subtitles(self): if self.location == '': return if not os.path.isfile(self.location): sickrage.app.log.debug("%s: Episode file doesn't exist, can't download subtitles for S%02dE%02d" % (self.show.indexer_id, self.season or 0, self.episode or 0)) return sickrage.app.log.debug("%s: Downloading subtitles for S%02dE%02d" % (self.show.indexer_id, self.season or 0, self.episode or 0)) subtitles, newSubtitles = Subtitles().download_subtitles(self.showid, self.season, self.episode) self.subtitles = ','.join(subtitles) self.subtitles_searchcount += 1 if self.subtitles_searchcount else 1 self.subtitles_lastsearch = datetime.datetime.now().toordinal() if newSubtitles: subtitle_list = ", ".join([Subtitles().name_from_code(newSub) for newSub in newSubtitles]) sickrage.app.log.debug("%s: Downloaded %s subtitles for S%02dE%02d" % (self.show.indexer_id, subtitle_list, self.season or 0, self.episode or 0)) Notifiers.mass_notify_subtitle_download(self.pretty_name(), subtitle_list) else: sickrage.app.log.debug("%s: No subtitles downloaded for S%02dE%02d" % (self.show.indexer_id, self.season or 0, self.episode or 0)) return newSubtitles
def update(self): """ Calls git pull origin <branch> in order to update SiCKRAGE. Returns a bool depending on the call's success. """ if not self.install_requirements(self.current_branch): return False # remove untracked files and performs a hard reset on git branch to avoid update issues if sickrage.app.config.git_reset: # self.clean() # This is removing user data and backups self.reset() __, __, exit_status = self._git_cmd( self._git_path, 'pull -f {} {}'.format(sickrage.app.config.git_remote, self.current_branch)) if exit_status == 0: sickrage.app.log.info("Updating SiCKRAGE from GIT servers") sickrage.app.alerts.message( _('Updater'), _('Updating SiCKRAGE from GIT servers')) Notifiers.mass_notify_version_update(self.get_newest_version) return True return False
def update(self): """ Downloads the latest source tarball from server and installs it over the existing version. """ tar_download_url = 'https://git.sickrage.ca/SiCKRAGE/sickrage/repository/archive.tar.gz?ref={}'.format(('master', 'develop')['dev' in self.version]) try: if not self.install_requirements(self.current_branch): return False with tempfile.TemporaryFile() as update_tarfile: sickrage.app.log.info("Downloading update from " + repr(tar_download_url)) update_tarfile.write(WebSession().get(tar_download_url).content) update_tarfile.seek(0) with tempfile.TemporaryDirectory(prefix='sr_update_', dir=sickrage.app.data_dir) as unpack_dir: sickrage.app.log.info("Extracting SiCKRAGE update file") try: tar = tarfile.open(fileobj=update_tarfile, mode='r:gz') tar.extractall(unpack_dir) tar.close() except tarfile.ReadError: sickrage.app.log.warning("Invalid update data, update failed: not a gzip file") return False # find update dir name update_dir_contents = [x for x in os.listdir(unpack_dir) if os.path.isdir(os.path.join(unpack_dir, x))] if len(update_dir_contents) != 1: sickrage.app.log.warning("Invalid update data, update failed: " + str(update_dir_contents)) return False # walk temp folder and move files to main folder content_dir = os.path.join(unpack_dir, update_dir_contents[0]) sickrage.app.log.info("Moving files from " + content_dir + " to " + sickrage.MAIN_DIR) for dirname, __, filenames in os.walk(content_dir): dirname = dirname[len(content_dir) + 1:] for curfile in filenames: old_path = os.path.join(content_dir, dirname, curfile) new_path = os.path.join(sickrage.MAIN_DIR, dirname, curfile) if os.path.isfile(new_path) and os.path.exists(new_path): os.remove(new_path) try: shutil.move(old_path, new_path) except IOError: os.makedirs(os.path.dirname(new_path)) shutil.move(old_path, new_path) except Exception as e: sickrage.app.log.error("Error while trying to update: {}".format(e)) return False # Notify update successful Notifiers.mass_notify_version_update(self.get_newest_version) return True
def update(self): """ Performs pip upgrade """ __, __, exit_status = self._pip_cmd(self._pip_path, 'install -U --no-cache-dir sickrage') if exit_status == 0: sickrage.app.log.info("Updating SiCKRAGE from PyPi servers") Notifiers.notify_version_update(self.get_newest_version) return True return False
def update(self): """ Performs pip upgrade """ __, __, exit_status = self._pip_cmd(self._pip3_path, 'install -U --no-cache-dir sickrage') if exit_status == 0: sickrage.app.log.info("Updating SiCKRAGE from PyPi servers") sickrage.app.alerts.message(_('Updater'), _('Updating SiCKRAGE from PyPi servers')) Notifiers.mass_notify_version_update(self.get_newest_version) return True return False
def update(self): """ Calls git pull origin <branch> in order to update SiCKRAGE. Returns a bool depending on the call's success. """ # remove untracked files and performs a hard reset on git branch to avoid update issues if sickrage.app.config.git_reset: # self.clean() # This is removing user data and backups self.reset() __, __, exit_status = self._git_cmd(self._git_path, 'pull -f {} {}'.format(sickrage.app.config.git_remote, self.current_branch)) if exit_status == 0: sickrage.app.log.info("Updating SiCKRAGE from GIT servers") Notifiers.notify_version_update(self.get_newest_version) self.install_requirements() return True return False
def snatchEpisode(result, endStatus=SNATCHED): """ Contains the internal logic necessary to actually "snatch" a result that has been found. :param result: SearchResult instance to be snatched. :param endStatus: the episode status that should be used for the episode object once it's snatched. :return: boolean, True on success """ if result is None: return False result.priority = 0 # -1 = low, 0 = normal, 1 = high if sickrage.app.config.allow_high_priority: # if it aired recently make it high priority for curEp in result.episodes: if date.today() - curEp.airdate <= timedelta(days=7): result.priority = 1 if re.search(r'(^|[. _-])(proper|repack)([. _-]|$)', result.name, re.I) is not None: endStatus = SNATCHED_PROPER # get result content result.content = result.provider.get_content(result.url) dlResult = False if result.resultType in ("nzb", "nzbdata"): if sickrage.app.config.nzb_method == "blackhole": dlResult = result.provider.download_result(result) elif sickrage.app.config.nzb_method == "sabnzbd": dlResult = SabNZBd.sendNZB(result) elif sickrage.app.config.nzb_method == "nzbget": is_proper = True if endStatus == SNATCHED_PROPER else False dlResult = NZBGet.sendNZB(result, is_proper) else: sickrage.app.log.error("Unknown NZB action specified in config: " + sickrage.app.config.nzb_method) elif result.resultType in ("torrent", "torznab"): # add public trackers to torrent result if not result.provider.private: result = result.provider.add_trackers(result) if sickrage.app.config.torrent_method == "blackhole": dlResult = result.provider.download_result(result) else: if any([result.content, result.url.startswith('magnet:')]): client = getClientIstance(sickrage.app.config.torrent_method)() dlResult = client.send_torrent(result) else: sickrage.app.log.warning("Torrent file content is empty") else: sickrage.app.log.error( "Unknown result type, unable to download it (%r)" % result.resultType) # no download results found if not dlResult: return False FailedHistory.logSnatch(result) sickrage.app.alerts.message(_('Episode snatched'), result.name) History.logSnatch(result) # don't notify when we re-download an episode trakt_data = [] for curEpObj in result.episodes: with curEpObj.lock: if isFirstBestMatch(result): curEpObj.status = Quality.compositeStatus( SNATCHED_BEST, result.quality) else: curEpObj.status = Quality.compositeStatus( endStatus, result.quality) # save episode to DB curEpObj.save_to_db() if curEpObj.status not in Quality.DOWNLOADED: try: Notifiers.mass_notify_snatch( curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN') + " from " + result.provider.name) except: sickrage.app.log.debug("Failed to send snatch notification") trakt_data.append((curEpObj.season, curEpObj.episode)) data = sickrage.app.notifier_providers[ 'trakt'].trakt_episode_data_generate(trakt_data) if sickrage.app.config.use_trakt and sickrage.app.config.trakt_sync_watchlist: sickrage.app.log.debug("Add episodes, showid: indexerid " + str(result.show.indexerid) + ", Title " + str(result.show.name) + " to Traktv Watchlist") if data: sickrage.app.notifier_providers['trakt'].update_watchlist( result.show, data_episode=data, update="add") return True
def update(self): """ Downloads the latest source tarball from server and installs it over the existing version. """ tar_download_url = 'https://git.sickrage.ca/SiCKRAGE/sickrage/repository/archive.tar?ref=master' try: # prepare the update dir sr_update_dir = os.path.join(sickrage.app.data_dir, 'sr-update') if os.path.isdir(sr_update_dir): sickrage.app.log.info("Clearing out update folder " + sr_update_dir + " before extracting") shutil.rmtree(sr_update_dir) sickrage.app.log.info("Creating update folder " + sr_update_dir + " before extracting") try: os.makedirs(sr_update_dir) except OSError as e: sickrage.app.log.warning("Unable to create update folder " + sr_update_dir + ': ' + str(e)) return False # retrieve file sickrage.app.log.info("Downloading update from " + repr(tar_download_url)) tar_download_path = os.path.join(sr_update_dir, 'sr-update.tar') WebSession().download(tar_download_url, tar_download_path) if not os.path.isfile(tar_download_path): sickrage.app.log.warning( "Unable to retrieve new version from " + tar_download_url + ", can't update") return False if not tarfile.is_tarfile(tar_download_path): sickrage.app.log.warning("Retrieved version from " + tar_download_url + " is corrupt, can't update") return False # extract to sr-update dir sickrage.app.log.info("Extracting file " + tar_download_path) tar = tarfile.open(tar_download_path) tar.extractall(sr_update_dir) tar.close() # delete .tar.gz sickrage.app.log.info("Deleting file " + tar_download_path) os.remove(tar_download_path) # find update dir name update_dir_contents = [ x for x in os.listdir(sr_update_dir) if os.path.isdir(os.path.join(sr_update_dir, x)) ] if len(update_dir_contents) != 1: sickrage.app.log.warning( "Invalid update data, update failed: " + str(update_dir_contents)) return False # walk temp folder and move files to main folder content_dir = os.path.join(sr_update_dir, update_dir_contents[0]) sickrage.app.log.info("Moving files from " + content_dir + " to " + sickrage.MAIN_DIR) for dirname, __, filenames in os.walk(content_dir): dirname = dirname[len(content_dir) + 1:] for curfile in filenames: old_path = os.path.join(content_dir, dirname, curfile) new_path = os.path.join(sickrage.MAIN_DIR, dirname, curfile) if os.path.isfile(new_path): os.remove(new_path) os.renames(old_path, new_path) # install requirements if not self.install_requirements(): return False except Exception as e: sickrage.app.log.error( "Error while trying to update: {}".format(e)) return False # Notify update successful Notifiers.mass_notify_version_update(self.get_newest_version) return True
def update(self): """ Downloads the latest source tarball from server and installs it over the existing version. """ tar_download_url = 'https://git.sickrage.ca/SiCKRAGE/sickrage/repository/archive.tar.gz?ref={}'.format( ('master', 'develop')['dev' in self.version]) try: if not self.upgrade_pip(): return False if not self.install_requirements(self.current_branch): return False with tempfile.TemporaryFile() as update_tarfile: sickrage.app.log.info("Downloading update from " + repr(tar_download_url)) resp = WebSession().get(tar_download_url) if not resp or not resp.content: sickrage.app.log.warning( 'Failed to download SiCKRAGE update') return False update_tarfile.write(resp.content) update_tarfile.seek(0) with tempfile.TemporaryDirectory( prefix='sr_update_', dir=sickrage.app.data_dir) as unpack_dir: sickrage.app.log.info("Extracting SiCKRAGE update file") try: tar = tarfile.open(fileobj=update_tarfile, mode='r:gz') tar.extractall(unpack_dir) tar.close() except tarfile.TarError: sickrage.app.log.warning( "Invalid update data, update failed: not a gzip file" ) return False if len(os.listdir(unpack_dir)) != 1: sickrage.app.log.warning( "Invalid update data, update failed") return False update_dir = os.path.join( *[unpack_dir, os.listdir(unpack_dir)[0], 'sickrage']) sickrage.app.log.info("Sync folder {} to {}".format( update_dir, sickrage.PROG_DIR)) dirsync.sync(update_dir, sickrage.PROG_DIR, 'sync', purge=True) except Exception as e: sickrage.app.log.error( "Error while trying to update: {}".format(e)) return False # Notify update successful Notifiers.mass_notify_version_update(self.get_newest_version) return True
def update(self): """ Downloads the latest source tarball from server and installs it over the existing version. """ tar_download_url = 'https://git.sickrage.ca/SiCKRAGE/sickrage/repository/archive.tar?ref=master' try: # prepare the update dir sr_update_dir = os.path.join(sickrage.PROG_DIR, 'sr-update') if os.path.isdir(sr_update_dir): sickrage.app.log.info("Clearing out update folder " + sr_update_dir + " before extracting") shutil.rmtree(sr_update_dir) sickrage.app.log.info("Creating update folder " + sr_update_dir + " before extracting") os.makedirs(sr_update_dir) # retrieve file sickrage.app.log.info("Downloading update from " + repr(tar_download_url)) tar_download_path = os.path.join(sr_update_dir, 'sr-update.tar') sickrage.app.wsession.download(tar_download_url, tar_download_path) if not os.path.isfile(tar_download_path): sickrage.app.log.warning( "Unable to retrieve new version from " + tar_download_url + ", can't update") return False if not tarfile.is_tarfile(tar_download_path): sickrage.app.log.error( "Retrieved version from " + tar_download_url + " is corrupt, can't update") return False # extract to sr-update dir sickrage.app.log.info("Extracting file " + tar_download_path) tar = tarfile.open(tar_download_path) tar.extractall(sr_update_dir) tar.close() # delete .tar.gz sickrage.app.log.info("Deleting file " + tar_download_path) os.remove(tar_download_path) # find update dir name update_dir_contents = [x for x in os.listdir(sr_update_dir) if os.path.isdir(os.path.join(sr_update_dir, x))] if len(update_dir_contents) != 1: sickrage.app.log.error("Invalid update data, update failed: " + str(update_dir_contents)) return False content_dir = os.path.join(sr_update_dir, update_dir_contents[0]) # walk temp folder and move files to main folder sickrage.app.log.info("Moving files from " + content_dir + " to " + sickrage.PROG_DIR) for dirname, __, filenames in os.walk(content_dir): dirname = dirname[len(content_dir) + 1:] for curfile in filenames: old_path = os.path.join(content_dir, dirname, curfile) new_path = os.path.join(sickrage.PROG_DIR, dirname, curfile) # Avoid DLL access problem on WIN32/64 # These files needing to be updated manually # or find a way to kill the access from memory if curfile in ('unrar.dll', 'unrar64.dll'): try: os.chmod(new_path, stat.S_IWRITE) os.remove(new_path) os.renames(old_path, new_path) except Exception as e: sickrage.app.log.debug("Unable to update " + new_path + ': ' + e.message) os.remove(old_path) # Trash the updated file without moving in new path continue if os.path.isfile(new_path): os.remove(new_path) os.renames(old_path, new_path) except Exception as e: sickrage.app.log.error("Error while trying to update: {}".format(e.message)) sickrage.app.log.debug("Traceback: " + traceback.format_exc()) return False # Notify update successful Notifiers.notify_version_update(self.get_newest_version) # install requirements self.install_requirements() return True
def update(self): """ Downloads the latest source tarball from server and installs it over the existing version. """ tar_download_url = 'https://git.sickrage.ca/SiCKRAGE/sickrage/repository/archive.tar?ref=master' try: # prepare the update dir sr_update_dir = os.path.join(sickrage.PROG_DIR, 'sr-update') if os.path.isdir(sr_update_dir): sickrage.app.log.info("Clearing out update folder " + sr_update_dir + " before extracting") shutil.rmtree(sr_update_dir) sickrage.app.log.info("Creating update folder " + sr_update_dir + " before extracting") os.makedirs(sr_update_dir) # retrieve file sickrage.app.log.info("Downloading update from " + repr(tar_download_url)) tar_download_path = os.path.join(sr_update_dir, 'sr-update.tar') sickrage.app.wsession.download(tar_download_url, tar_download_path) if not os.path.isfile(tar_download_path): sickrage.app.log.warning( "Unable to retrieve new version from " + tar_download_url + ", can't update") return False if not tarfile.is_tarfile(tar_download_path): sickrage.app.log.error("Retrieved version from " + tar_download_url + " is corrupt, can't update") return False # extract to sr-update dir sickrage.app.log.info("Extracting file " + tar_download_path) tar = tarfile.open(tar_download_path) tar.extractall(sr_update_dir) tar.close() # delete .tar.gz sickrage.app.log.info("Deleting file " + tar_download_path) os.remove(tar_download_path) # find update dir name update_dir_contents = [ x for x in os.listdir(sr_update_dir) if os.path.isdir(os.path.join(sr_update_dir, x)) ] if len(update_dir_contents) != 1: sickrage.app.log.error("Invalid update data, update failed: " + str(update_dir_contents)) return False content_dir = os.path.join(sr_update_dir, update_dir_contents[0]) # walk temp folder and move files to main folder sickrage.app.log.info("Moving files from " + content_dir + " to " + sickrage.PROG_DIR) for dirname, __, filenames in os.walk(content_dir): dirname = dirname[len(content_dir) + 1:] for curfile in filenames: old_path = os.path.join(content_dir, dirname, curfile) new_path = os.path.join(sickrage.PROG_DIR, dirname, curfile) # Avoid DLL access problem on WIN32/64 # These files needing to be updated manually # or find a way to kill the access from memory if curfile in ('unrar.dll', 'unrar64.dll'): try: os.chmod(new_path, stat.S_IWRITE) os.remove(new_path) os.renames(old_path, new_path) except Exception as e: sickrage.app.log.debug("Unable to update " + new_path + ': ' + e.message) os.remove( old_path ) # Trash the updated file without moving in new path continue if os.path.isfile(new_path): os.remove(new_path) os.renames(old_path, new_path) except Exception as e: sickrage.app.log.error("Error while trying to update: {}".format( e.message)) sickrage.app.log.debug("Traceback: " + traceback.format_exc()) return False # Notify update successful Notifiers.notify_version_update(self.get_newest_version) # install requirements self.install_requirements() return True
def snatchEpisode(result, endStatus=SNATCHED): """ Contains the internal logic necessary to actually "snatch" a result that has been found. :param result: SearchResult instance to be snatched. :param endStatus: the episode status that should be used for the episode object once it's snatched. :return: boolean, True on success """ if result is None: return False result.priority = 0 # -1 = low, 0 = normal, 1 = high if sickrage.app.config.allow_high_priority: # if it aired recently make it high priority for curEp in result.episodes: if date.today() - curEp.airdate <= timedelta(days=7): result.priority = 1 if re.search(r'(^|[. _-])(proper|repack)([. _-]|$)', result.name, re.I) is not None: endStatus = SNATCHED_PROPER # get result content result.content = result.provider.get_content(result.url) dlResult = False if result.resultType in ("nzb", "nzbdata"): if sickrage.app.config.nzb_method == "blackhole": dlResult = result.provider.download_result(result) elif sickrage.app.config.nzb_method == "sabnzbd": dlResult = SabNZBd.sendNZB(result) elif sickrage.app.config.nzb_method == "nzbget": is_proper = True if endStatus == SNATCHED_PROPER else False dlResult = NZBGet.sendNZB(result, is_proper) else: sickrage.app.log.error("Unknown NZB action specified in config: " + sickrage.app.config.nzb_method) elif result.resultType in ("torrent", "torznab"): # add public trackers to torrent result if not result.provider.private: result = result.provider.add_trackers(result) if sickrage.app.config.torrent_method == "blackhole": dlResult = result.provider.download_result(result) else: if any([result.content, result.url.startswith('magnet:')]): client = getClientIstance(sickrage.app.config.torrent_method)() dlResult = client.send_torrent(result) else: sickrage.app.log.warning("Torrent file content is empty") else: sickrage.app.log.error("Unknown result type, unable to download it (%r)" % result.resultType) # no download results found if not dlResult: return False FailedHistory.logSnatch(result) sickrage.app.alerts.message(_('Episode snatched'), result.name) History.logSnatch(result) # don't notify when we re-download an episode trakt_data = [] for curEpObj in result.episodes: with curEpObj.lock: if isFirstBestMatch(result): curEpObj.status = Quality.compositeStatus(SNATCHED_BEST, result.quality) else: curEpObj.status = Quality.compositeStatus(endStatus, result.quality) # save episode to DB curEpObj.save_to_db() if curEpObj.status not in Quality.DOWNLOADED: try: Notifiers.mass_notify_snatch( curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN') + " from " + result.provider.name) except: sickrage.app.log.debug("Failed to send snatch notification") trakt_data.append((curEpObj.season, curEpObj.episode)) data = sickrage.app.notifier_providers['trakt'].trakt_episode_data_generate(trakt_data) if sickrage.app.config.use_trakt and sickrage.app.config.trakt_sync_watchlist: sickrage.app.log.debug( "Add episodes, showid: indexerid " + str(result.show.indexerid) + ", Title " + str( result.show.name) + " to Traktv Watchlist") if data: sickrage.app.notifier_providers['trakt'].update_watchlist(result.show, data_episode=data, update="add") return True
def update(self): """ Downloads the latest source tarball from server and installs it over the existing version. """ tar_download_url = 'https://git.sickrage.ca/SiCKRAGE/sickrage/repository/archive.tar?ref=master' try: if not self.install_requirements(self.current_branch): return False # prepare the update dir sr_update_dir = os.path.join(sickrage.MAIN_DIR, 'sr-update') if os.path.isdir(sr_update_dir): sickrage.app.log.info("Clearing out update folder " + sr_update_dir + " before extracting") shutil.rmtree(sr_update_dir) sickrage.app.log.info("Creating update folder " + sr_update_dir + " before extracting") try: os.makedirs(sr_update_dir) except OSError as e: sickrage.app.log.warning("Unable to create update folder " + sr_update_dir + ': ' + str(e)) return False # retrieve file sickrage.app.log.info("Downloading update from " + repr(tar_download_url)) tar_download_path = os.path.join(sr_update_dir, 'sr-update.tar') WebSession().download(tar_download_url, tar_download_path) if not os.path.isfile(tar_download_path): sickrage.app.log.warning( "Unable to retrieve new version from " + tar_download_url + ", can't update") return False if not tarfile.is_tarfile(tar_download_path): sickrage.app.log.warning( "Retrieved version from " + tar_download_url + " is corrupt, can't update") return False # extract to sr-update dir sickrage.app.log.info("Extracting file " + tar_download_path) tar = tarfile.open(tar_download_path) tar.extractall(sr_update_dir) tar.close() # delete .tar.gz sickrage.app.log.info("Deleting file " + tar_download_path) os.remove(tar_download_path) # find update dir name update_dir_contents = [x for x in os.listdir(sr_update_dir) if os.path.isdir(os.path.join(sr_update_dir, x))] if len(update_dir_contents) != 1: sickrage.app.log.warning("Invalid update data, update failed: " + str(update_dir_contents)) return False # walk temp folder and move files to main folder content_dir = os.path.join(sr_update_dir, update_dir_contents[0]) sickrage.app.log.info("Moving files from " + content_dir + " to " + sickrage.MAIN_DIR) for dirname, __, filenames in os.walk(content_dir): dirname = dirname[len(content_dir) + 1:] for curfile in filenames: old_path = os.path.join(content_dir, dirname, curfile) new_path = os.path.join(sickrage.MAIN_DIR, dirname, curfile) if os.path.isfile(new_path) and os.path.exists(new_path): os.remove(new_path) try: shutil.move(old_path, new_path) except IOError: os.makedirs(os.path.dirname(new_path)) shutil.move(old_path, new_path) except Exception as e: sickrage.app.log.error("Error while trying to update: {}".format(e)) return False # Notify update successful Notifiers.mass_notify_version_update(self.get_newest_version) return True