python 2.7.5: run a whole function in background - background-process

I am a beginner with python. I want to run a whole function in the background (because it can take a while or even fail).
Here is the function:
def backup(str):
command = barman_bin + " backup " + str
log_maif.info("Lancement d'un backup full:")
log_maif.info(command)
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = p.communicate()
if p.returncode == 0:
for line in output[0].decode(encoding='utf-8').split('\n'):
log_maif.info(line)
else:
for line in output[0].decode(encoding='utf-8').split('\n'):
log_maif.error(line)
log_maif.info("Fin du backup full")
return output
I want to run this function in the background into a loop :
for host in list_hosts_sans_doublon:
backup(host) # <-- how to run the whole function in background ?
In ksh, I would have written something like backup $host & with backup a function that takes $host as an argument.

What you are looking for is to run the function in a different thread from what I understand. For this you need to use python thread module.
This is how you start a thread:
import threading
def backup(mystring):
print(mystring)
host="hello"
x = threading.Thread(target=backup, [host])
x.start()
Do what ever you want after this and the thread will run separately.

Related

Execute custom command in awesomewm tooltip

I have a simple widget to display free memory:
myFreeMemory = awful.widget.watch('bash -c "free -h | awk \'/^Mem:/ {print $3}\'"', 1)
This line produces a single number.
I would like to create a tooltip for it that runs a custom command:
local free_memory_tooltip = awful.tooltip
{
objects = { myFreeMemory },
timer_function = function()
return "free -h"
end,
font = "monaco 18",
timeout=0,
opacity=0.9,
bg="#000000",
fg="#ffffff",
align="top_left"
}
Instead of return "free -h", what should I put to execute this command and return the textual output?
Simplest solution might be to use return io.popen("free -h"):read("*a"), but this uses io.popen which one best avoids in AwesomeWM.
Best solution might be to write a parser for /proc/meminfo yourself. Yuck.
Intermediate solution would be something like the following:
local last_result = ""
local function my_timer_function()
local cmd = "free -h | awk '/^Mem:/ {print $3}'""
awful.spawn.easy_async_with_shell(cmd, function(result)
last_result = result
free_memory_tooltip:set_markup(last_result)
end)
return last_result
end
-- Call it once to initialise its state; otherwise you would get a brief flicker of empty text
my_timer_function()

Workaround for case-sensitive input to dir

