I'm using Python 3. I'm still learning but am, let's say, an intermediate at other programming languages. I'm building a simple GUI that just does simple things for now but will add on more things as I go. I've got some success. Then I had an idea, to have a function (or whatever it's called in Python) to run an external script, stored in my script folder. So I wrote this...
def runscript(scriptname):
from subprocess import call
call(['scripts/'+scriptname])
Then later on in my code I have this...
sdb = Button(topbar, text="Shutdown", command= runscript("shutdown.sh"), font=("Helvetica", 20), width=18)
shutdown.sh is a simple script that does what you might expect it to.
Now whenever I run the python script with python3 MyScript.py the machine instantly shuts down! I obviously only want it to shut down when I click the Shutdown button. From reading I gather it's to do with the fact that Python executes every line as it goes. So I don't understand why there are plenty of examples around on the internet for functions that will shutdown your PC, whereas my more general script-running code doesn't work in any useful way.
When you write the code runscript("shutdown.sh"), what should it do?
Obviously, the answer is that it should call the runscript function and pass it the argument "shutdown.sh".
So, when you write the code command=runscript("shutdown.sh"), what should it do?
Do you see the problem? You're executing the runscript function, and passing the result of that function to the command attribute. Instead, the command attribute takes a reference to a callable function. Since you are trying to pass in an explicit argument, one way to accomplish that is with lambda:
sdb = Button(..., command=lambda script="shutdown.sh": runscript(script))
Some people prefer functools.partial over lambda:
sdb = Button(..., command=functools.partial(runscript, "shutdown.sh"))
Related
I'm just basically asking:
if it's considered OK to use exec() in this context
if there's a better/more pythonic solution
for any input or comments on how my code could be improved
First, some context. I have main.py which basically takes input and checks to see if I've written a command. Let's say I type '/help'. The slash just tells it my input was supposed to be a command, so then it checks if a function called 'help' exists, and if so, that function will be run.
To keep things tidy in main.py, and to allow myself to add more commands easily, I have a 'commands' directory, with individual command files in it, such as help.py. help.py would look like this for example:
def help():
print("You've been helped")
So then of course, I need to import help() from help.py, which was trivial.
As I added more commands, I decided to add an init.py file where I'd keep all the command import lines of code, and then just do 'from init import *' in main.py. At first, each time I added a command, I'd add another line in init.py to import it. But that wasn't as flexible as I wanted, so I thought, there's got to be a way to just loop through all the .py files in my commands directory and import them. I struggled with this for a while but came up with a solution that works.
In the init.py snippet below, I loop through the commands directory (and a couple others, but they're irrelevant to the question), and you'll see I use the dreaded exec() function to actually import the commands.
loaded, failed = '', ''
for directory in command_directories:
command_list = os.listdir(directory)
command_list.sort()
for command_file in command_list:
if command_file.endswith(".py"):
command_name = command_file.split(".")[0]
try:
# Evil exec() hack to use variable-name directories/modules
# Haven't found a more... pythonic... way to do this
exec(f"from {directory}.{command_name} import {command_name}")
loaded = loaded + f" - Loaded: {command_name}\n"
except:
failed = failed + f" - Failed to load: {command_name}\n"
if debug == True:
for init_debug in [loaded, failed]: print(init_debug)
I use exec() because I don't know a better way to make a variable with the name of the function being loaded, so I use {command_name} in my exec string to arbitrarily evaluate the variable name that will store the function I'm importing. And... well, it works. The functions work perfectly when called from main.py, so I believe they are being imported in the correct namespace.
Obviously, exec() can be dangerous, but I'm not taking any user input into it, just file names. Filenames that I only I am creating. This program isn't being distributed, but if it was, then I believe using exec() would be bad since there's potential someone could exploit it.
If I'm wrong about something, I'd love to hear about it and get suggestions for a better implementation. Python has been very easy to pick up for me, but I'm probably missing some of the fundamentals.
I should note, I'm running python 3.10 on replit (until I move this project to another host).
I am trying to run a python script through script snap in snaplogic. I am facing some issues where it ask me to declare a script hook variable. Can you please help me on that.
With the script snap you should use the "Edit Script" button on the snap itself. This will open a script editor and generate a skeleton script in the language you've selected (Py in this case).
In the skeleton you can see the baseline methods and functions we define. In there you can see the usage and comments of the scripthook var. If you have an existing script I would recommend trying to write it into this skeleton's execute method than trying to implement scripthook in your existing code. You can also define your own methods and functions within the confines of the skeleton class and reference them with "this." notation.
For faster answers on SnapLogic related questions I'd recommend visiting the SnapLogic Community site.
As explained by #dwhite0101, within Script Snap when you click Edit Script you get an option to generate code template.
ScriptHook is an interface that is implemented as callback mechanism for Script Snap to call into the script.
It helps you to deal with input and output rows. The constructor below initializes the input, output, error and log variables.
self object is similar to this in c++ that holds the current row values.
class TransformScript(ScriptHook):
def __init__(self, input, output, error, log):
self.input = input
self.output = output
self.error = error
self.log = log
You can perform transformations in execute method:
def execute(self):
self.log.info("Executing Transform script")
while self.input.hasNext():
in_doc = self.input.next()
wrapper = java.util.HashMap()
for field in in_doc:
#your code
Next step is to store your results in an object and output it:
wrapper['original'] = result
self.output.write(result, wrapper)
Make sure to indent your code properly.
I wish to create one NodeJS source file in a Jupyter notebook which is using the IJavascript kernel so that I can quickly debug my code. Once I have it working, I can then use the "Download As..." feature of Jupyter to save the notebook as a NodeJS script file.
I'd like to have the ability to selectively ignore / include code in the notebook source that will not execute when I run the generated NodeJS script file.
I have solved this problem for doing a similar thing for Python Jupyter notebooks because I can determine if the code is running in an interactive session (IPython [REPL]). I accomplished this by using this function in Python:
def is_interactive():
import __main__ as main
return not hasattr(main, '__file__')
(Thanks to Tell if Python is in interactive mode)
Is there a way to do a similar thing for NodeJS?
I don't know if this is the correct way but couldn't find anything else
basically if you
try {
const repl = __dirname
} catch (err) {
//code run if repl
}
it feels a little hacky but works ¯\_(ツ)_/¯
This may not help the OP in all cases, but could help others googling for this question. Sometimes it's enough to know if the script is running interactively or not (REPL and any program that is run from a shell).
In that case, you can check for whether standard output is a TTY:
process.stdout.isTTY
The fastest and most reliable route would just be to query the process arguments. From the NodeJS executable alone, there are two ways to launch the REPL. Either you do something like this without any script following the call to node.
node --experimental-modules ...
Or you force node into the REPL using interactive mode.
node -i ...
The option ending parameter added in v6.11.0 -- will never append arguments into the process.argv array unless it's executing in script mode; via FILE, -p, or -e. Any arguments meant for NodeJS will be filtered into the accompanying process.execArgv variable, so the only thing left in the process.argv array should be process.execPath. Under these circumstances, we can reduce the query to the solution below.
const isREPL = process.execArgv.includes("-i") || process.argv.length === 1;
console.log(isREPL ? "You're in the REPL" : "You're running a script m8");
This isn't the most robust method since any user can otherwise instantiate a REPL from an intiator script which your code could be ran by. For that I'm pretty sure you could use an artificial error to crawl the traceback and look for a REPL entry. Although I haven't the time to implement and ensure that solution at this time.
I would like to know, how would I, in Python, be able to ignore certain/all keypresses by the user while a certain function in the program is executing? Cross platform solutions are preferred, but if that is not possible, then I need to know how to do this on Macintosh. Any help is greatly appreciated! :)
EDIT: Right now, I am processing keypresses through the turtle module's onkey() function since I did create a program using turtle. I hope this helps avoid any confusion, and again, any help is greatly appreciated! :)
You might want to modify your question to show how you're currently processing key-presses. For example is this a command-line program and you're using curses?
You could use os.uname to return the os information or sys.platform, if that isn't available. The Python documentation for sys.platform indicates that 'darwin' is returned for OSX apple machines.
If the platform is darwin then you could, in your code, ignore whatever key-presses you want to.
Edit (Update due to changed question):
If you want to ignore key-presses when a certain function is being called you could either use a lock to stop the key-press function call and your particular function being executed together.
Here is an example of using a lock, this may not run, but it should give you a rough idea of what's required.
import _thread
a_lock = _thread.allocate_lock()
def certainFunction():
with a_lock:
print("Here's the code that you don't want to execute at the same time as onSpecificKeyCall()")
def onSpecificKeyCall():
with a_lock:
print("Here's the code that you don't want to execute at the same time as certainFunction()")
Or, depending on the circumstances, when the function which you don't want interrupting with a key press is called, you could call onkey() again, with the specific key to ignore, to call to a function that doesn't do anything. When your particular function has finished, you could call onkey() again to bind the key press to the function that processes the input.
I found similar problems, maybe it will help you with your problem:
globally capture, ignore and send keyevents with python xlib, recognize fake input
How do I 'lock the keyboard' to prevent any more keypresses being sent on X11/Linux/Gnome?
https://askubuntu.com/questions/160522/python-gtk-event-ignore
What I mean by this is:
I have a program. The end user is currently using it. I submit a new piece of source code and expect it to run as if it were always there?
I can't find an answer that specifically answers the point.
I'd like to be able to say, "extend" or add new features (rather than fix something that's already there on the fly) to the program without requiring a termination of the program (eg. Restart or exit).
Yes, you can definitely do that in python.
Although, it opens a security hole, so be very careful.
You can easily do this by setting up a "loader" class that can collect the source code you want it to use and then call the exec builtin function, just pass some python source code in and it will be evaluated.
Check the package
http://opensourcehacker.com/2011/11/08/sauna-reload-the-most-awesomely-named-python-package-ever/ . It allows to overcome certain raw edges of plain exec. Also it may be worth to check Dynamically reload a class definition in Python