def easy_args_for_loop(): from joecceasy import Easy Easy.Init(shouldAutoLoadCode=False) ## Easy.ArgsE and Easy.Args give us easy access to our programs arguments, ## while conveniently not including zero sys.argv[0] ## (argument zero) this way we can easily process ## just the arguments given to this script. for i, arg in Easy.ArgsE: print(f"arg at index {i} (at sys.argv index {i+1}) : {arg}") ## Same as the function call, Easy.EnumArgs() #for i, arg in Easy.EnumArgs(): # print( f"arg at index {i}: in sys index {i+1} : {arg}" ) ## or, if we didn't want to bother enumerating them: #for arg in Easy.Args: # print( f"Easy.Args contains: {arg}" ) if Easy.ArgsCount < 1: print( Easy.TrimAndTab(r""" ### No arguments given. Please provide at least one argument. For example: By dragging and dropping a file onto this script. """))
def modifyClipboard(self): if self.isInProgress == True: return self self.isInProgress = True anyFailed = False dictOfRenamed = {} btn = self.widgets['button'] btnWasEnabled = btn.isEnabled() btn.setEnabled(False) oldLabel = btn.text() btn.setText("modifying text in clipboard...") self.qapp.processEvents() text = self.clipboard.text() #'plain' ) #text = ''.join( list(text) ) textOrig = text prefix = self.widgets['prefixLineEdit'].text() suffix = self.widgets['suffixLineEdit'].text() search = self.widgets['searchLineEdit'].text() replace = self.widgets['replaceLineEdit'].text() bPrefix = len(prefix) bSuffix = len(suffix) bSearch = len(search) atLoc = self.widgets['whereButtonGroup'].checkedId() if len(search): if atLoc == ANYWHERE: text = text.replace(search, replace) if atLoc == START: text = Easy.StrReplaceStart(text, search, replace) if atLoc == END: text = Easy.StrReplaceEnd(text, search, replace) if bPrefix and bSuffix: text = prefix + text + suffix elif bPrefix: text = prefix + text elif bSuffix: text = text + suffix self.clipboard.setText(text) self.showResultInOutput(text) btn.setText(oldLabel) btn.setEnabled(btnWasEnabled) self.isInProgress = False
def ytdlIter(urls, resultsList, location=None, checkFunc=None, maxEntries=-1, forceList=False): if isinstance(urls, str): urls = [urls] if location is None: location = Easy.Cwd if checkFunc is None: checker = Checker(location) checkFunc = checker.check for url in urls: #print( 'iterating...' ) if (forceList == True or (("?list=" in url or "&list=" in url) and not ('?v=' in url or '&v=' in url)) or '/c/' in url or url.endswith('/videos') or url.endswith('/featured') or ('/user/' in url and (not '&v=' in url or '?v=' in url))): try: #print( f'treating as playlist: {url}' ) ids = ytGetPlaylistIds(url) #print( f'Adding to urls from id list found in playlist... ') ##, id list was: {ids}' ) for id in ids: urls.append('https://www.youtube.com/watch?v=' + id) except KeyboardInterrupt as err: raise err except: Easy.PrintTraceback() else: try: _ytDownload(url, resultsList=resultsList, location=location, checkFunc=checkFunc) #print( 'try end' ) except KeyboardInterrupt as err: raise err except: Easy.PrintTraceback() #print( 'yielding' ) yield resultsList
def main(): tt = Easy.TrimAndTab location = tt(r""" # D:\music-on-wilbert\tmp\testEasyYt """) location = Easy.AbsPath(location) urls = [ ## a standalone short video 'https://www.youtube.com/watch?v=UO_QuXr521I', ## aaa-supershort playlist 'https://www.youtube.com/playlist?list=PLiCtOh7e1jKo5v8aIhKMxH56baLU5xlHJ', ## should always fail because it's in the above playlist 'https://www.youtube.com/watch?v=9RTaIpVuTqE', ] Easy.Ytdl( urls, location, )
def searchClipboard(self): text = self.clipboard.text() if not len(text): return search = self.widgets['searchLineEdit'].text() replace = self.widgets['replaceLineEdit'].text() bSearch = len(search) atLoc = self.widgets['whereButtonGroup'].checkedId() if len(search): if atLoc == ANYWHERE: text = text.replace(search, replace) if atLoc == START: text = Easy.StrReplaceStart(text, search, replace) if atLoc == END: text = Easy.StrReplaceEnd(text, search, replace) self.clipboard.setText(text) self.showResultInOutput(text)
def __init__(self): self.check = False self.url = None self.attempStartTimeStr = Easy.NowLocalStr() self.workDir = None self.dlFname = None self.fname = None self.txtFile = None self.resultEx = None ## result obj from extracted info stage self.resultDl = None ## result obj from dl stage self.resultEntries = []
def test_Utils_funcs_Fstring02(): from joecceasy import Easy exampleToFormat = "example number is: {number}" ## note that at this point the substitution hasn't happened yet ## now number is defined, late number = 5 substitutions = {'number': number} ## print while substituting in local variables and capture result... r1 = Easy.PrintWithFormat(exampleToFormat, **locals()) ## or, substituting named filed with given value.. r2 = Easy.PrintWithFormat(exampleToFormat, number=number) ## alternate methods of doing the same, with optional end r3 = Easy.PrintWithFormatV(exampleToFormat, kwargs=locals(), end='\n\n\n') # we don't have to print the results r4 = Easy.Format(exampleToFormat, number=5) r5 = Easy.FormatV(exampleToFormat, kwargs=substitutions) # or without, keyword arguments, first locals then globals, use None to skip r6 = Easy.FormatV(exampleToFormat, None, substitutions) resultPyFmt = exampleToFormat.format(**locals()) ## nothing wrong with this other than too much syntax #print ( f'pure python example: {resultPyFmt}' ) assert resultPyFmt == r1 assert resultPyFmt == r2 assert resultPyFmt == r3 assert resultPyFmt == r4 assert resultPyFmt == r5 assert resultPyFmt == r6
def check(self, id): ## clean up id in case it has other data in it if '&' in id: ampAt = id.index('&') id = id[:ampAt] location = self.location listed = Easy.Ls(location) #print( f'listed: {listed}') isOk = True for l in listed: #print( f'comapre id: {id} l: {l}' ) if id + '.' in l or l.endswith( id) or f'?id={id}' in l or f'&id={id}' in l: isOk = False return isOk
def test_Utils_Funcs_Fstring_01(): from joecceasy import Easy exampleToFormat = "example number is: {number}" ## note that at this point the substitution hasn't happened yet ## now number is defined, late number = 2 ## now we want to use our number, late result = eval(Easy.Fstring(exampleToFormat)) ## at this point the substitution should be done ## here's the normal python way resultPyFmt = exampleToFormat.format(**locals()) #print ( f'pure python example: {resultPyFmt}' ) assert resultPyFmt == result
from joecceasy import Easy QtWidgets = Easy.Mods['PySide2.QtWidgets'] instructions = "Instructions: " \ "This is some instructional text. It can be multiple lines if you like. " \ "Click Go to get a message!\n" def additionalWidgets(ui): qw = Easy.Mods.PySide2.QtWidgets ui.mainLayout.addRow( qw.QLabel('This is an additional row!'), qw.QPushButton('click me'), ) qtui = Easy.Qtui( title="JoecceasyQtuiExample", instructionsText=instructions, showInput=False, callbacks={ 'initAdditionalWidgetsIntoDefault': additionalWidgets, 'initWidgetsPre': additionalWidgets, 'initWidgetsPost': additionalWidgets }, ) exitCode = qtui.execQapp() ## qtui.qapp.exec_() would do the same Easy.Exit(exitCode) ## just uses sys.exit
def convertFilesOnClipboard(self): if self.isConversionInProgress == True: return self self.isConversionInProgress = True btn = self.widgets['button'] btnWasEnabled = btn.isEnabled() btn.setEnabled(False) oldLabel = btn.text() btn.setText("converting...") self.qapp.processEvents() clip = self.Qtg.QGuiApplication.clipboard() mimeData = clip.mimeData() urls = mimeData.urls() paths = [path.toLocalFile()[0:] for path in urls] #self.print( paths ) import sys import subprocess import time import traceback args = paths argsCount = len(args) ffmpeg = self.widgets['ffmpegLineEdit'].text() ##"ffmpeg" ## works on most linux systems if ffmpeg is installed self.print("Attempting to convert to mp3 files...") try: for i, arg in enumerate(args): self.qapp.processEvents() inFile = arg outFile = self.replaceOrAppendExtension(inFile) ffmpeg = "ffmpeg" #infoCmd = '"ffmpeg"' + " -i " + inFile #subprocess.call( ) spc = ' ' isCopyCodec = self.widgets['codecCopyCheckbox'].isChecked() #False fOptsList = [] optBitrate = self.widgets['bitrateLineEdit'].text() optBitrateStr = str(int(optBitrate)) optBitrateStr += 'k' fOptsFlagsList = ['-vn', '-sn'] fOptsCopyList = ['-c:a', 'copy'] fOptsAudioBitrateList = \ ['-b:a', optBitrateStr, ] fOptsList.extend(fOptsFlagsList) if isCopyCodec: fOptsList.extend(fOptsCopyList) else: fOptsList.extend(fOptsAudioBitrateList) """ cmd = ( '"' + ffmpeg + '"' + " -n -i " + '"' + inFile + '"' + fOptsStr + '"' + outFile + '"' ) """ cmdList = [ffmpeg, '-n', '-i', inFile] cmdList.extend(fOptsList) cmdList.append(outFile) cmd = cmdList #cmd = f"echo {inFile}" self.print(f"cmd is: {cmd}") ## -vn discards video ## -sn discards subtitles ## -loglevel panic msg = f"Converting file {i+1} of {argsCount}:\n" \ + "" + inFile + "\n" \ + "To:\n" \ + "" + outFile self.print(msg) try: tub = Easy.Tubprocess(cmd) for v in tub: self.print(v.out, v.err, end='') retVal = tub.wait() ## only needed for its cleanup sidefx if retVal == 0: self.print("\n...done") else: self.print( f"...ffmpeg exited with error code: {retVal}") except: self.print("An error occured.") self.print(Easy.Traceback()) except: self.print(Easy.Traceback()) self.print( Easy.TrimAndTab(r""" ## ...finished the attempt to process all files. Any failures/errors should be noted above. =============================== """)) btn.setText(oldLabel) btn.setEnabled(btnWasEnabled) self.isConversionInProgress = False
from joecceasy import Easy ## make a qtui that uses a timer based callback ## to run code on update ## using function as lambda inline qtui = Easy.Qtui( title="JoecceasyQtuiExample", updateInterval=1000, callbacks={ 'update' : lambda self: self.print( f"Update at time: {Easy.Mods.time.time()}" ), }, showInput=False, autoExpandOutput=True, ) exitCode = qtui.execQapp() Easy.Exit( exitCode )
from joecceasy import Easy cmd = ["python.exe", "-c", "import time; print(1); time.sleep(1); print(2)"] tub = Easy.Tubprocess(cmd) for i in tub: print(i.out, end='')
from random import randint import time from joecceasy import Easy #from asciimatics.screen import Screen #Screen = Easy.Ascui.AsciimaticsMod.screen.Screen #Easy.Mods.sys.exit( ) ## Multiples can be used in sequence if you want multiple steps... ## First one, minor customization, no custom class ## note that since this functions as first screen only, ## we show "Next" instead of "Quit" Easy.Ascui(title='Ascui Examples Step 1 of 2', quitLabel="Next", quitAskMsg='').exec_() ## Second one, via, customized subclass class ExampleAscui( Easy.Ascui ): def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) def initWidgets(self): self.frame.createWidget("Text", "MyText", "My Text" ) self.frame.createWidget("Divider", "Divider01", None, height=3 ) self.frame.createWidget("Button", "Do Nothing", None, layoutCol=0, inFooter=True ) self.frame.createWidget("Button", "Show Anim Msg", None, layoutCol=1, inFooter=True, callback=lambda: Easy.Ascui.FullscreenMsg( msg="Button was pressed!",
from joecceasy import Easy intro = r""" Easy.Input Example ====================== This script has inputs with timeouts! Easy.Input is clumsy, only use it for simplest cases. Behaviour of further calls to Easy.Input, after one of them times out, is awful in terms of user experience. Perhaps use Ascui instead? Or something like whip tail etc. """ print(intro, end="") greeting = Easy.Input("\n\n" + "Please enter a greeting (5 second timeout):", 5, "Hello") print(f'greeting is: {repr(greeting)}') message = Easy.Input("\n\n" + "Please enter a message (6 sec timeout):", timeout=6, default="It's a wonderful world. :) ") print(f'message is: {repr(message)}')
from random import randint import time from joecceasy import Easy #from asciimatics.screen import Screen #Screen = Easy.Ascui.AsciimaticsMod.screen.Screen #Easy.Mods.sys.exit( ) ## Multiples can be used in sequence if you want multiple steps... ## First one, minor customization, no custom class ## note that since this functions as first screen only, ## we show "Next" instead of "Quit" Easy.Ascui(title='Ascui Examples Step 1 of 2', quitLabel="Next").exec_() ## Second one, via, customized subclass class ExampleAscui(Easy.Ascui): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def initWidgets(self): self.frame.createWidget("Text", "MyText", "My Text") # self.frame.createWidget("Divider", "Divider01", None, height=3 ) self.frame.createWidget("Button", "Do Nothing", None, layoutCol=0,
from joecceasy import Easy cmd = [ "python.exe", "-c", "import time; print(1); time.sleep(1); print(2); time.sleep(1); print(3)" ] tub = Easy.Tubprocess(cmd, autoPrint=True) tub.wait()
from joecceasy import Easy instructions = "Instructions: " \ "This is some instructional text. It can be multiple lines if you like. " \ "Click Go to get a message!\n" def onGoButtonClicked(): global qtui qtui.print( "Go button was clicked at epoch time: " \ f"{Easy.Mods.time.time()}" ) qtui = Easy.Qtui( title="JoecceasyQtuiExample", instructionsText=instructions, showInput=False, callbacks={'onGoButtonClicked': onGoButtonClicked}, ) exitCode = qtui.execQapp() ## qtui.qapp.exec_() would do the same Easy.Exit(exitCode) ## just uses sys.exit
from joecceasy import Easy if True: trimmed = Easy.TrimAndTab(r""" ## first non whitespace must be "#", this line gets removed and others unindented to match Here's some trimmed lines, trimmed lines are really useful. The literal code has nice indentation. Code is easier to copy/paste and it's easier to write big strings inside in functions/classes. They can end (from a practical perspective) with windows backslashes too! eg. C:\Windows\ """) print(trimmed)
from joecceasy import Easy from joecceasy import Easy instructions = Easy.TrimAndTab(r""" ## Instructions: This is some instructional text. It can be multiple lines if you like. """) ## Create and run a Qtui app with more customization qtui = Easy.Qtui( title="Joecceasy Qtui Example - Customization", tabTitle='DefaultTab', showInput=False, showInstructions=True, instructionsText=instructions, ) exitCode = qtui.execQapp() Easy.Exit(exitCode)
from joecceasy import Easy spc = ' ' echoCmdAndArgs = [ r'''echo''', r'''test!''', r'''another>test''', r'''test three''', r'''c:\some dir\file.txt''' ] echoCmdAndArgs = Easy.EscArgsForWin(echoCmdAndArgs) print("esc: ", echoCmdAndArgs) Easy.CallInteractive(echoCmdAndArgs, loud=True) pyCmdAndArgs = [ r'''python''', r'''-c''', r'''import sys; print( sys.argv[0] ); print( len(sys.argv) ); print('hello you'); print( "hello again")''' ] pyCmdAndArgs = Easy.EscArgsForCmdExe(pyCmdAndArgs) print("esc: ", pyCmdAndArgs) Easy.CallInteractive(pyCmdAndArgs, loud=True)
## ## most useful example from here: https://www.attrs.org/en/stable/examples.html from joecceasy import Easy ; #Easy.Init() @Easy.DataClass class MyDataClass: simple: bool = True dataclassesAreTheOnlyOption: bool = False thisCouldBeAnything: object = None myDataInstance = MyDataClass( ) Easy.Ic( myDataInstance ) Point2d = Easy.NamedTuple( 'Point2d', ['x', 'y']) point2d = Point2d( 5, -2 ) Easy.Ic( point2d )
#!/usr/bin/python3 from joecceasy import Easy pkg = "isodate" ## note that this testing script ## assumes pkg name is same as mod name, ## like "isodate" example. ## The test will fail otherwise, ## but Easy.PipInstall feature can be used without ## matching names as long as care is taken to use the ## correct different pkg and mod names try: pkgMod = Easy.Mods[pkg] except: print(f""" {pkg} package not found, attempting pip install...""") Easy.PipInstall(pkg) print(f""" {pkg} package installed """) pkgMod = Easy.Mods[pkg] print(f"dir function used on pkg {pkg} shows:") print(dir(pkgMod)) Easy.Input('press enter to exit or wait 5 sec for timeout', 5, warn=0)
def main(): paths = ['..','.'] absOfEntries = [ i.abs for i in Easy.WalkAnIter(paths) ] for i in absOfEntries: print( i )
def replaceOrAppendExtension(self, inFile): ## default outFile = inFile + ".mp3" if False: "pass" elif inFile.endswith('.flac'): outFile = Easy.ReplaceEnd(inFile, ".flac", ".mp3") elif inFile.endswith('.mp4'): outFile = Easy.ReplaceEnd(inFile, ".mp4", ".mp3") elif inFile.endswith('.m4a'): outFile = Easy.ReplaceEnd(inFile, ".m4a", ".mp3") elif inFile.endswith('.mkv'): outFile = Easy.ReplaceEnd(inFile, ".mkv", ".mp3") elif inFile.endswith('.ogg'): outFile = Easy.ReplaceEnd(inFile, ".ogg", ".mp3") elif inFile.endswith('.opus'): outFile = Easy.ReplaceEnd(inFile, ".opus", ".mp3") elif inFile.endswith('.webm'): outFile = Easy.ReplaceEnd(inFile, ".webm", ".mp3") elif inFile.endswith('.avi'): outFile = Easy.ReplaceEnd(inFile, ".avi", ".mp3") elif inFile.endswith('.mpeg'): outFile = Easy.ReplaceEnd(inFile, ".mpeg", ".mp3") elif inFile.endswith('.mpg'): outFile = Easy.ReplaceEnd(inFile, ".mpg", ".mp3") elif inFile.endswith('.aac'): outFile = Easy.ReplaceEnd(inFile, ".aac", ".mp3") elif inFile.endswith('.wav'): outFile = Easy.ReplaceEnd(inFile, ".wav", ".mp3") else: "pass" ## Default case already handled return outFile
#!/usr/bin/env python3 from joecceasy import Easy Easy.Init() ## current working dir is auto changed ## when using typical initialization ## of Easy class instance. ## e.g. when accessing Easy.Magic ## or calling Easy.Init() ## ## So here, current working dir is changed, ## but... other dirs are kept track of! Yey! print("current dir is:") print(Easy.Cwd) ## same as os.getcwd() print("but also remembers original working dir:") print(Easy.OrigWorkDir) print("script dir is available even after changing directory:") #Easy.Chdir( ) print(Easy.ScriptDir) print( "If script was started when working dir was script's dir, the above 3 will all be the same." )
from joecceasy import Easy from joecceasy import Easy instructions = Easy.TrimAndTab(r""" ## Instructions: This is some instructional text. It can be multiple lines if you like. """) def additionalWidgetsInMain(qtui): qw = qtui.QtWidgets qtui.mainLayout.addRow( qw.QLabel('This is an added row!'), qw.QPushButton('click me'), ) ## Create and run a Qtui app with more customization qtui = Easy.Qtui( title="Joecceasy Qtui Example - Customization", tabTitle='DefaultTab', showInput=False, useOutput=False, callbacks={ 'initAdditionalWidgetsIntoDefault': additionalWidgetsInMain, }, ) exitCode = qtui.execQapp() Easy.Exit(exitCode)
from joecceasy import Easy #tub = Easy.Tubprocess( ["python.exe", "example__func__PrintLoop__01_a.py"], ) #errToOut=True ) for i in Easy.Tubprocess([ "python.exe", "-c", "import time; print(1); time.sleep(1); print(2); time.sleep(1); print(3)" ]): print(i.out, end='') exit() for i, (out, err), in enumerate(tub): print(out, end='') #print( err, end='' ) if i > 80: break print('break') print(tub.outStr) Easy.Mods.time.sleep(1.5) print("next") print(tub.next().out) print("resuming") for out, err2 in tub: print(out, end='') print(err2, end='') print(tub.outStr[-25:])
from joecceasy import Easy Easy.Init() ## When making a subclass, the init function ## should pass through ## *args, then optional arguments, then **kwargs ## using a pattern like below, otherwise there may be issues ## trying to pass through optional arguments class MyQtui(Easy.Qtui): def __init__(self, *args, title="Joecceasy Qtui Example - Subclass", showInput=False, autoExpandOutput=True, updateInterval=3000, **kwargs): super().__init__( *args, title=title, showInput=showInput, autoExpandOutput=autoExpandOutput, updateInterval=updateInterval, **kwargs, ) def initAdditionalWidgetsIntoDefault(self): qw = Easy.Mods.PySide2.QtWidgets msgBtn = self.widgets["msgButton"] = qw.QPushButton('click me') self.mainLayout.addRow(msgBtn)
import os, sys, traceback, subprocess from joecceasy import Easy timeout = 5 print(f'About to get input (with timeout)...') print(f'Note that default input will be received after {timeout} seconds.') got = Easy.Input(f'Input - hurry, before {timeout} second timeout!:', timeout=timeout, default=None) print(f'received input was: {got}\n{repr(got)} {type(got)}')