I am using Octave 5.1.0 on Windows 10 (x64). I am parsing a series of directories looking for an Excel spreadsheet in each directory with "logbook" in its filename. The problem is these files are created by hand and the filenaming isn't consistent: sometimes it's "LogBook", other times it's "logbook", etc...
It looks like the string passed as input to the dir function is case-sensitive so if I don't have the correct case, dir returns an empty struct. Currently, I am using the following workaround, but I wondered if there was a better way of doing this (for a start I haven't captured all possible upper/lower case combinations):
logbook = dir('*LogBook.xls*');
if isempty(logbook)
logbook = dir('*logbook.xls*');
if isempty(logbook)
logbook = dir('*Logbook.xls*');
if isempty(logbook)
logbook = dir('*logBook.xls*');
if isempty(logbook)
error(['Could not find logbook spreadsheet in ' dir_name '.'])
end
end
end
end
You need to get the list of filenames (either via readdir, dir, ls), and then search for the string in that list. If you use readdir, it can be done like this:
[files, err, msg] = readdir ('.'); # read current directory
if (err != 0)
error ("failed to readdir (error code %d): %s", msg);
endif
logbook_indices = find (cellfun (#any, regexpi (files, 'logbook'));
logbook_filenames = files(logbook_indices);
A much less standard approach could be:
glob ('*[lL][oO][gG][bB][oO][kK]*')

How to trigger operator inside Python function using Airflow?

I have the following code:
def chunck_import(**kwargs):
...
for i in range(1, num_pages + 1):
start = lower + chunks * i
end = start + chunks
if i>1:
start = start + 1
logging.info(start, end)
if end > max_current:
end = max_current
where = 'where orders_id between {0} and {1}'.format(start,end)
logging.info(where)
import_orders_products_op = MySqlToGoogleCloudStorageOperator(
task_id='import_orders_and_upload_to_storage_orders_products_{}'.format(i),
mysql_conn_id='mysql_con',
google_cloud_storage_conn_id='gcp_con',
provide_context=True,
approx_max_file_size_bytes = 100000000, #100MB per file
sql = 'import_orders.sql',
params={'WHERE': where},
bucket=GCS_BUCKET_ID,
filename=file_name_orders_products,
dag=dag)
start_task_op = DummyOperator(task_id='start_task', dag=dag)
chunck_import_op = PythonOperator(
task_id='chunck_import',
provide_context=True,
python_callable=chunck_import,
dag=dag)
start_task_op >> chunck_import_op
This code uses PythonOperator to calculate how many runs I need from the MySqlToGoogleCloudStorageOperator and create the WHERE cluster of the SQL then it needs to execute it.
The problem is that the MySqlToGoogleCloudStorageOperator isn't being executed.
I can't actually do
chunck_import_op >> import_orders_products_op
How can I make the MySqlToGoogleCloudStorageOperator be executed inside the PythonOperator?
I think at the end of your for loop, you'll want to call import_orders_products_op.execute(context=kwargs) possibly preceded by import_orders_products_op.pre_execute(context=kwargs). This is a bit complicated in that it skips the render_templates() call of the task_instance, and actually if you instead made a task_instance to put each of these tasks in, you could call run or _raw_run_task instead but these both require information from the dagrun (which you can get in the python callable's context like kwargs['dag_run'])
Looking at what you've passed to the operators it looks like as is you'll need the templating step to load the import_orders.sql file and fill in the WHERE parameter. Alternatively it's okay within the callable itself to load the file into a string, replace the {{ params.WHERE }} part (and any others) manually without Jinja2 (or you could spend time to figure out the right jinja2 calls), and then set the import_orders_products_op.sql=the_string_you_loaded before calling import_orders_products_op.pre_execute(context=kwargs) and import_orders_products_op.execute(context=kwargs).

Simplifying device creation in sip.conf

I often have to define many similar devices in sip.conf like this:
[device](!)
; setting some parameters
[device01](device)
callerid=dev01 <01>
[device02](device)
callerid=dev02 <02>
; ...
[deviceXX](device)
callerid=devXX <XX>
The question is perhaps I could avoid setting device-name specific parameters by using some variable like following?
[device](!)
callerid=dev${DEVICE_NAME:-2} <${DEVICE_NAME:-2}>
; setting some parameters
[device01](device)
[device02](device)
; ...
[deviceXX](device)
P.S.
It would be perfect, if there was some device constructor, so I could reduce the script to following, but, I think, that is not possible in Asterisk.
[device](!)
callerid=dev${DEVICE_NAME:-2} <${DEVICE_NAME:-2}>
; setting some parameters
;[device${MAGIC_LOOP(1,XX,leading_zeroes)}](device)
I've had good results writing a small program that takes care of it. It checks for a line saying something like
------- Automatically generated -------
and whatever is after that line, it's going to be regenerated as soon as it detects that there are new values for it (it could be from a database or from a text file). Then, I run it with supervisor and it checks every XX seconds if there are changes.
If there are changes, it issues a sip reload command after updating the sip.conf file
I wrote it in python, but whatever language you feel comfortable with should work just fine.
That's how I managed that and has been working fine so far (after a couple of months). I'd be extremely interested in learning about other approaches though. It's basically this (called from another script with supervisor):
users = get_users_logic()
#get the data that will me used on the sip.conf file
data_to_be_hashed = reduce(lambda x, y: x + y, map(lambda x: x['username'] + x['password'] + x['company_prefix'], users))
m = hashlib.md5()
m.update(str(data_to_be_hashed).encode("ascii"))
new_md5 = m.hexdigest()
last_md5 = None
try:
file = open(os.path.dirname(os.path.realpath(__file__)) + '/lastMd5.txt', 'r')
last_md5 = file.read().rstrip()
file.close()
except:
pass
# if it changed...
if new_md5 != last_md5:
#needs update
with open(settings['asterisk']['path_to_sip_conf'], 'r') as file:
sip_content = file.read().rstrip()
parts = sip_content.split(";-------------- BEYOND THIS POINT IT IS AUTO GENERATED --------------;")
sip_content = parts[0].rstrip()
sip_content += "\n\n;-------------- BEYOND THIS POINT IT IS AUTO GENERATED --------------;\n\n"
for user in users:
m = hashlib.md5()
m.update(("%s:sip.ellauri.it:%s" % (user['username'], user['password'])).encode("ascii"))
md5secret = m.hexdigest()
sip_content += "[%s]\ntype = friend\ncontext = %sLocal\nmd5secret = %s\nhost = dynamic\n\n" % (
user['username'], user['company_prefix'], md5secret)
#write the sip.conf file
f = open(settings['asterisk']['path_to_sip_conf'], 'w')
print(sip_content, file=f)
f.close()
subprocess.call('asterisk -x "sip reload"', shell=True)
#write the new md5
f = open(os.path.dirname(os.path.realpath(__file__)) + '/lastMd5.txt', 'w')
print(new_md5, file=f)
f.close()

Why does the "command" directly open and not when clicked on Button? Python 3

I pretty new in this whole Python thing and my question is how to make, that a button runs the command, when clicking it and not before.
I searched much in the Internet but i didnt find anything.
I dont understand the classes at all. Is there no other way to do this?
Here is my work, i did on the programm.
Thanks for your help
from tkinter import *
import os
t = ""
def ordner(x):
print ("def")
if os.path.exists(os.path.join("/Kunden/",x)) == True:
pass
else:
os.mkdir(os.path.join("/Kunden/",x))
def E1holen():
x = E1.get()
ordner(x)
#Hauptfenster
main=Tk(className='Kundendatenbank')
main.iconbitmap('icon.ico')
#Inhalt Hauptfenster
L1 = Label(main, text="Kundenname:")
L1.pack(side = LEFT)
E1 = Entry(main, bd =5, textvariable=t)
E1.pack(side = RIGHT)
a = Button (main, text=("erstellen/bearbeiten"), command=E1holen()).pack()
main.mainloop()
It runs immediately ecause you tell it to.
What is the syntax for calling a function in Python? It's foo(), right? So, when you do command=E1holen(), what should python do? It should call E1holen(), and then pass the result to the command attribute.
Put another way, the command attribute takes a reference to a function, but because of the () you were calling the function and giving the command attribute whatever that function returned. The solution? Remove the ():
a = Button(..., command=E1holen)

Resources