def execute(self, args): logger = logging.getLogger(__name__) if args.workspace_subcommand is None: self.parser.print_help() return None color = Color() if (args.workspace_subcommand == "add"): ws_name = slashes2dash(args.name) self.ws.add(ws_name, args.path) logger.info(color.colored( "Workspace `%s` successfuly added" % ws_name, "green")) elif (args.workspace_subcommand == "remove"): ws_name = slashes2dash(args.name) self.ws.remove(ws_name) logger.info(color.colored( "Workspace `%s` successfuly removed" % ws_name, "green")) elif (args.workspace_subcommand == "list"): table = PrettyTable(["Name", "Path"]) table.align["Name"] = "l" table.align["Path"] = "l" for key, ws in sorted(self.ws.list().items()): table.add_row([key, ws["path"]]) logger.info(table)
def print_update(self, repo_name, repo_path): """Print repository update.""" color = Color() self.logger.info(color.colored( "=> [%s] %s" % (repo_name, repo_path), "green")) try: repo = Repository(repo_path) repo.update() except RepositoryError as e: self.logger.error(e) pass print("\n")
def print_status(self, repo_name, repo_path): """Print repository status.""" color = Color() try: repo = Repository(repo_path) self.logger.info(color.colored( "=> [%s] %s" % (repo_name, repo_path), "green")) repo.status() self.logger.info("\n") except ValueError as e: self.logger.error(e) pass
def show_workspace(self, name): """Show specific workspace.""" if not self.workspace.exists(name): raise ValueError("Workspace `%s` doesn't exists." % name) color = Color() workspaces = self.workspace.list() self.logger.info("<== %s workspace ==>" % color.colored(name, "green")) self.logger.info("\tPath: %s" % workspaces[name]["path"]) self.logger.info("\tNumber of repositories: %s" % color.colored( len(workspaces[name]["repositories"]), "yellow")) repo_colored = color.colored("Repositories", "blue") path_colored = color.colored("Path", "blue") trepositories = PrettyTable( [repo_colored, path_colored, color.colored("+", "blue")]) trepositories.align[repo_colored] = "l" trepositories.align[path_colored] = "l" for repo_name in workspaces[name]["repositories"]: fullname = "%s/%s" % (name, repo_name) fullpath = find_path(fullname, self.config)[fullname] try: repo = Repository(fullpath) repo_scm = repo.get_scm() except RepositoryAdapterNotFound: repo_scm = None trepositories.add_row( [color.colored(repo_name, "cyan"), fullpath, repo_scm]) self.logger.info(trepositories)
def __init__(self, connector, output_directory, subprocess=None): """ Initiliaze Downloader Parameters: connector: connector to Grooveshark api subprocess: spawn new processes output_directory: where files will be downloaded """ if subprocess is not None: self.subprocess = subprocess else: import subprocess self.subprocess = subprocess self.color = Color() self.output_directory = output_directory self.connector = connector self.download_queue = [] self.download_count = 0
def sync(self, ws_name): """Synchronise workspace's repositories.""" path = self.config["workspaces"][ws_name]["path"] repositories = self.config["workspaces"][ws_name]["repositories"] logger = logging.getLogger(__name__) color = Color() for r in os.listdir(path): try: repo = Repository(os.path.join(path, r)) except RepositoryError: continue else: repositories[r] = repo.path for repo_name, path in repositories.items(): logger.info(color.colored( " - %s" % repo_name, "blue")) self.config["workspaces"][ws_name]["repositories"] self.config.write()
def sync(self, ws_name): """Synchronise workspace's repositories.""" path = self.config["workspaces"][ws_name]["path"] repositories = self.config["workspaces"][ws_name]["repositories"] repo_list = {} for r in listdir(path): try: repo = Repository(join(path, r)) except RepositoryError: continue else: repositories[r] = repo.path repo_list[r] = repo.path logger = logging.getLogger(__name__) color = Color() logger.info("Workspace `%s` synchronized" % ws_name) logger.info("Added %d repositories:" % len(repo_list)) for repo_name, path in repo_list.items(): logger.info(color.colored( " - %s" % repo_name, "blue"))
def __init__(self, connector, output_directory, subprocess=None): """ Initiliaze Downloader Parameters: connector: connector to Grooveshark api subprocess: spawn new processes output_directory: where files will be downloaded """ if subprocess is not None: self.subprocess = subprocess else: import subprocess self.subprocess = subprocess self.color = Color() self.output_directory = output_directory self.connector = connector self.download_queue = [] self.download_count = 0
#!/usr/bin/env python from pycolorizer import Color, InvalidStyleNameError c = Color() # highlight('green') == bg('green') == bg_green() # white() == fg('white') print(c('Hello World!').white().bold().highlight('blue')) # Create your own styles c.set_themes( { 'welcome': ('yellow', 'bg_cyan'), 'bye': 'blue', } ) print(c('Hello world!').welcome().bold()) print(c('Bye!').bye()) c.add_theme('error', 'red') try: c.add_theme('error&é"&é"&é', 'red') except InvalidStyleNameError as e: print(c('InvalidStyleNameError {}'.format(e)).error()) # Use style tags text = """
class Downloader: output_directory = None connector = None subprocess = None download_queue = None download_count = None max_per_list = 10 def __init__(self, connector, output_directory, subprocess=None): """ Initiliaze Downloader Parameters: connector: connector to Grooveshark api subprocess: spawn new processes output_directory: where files will be downloaded """ if subprocess is not None: self.subprocess = subprocess else: import subprocess self.subprocess = subprocess self.color = Color() self.output_directory = output_directory self.connector = connector self.download_queue = [] self.download_count = 0 def download_playlist(self, playlist_id=None): """ Download Playlist Parameters: playlist_id: the playlist id """ songs = [] if (playlist_id is not None): plist = self.connector.get_playlist_from_id(playlist_id) songs = plist["Songs"] if ("Songs" in plist) else [] else: for playlist in self.download_queue: plist = self.connector.get_playlist_from_id( playlist['PlaylistID']) songs = songs + plist["Songs"] self.download_queue = songs self.download() def download_song(self, filename, song): """ Download song Parameters: filename: the filename song: dictionary with song informations """ self.color.cprint(("Downloading: %s" % (filename)), "cyan") stream_key = self.connector.get_stream_key_from_song_id(song["SongID"]) if stream_key == []: print("Failed to retrieve stream key!") return False #Run wget to download the song wget = "wget --progress=dot --post-data=streamKey=%s" \ " -O \"%s\" \"http://%s/stream.php\"" % ( stream_key["streamKey"], filename, stream_key["ip"] ) cmd = wget + " 2>&1 | grep --line-buffered \"%\" |" \ "sed -u -e \"s,\.,,g\" | awk '{printf(\"\b\b\b\b%4s\", $2)}'" process = self.subprocess.Popen(cmd, shell=True) try: process.wait() self.color.cprint("\nDownloaded", "green") self.download_count += 1 except BaseException: self.color.cprint("Download cancelled. File deleted.", "red") os.remove(filename) return False return True def prepare(self, query, type=None): """ Prepare downloads Parameters: query: the search query type: the search type (types are 'Songs', 'Artists', 'Albums' or 'Playlists') """ result = self.connector.search(query, type) self.__display_raw_input( result, type, "Press \"n\" for next page, " "\"Number id\" to add element in queue, " "\"q\" for quit and download: ") def __display_raw_input(self, result, type, input_text): """ Display prompt to choose songs, playlist, etc... Parameters: result: the result from the connector type: the search type (types are 'Songs', 'Artists', 'Albums' or 'Playlists') input_text: texte for the raw input """ try: if type != "Playlists": table = PrettyTable(["id", "Album", "Artist", "Song"]) else: table = PrettyTable(["id", "Name", "Author", "NumSongs"]) for idx, data in enumerate(result): key = None if (type != "Playlists"): table.add_row([ idx, data["AlbumName"].ljust(40), data["ArtistName"], data["SongName"] if "SongName" in data else data["Name"] ]) else: table.add_row([ idx, data["Name"].ljust(40), data["FName"], data["NumSongs"] ]) is_last = (idx == (len(result) - 1)) if ((idx != 0 and idx % self.max_per_list == 0) or is_last): print(table.get_string()) table.clear_rows() while (key is not False): key = input(input_text) if (key == "q"): raise StopIteration elif (key == "n" and is_last is False): key = False elif (key.isdigit()): key = int(key) if (key >= 0 and key <= len(result)): added_data = result[key] self.download_queue.append(added_data) print("%s added" % added_data["SongName"] if "SongName" in added_data else added_data["Name"]) continue except StopIteration: pass except Exception as inst: print("Unexpected error:", sys.exc_info()[0]) raise inst def download(self): """ Download files """ if (self.download_queue != []): for file in self.download_queue: filename = ( "%s/%s - %s.mp3" % (self.output_directory, file["ArtistName"], file["SongName"] if "SongName" in file else file["Name"])) if (os.path.exists(filename) is not True): self.download_song(filename, file) else: self.download_count += 1 return True return False def has_downloaded(self): return False if self.download_count == 0 else True
class ColorTest(unittest.TestCase): def setUp(self): self.color = Color() def test_given_string_should_apply_style(self): self.assertEqual( "\033[31mfoo\033[0m", str(self.color('foo').red()) ) def test_given_string_should_apply_more_than_one_style(self): self.assertEqual( "\033[1m\033[97mfoo\033[0m\033[0m", str(self.color('foo').white().bold()) ) def test_style_name_is_not_case_sensitive(self): self.assertEqual( "\033[31mfoo\033[0m", str(self.color('foo').RED()) ) def test_state_is_initialized(self): self.assertEqual('foo', str(self.color('foo'))) self.assertEqual('bar', str(self.color('bar'))) def test_given_styled_string_should_be_able_to_reused(self): self.assertEqual('foo', str(self.color('foo').blue().reset())) def test_raise_error_when_style_not_found(self): self.assertRaises( NoStyleFoundError, lambda: self.color.color('foo bar').foo() ) def test_style_can_contain_text(self): self.assertEqual( str(self.color('foo').blue()), self.color().blue('foo') ) def test_shortcut_foreground(self): self.assertEqual( str(self.color('Hello').blue()), str(self.color('Hello').fg('blue')) ) def test_shortcut_background(self): self.assertEqual( str(self.color('Hello').bg_red()), str(self.color('Hello').bg('red')) ) def test_has_highlight_shortcut_for_background(self): self.assertEqual( str(self.color('Hello').bg_blue()), str(self.color('Hello').highlight('blue')) ) def test_should_support_themes(self): self.color.set_themes({'error': 'red'}) self.assertEqual( str(self.color('Error...').red()), str(self.color('Error...').error()) ) def test_thmes_can_override_default_styles(self): self.color.set_themes({'white': 'red'}) self.assertEqual( str(self.color('Warning...').red()), str(self.color('Warning...').white()) ) def test_given_invalid_them_name_should_raise_error(self): self.assertRaises( InvalidStyleNameError, lambda: self.color('foo bar').set_themes({'&é""': "white"}) ) def test_given_styled_string_can_be_cleaned(self): self.assertEqual( 'some text', str(self.color(str(self.color('some text').red())).clean()) ) def test_given_string_with_style_tags_should_be_interpret(self): text = 'This is <red>some text</red>' self.assertEqual( 'This is ' + str(self.color('some text').red()), str(self.color(text).colorize()) ) def test_given_string_with_nested_tags_should_be_interpret(self): actual = str( self.color('<cyan>Hello <bold>World!</bold></cyan>') .colorize() ) expected = str( self.color('Hello ' + str(self.color('World!').bold())) .cyan() ) self.assertEqual(expected, actual) def test_apply(self): self.assertEqual( str(self.color('foo').blue()), str(self.color().apply('blue', 'foo')) ) def test_apply_center(self): width = 80 for text in ('', 'hello', 'hellow world', '✩'): current_width = len( str(self.color(text).center(width)) ) self.assertEqual(width, current_width) current_width = len( str( self.color(text) .center(width) .bg('blue') .clean() ) ) self.assertEqual(width, current_width) def test_apply_center_multiline(self): width = 80 color = Color() text = 'hello' + "\n" + '✩' + "\n" + 'world' actual = str(color(text).center(width)) for line in actual.split("\n"): self.assertEqual(width, len(line)) def test_should_support_256_colors(self): self.assertEqual( "\033[38;5;3mfoo\033[0m", self.color().apply('color[3]', 'foo') ) self.assertEqual( "\033[48;5;3mfoo\033[0m", self.color().apply('bg_color[3]', 'foo') ) def test_given_invalid_color_number_should_raise_error(self): self.assertRaises( NoStyleFoundError, lambda: self.color().apply('color[-1]', 'foo') ) self.assertRaises( NoStyleFoundError, lambda: self.color().apply('color[256]', 'foo') ) def test_should_handle_recursion_in_theme_with_list(self): self.assertRaises( RecursionInThemeError, lambda: self.color().set_themes( { 'green': ['green'], } ) ) def test_should_handle_recursion_in_theme_with_string(self): self.assertRaises( RecursionInThemeError, lambda: self.color().set_themes( { 'green': 'green', } ) )
def setUp(self): self.color = Color()
class Downloader: output_directory = None connector = None subprocess = None download_queue = None download_count = None max_per_list = 10 def __init__(self, connector, output_directory, subprocess=None): """ Initiliaze Downloader Parameters: connector: connector to Grooveshark api subprocess: spawn new processes output_directory: where files will be downloaded """ if subprocess is not None: self.subprocess = subprocess else: import subprocess self.subprocess = subprocess self.color = Color() self.output_directory = output_directory self.connector = connector self.download_queue = [] self.download_count = 0 def download_playlist(self, playlist_id=None): """ Download Playlist Parameters: playlist_id: the playlist id """ songs = [] if (playlist_id is not None): plist = self.connector.get_playlist_from_id(playlist_id) songs = plist["Songs"] if ("Songs" in plist) else [] else: for playlist in self.download_queue: plist = self.connector.get_playlist_from_id( playlist['PlaylistID'] ) songs = songs + plist["Songs"] self.download_queue = songs self.download() def download_song(self, filename, song): """ Download song Parameters: filename: the filename song: dictionary with song informations """ self.color.cprint(("Downloading: %s" % (filename)), "cyan") stream_key = self.connector.get_stream_key_from_song_id(song["SongID"]) if stream_key == []: print("Failed to retrieve stream key!") return False #Run wget to download the song wget = "wget --progress=dot --post-data=streamKey=%s" \ " -O \"%s\" \"http://%s/stream.php\"" % ( stream_key["streamKey"], filename, stream_key["ip"] ) cmd = wget + " 2>&1 | grep --line-buffered \"%\" |" \ "sed -u -e \"s,\.,,g\" | awk '{printf(\"\b\b\b\b%4s\", $2)}'" process = self.subprocess.Popen(cmd, shell=True) try: process.wait() self.color.cprint("\nDownloaded", "green") self.download_count += 1 except BaseException: self.color.cprint("Download cancelled. File deleted.", "red") os.remove(filename) return False return True def prepare(self, query, type=None): """ Prepare downloads Parameters: query: the search query type: the search type (types are 'Songs', 'Artists', 'Albums' or 'Playlists') """ result = self.connector.search(query, type) self.__display_raw_input( result, type, "Press \"n\" for next page, " "\"Number id\" to add element in queue, " "\"q\" for quit and download: " ) def __display_raw_input(self, result, type, input_text): """ Display prompt to choose songs, playlist, etc... Parameters: result: the result from the connector type: the search type (types are 'Songs', 'Artists', 'Albums' or 'Playlists') input_text: texte for the raw input """ try: if type != "Playlists": table = PrettyTable(["id", "Album", "Artist", "Song"]) else: table = PrettyTable(["id", "Name", "Author", "NumSongs"]) for idx, data in enumerate(result): key = None if (type != "Playlists"): table.add_row([ idx, data["AlbumName"].ljust(40), data["ArtistName"], data["SongName"] if "SongName" in data else data["Name"]]) else: table.add_row([ idx, data["Name"].ljust(40), data["FName"], data["NumSongs"]]) is_last = (idx == (len(result) - 1)) if ((idx != 0 and idx % self.max_per_list == 0) or is_last): print(table.get_string()) table.clear_rows() while (key is not False): key = input(input_text) if (key == "q"): raise StopIteration elif (key == "n" and is_last is False): key = False elif (key.isdigit()): key = int(key) if (key >= 0 and key <= len(result)): added_data = result[key] self.download_queue.append(added_data) print( "%s added" % added_data["SongName"] if "SongName" in added_data else added_data["Name"] ) continue except StopIteration: pass except Exception as inst: print("Unexpected error:", sys.exc_info()[0]) raise inst def download(self): """ Download files """ if (self.download_queue != []): for file in self.download_queue: filename = ( "%s/%s - %s.mp3" % ( self.output_directory, file["ArtistName"], file["SongName"] if "SongName" in file else file["Name"] ) ) if (os.path.exists(filename) is not True): self.download_song(filename, file) else: self.download_count += 1 return True return False def has_downloaded(self): return False if self.download_count == 0 else True