threading not update module time - python-3.x

i'm new to python and i wrote a simple code just to run in sequence time and send email when is trigger.
i use threading timer for counting and import outbound.py (with import datetime) just to clean up the main scrip so it will not have email scrip in main.py. however when the first email received, the message time reflect correctly but the next email remain the same time from first email.
below is the main.py scrip
import threading
from outbound import outbound
def run ():
threading.Timer(10,run).start()
outbound()
run()
outbound.py scrip
from datetime import datetime
now=datetime.now()
dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
def outbound():
print (dt_string)

You created dt_string when you imported the module, and never updated it again. Move the string initialization into the function body.
def outbound():
dt_string = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
print (dt_string)

Related

Launching parallel tasks: Subprocess output triggers function asynchronously

The example I will describe here is purely conceptual so I'm not interested in solving this actual problem.
What I need to accomplish is to be able to asynchronously run a function based on a continuous output of a subprocess command, in this case, the windows ping yahoo.com -t command and based on the time value from the replies I want to trigger the startme function. Now inside this function, there will be some more processing done, including some database and/or network-related calls so basically I/O processing.
My best bet would be that I should use Threading but for some reason, I can't get this to work as intended. Here is what I have tried so far:
First of all I tried the old way of using Threads like this:
import subprocess
import re
import asyncio
import time
import threading
def startme(mytime: int):
print(f"Mytime {mytime} was started!")
time.sleep(mytime) ## including more long operation functions here such as database calls and even some time.sleep() - if possible
print(f"Mytime {mytime} finished!")
myproc = subprocess.Popen(['ping', 'yahoo.com', '-t'], shell=True, stdout=subprocess.PIPE)
def main():
while True:
output = myproc.stdout.readline()
if myproc.poll() is not None:
break
myoutput = output.strip().decode(encoding="UTF-8")
print(myoutput)
mytime = re.findall("(?<=time\=)(.*)(?=ms\s)", myoutput)
try:
mytime = int(mytime[0])
if mytime < 197:
# startme(int(mytime[0]))
p1 = threading.Thread(target=startme(mytime), daemon=True)
# p1 = threading.Thread(target=startme(mytime)) # tried with and without the daemon
p1.start()
# p1.join()
except:
pass
main()
But right after startme() fire for the first time, the pings stop showing and they are waiting for the startme.time.sleep() to finish.
I did manage to get this working using the concurrent.futures's ThreadPoolExecutor but when tried to replace the time.sleep() with the actual database query I found out that my startme() function will never complete so no Mytime xxx finished! message is ever shown nor any database entry is being made.
import sqlite3
import subprocess
import re
import asyncio
import time
# import threading
# import multiprocessing
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import ProcessPoolExecutor
conn = sqlite3.connect('test.db')
c = conn.cursor()
c.execute(
'''CREATE TABLE IF NOT EXISTS mytable (id INTEGER PRIMARY KEY, u1, u2, u3, u4)''')
def startme(mytime: int):
print(f"Mytime {mytime} was started!")
# time.sleep(mytime) ## including more long operation functions here such as database calls and even some time.sleep() - if possible
c.execute("INSERT INTO mytable VALUES (null, ?, ?, ?, ?)",(1,2,3,mytime))
conn.commit()
print(f"Mytime {mytime} finished!")
myproc = subprocess.Popen(['ping', 'yahoo.com', '-t'], shell=True, stdout=subprocess.PIPE)
def main():
while True:
output = myproc.stdout.readline()
myoutput = output.strip().decode(encoding="UTF-8")
print(myoutput)
mytime = re.findall("(?<=time\=)(.*)(?=ms\s)", myoutput)
try:
mytime = int(mytime[0])
if mytime < 197:
print(f"The time {mytime} is low enought to call startme()" )
executor = ThreadPoolExecutor()
# executor = ProcessPoolExecutor() # I did tried using process even if it's not a CPU-related issue
executor.submit(startme, mytime)
except:
pass
main()
I did try using asyncio but I soon realized this is not the case but I'm wondering if I should try aiosqlite
I also thought about using asyncio.create_subprocess_shell and run both as parallel subprocesses but can't think of a way to wait for a certain string from the ping command that would trigger the second script.
Please note that I don't really need a return from the startme() function and the ping command example is conceptually derived from the mitmproxy's mitmdump output command.
The first code wasn't working as I did a stupid mistake when creating the thread so p1 = threading.Thread(target=startme(mytime)) does not take the function with its arguments but separately like this p1 = threading.Thread(target=startme, args=(mytime,))
The reason why I could not get the SQL insert statement to work in my second code was this error:
SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 10688 and this is thread id 17964
that I didn't saw until I wrapped my SQL statement into a try/except and captured the error. So I needed to make the SQL database connection inside my startme() function
The other asyncio stuff was just nonsense and cannot be applied to the current issue here.

How to make share path monitoring script to generate outlook email alert if no movement appears in shard path after 20 minutes?

Greetings!! I am trying using below watchdog module to monitor a shared path that works fine but I am not getting the idea to
generate outlook email alert, after the time span of 20 minutes if no
modification or update happening to the specified path. Below is the
code:
import os
import sys
import time
import logging
from watchdog.observers import Observer
from watchdog.events import LoggingEventHandler
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
os.system('//fleet.ad/data/Data4/VMSSHARE/its/DOCS')
print("found")
# Defining your own path
path = "//bleet.ad/data/Data4/VMSSHARE/its/DOCS"
print("found")
# Initilaize logging event handler
event_handler = LoggingEventHandler()
# Initialize Observer
observer = Observer()
observer.schedule(event_handler, path, recursive=True)
# Start the observer
observer.start()
try:
while True:
# set the thread sleep time
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
However, tried this piece of code to receive outlook email alerts, but not sure how to make it work with above script:
import os
import smtplib
import requests
EMAIL_ADDRESS = os.environ.get('USER_ID')
EMAIL_PASSWORD = os.environ.get('USER_PASSWORD')
r = requests.get("https://fleet.my.salesforce.com", timeout=5)
#if r.status_code!= 200:
with smtplib.SMTP('smtp.office365.com', 587) as smtp:
smtp.ehlo()
smtp.starttls()
smtp.ehlo()
smtp.login(EMAIL_ADDRESS, EMAIL_PASSWORD)
subject = 'ALARM: MAPILab is stuck from copying Public folders to destination'
body = 'Make sure server is restarted and it is backed up'
msg = f'Subject:{subject}\n\n{body}'
smtp.sendmail(EMAIL_ADDRESS, 'ryadav#elementcorp.com', msg)
Challenge for me is :
r = requests.get("https://fleet.my.salesforce.com", timeout=5)
Instead of website monitor , how should I ask to look for the code output?
You have to attach methods to your event handler, like this:
my_event_handler.on_created = on_created
my_event_handler.on_deleted = on_deleted
my_event_handler.on_modified = on_modified
my_event_handler.on_moved = on_moved
where the methods look like:
def on_created(event):
print(f"{event.src_path} has been created!")
as described in this blog post: http://thepythoncorner.com/dev/how-to-create-a-watchdog-in-python-to-look-for-filesystem-changes/
Have your handlers update a last_changed timestamp variable whenever there is a change. (Since all your handlers do the same thing regardless of what the change was, you could get away with just defining one handler method, maybe call it on_any_change and attach it to all 4 handler methods. Oh look, the watchdog docs show that there is an on_any_event method, so you could just hook into that.)
Then in your while True loop, if the current time - last_changed is greater than your threshold, send the email.

Telethon events in multithreading not working as expected

I wanted to run Telethon events in multi thread, multithreading.
For the following code, what I expected is multi thread, cocurrent independent events. await asyncio.sleep( 3 ) will sleep 3 seconds. So If you send any text on telegram to the account, it will wait 3 seconds and send me back "hi.". I expected that if I send a text for several times at once, let's say 5 times, it should wait for approximately 3 seconds and send me "hi" back at once, but not like wait for 3 seconds, send "hi.", wait for 3 seconds, send "hi." .. for 5 times and takes approximately 15 seconds. This is not what I expected for.
So, How can I modify the code to run the code as expected? Or it's impossible in telethon?
I read google, stackoverflow, github issue, but couldn't find a solution by myself. So I want your help here. Thank you.
import time
from pathlib import Path
import re
import random
import asyncio
from telethon import TelegramClient, events
from telethon.sessions import StringSession
from telethon import utils
import logging
logging.basicConfig(level=logging.ERROR)
api_id = ""
api_hash = ''
phone = ''
string = Path('./string').read_text()
message = "hi."
if __name__ == '__main__':
client = TelegramClient(StringSession(string), api_id, api_hash, sequential_updates=True)
#client.on(events.NewMessage(incoming=True))
async def handle_new_message(event):
print('message:', event.message.message)
# // not working here, the sleep blocks next events but not only current event.
print('wait for 3 seconds...')
await asyncio.sleep( 3 )
await event.respond(message)
print('Auto-replying...')
client.start(phone)
client.run_until_disconnected()
# client.loop.run_forever()
# string = StringSession.save(client.session)
# Path('./string').write_text(string)
You are using sequential_updates so until the first update is not completed it will not move to other update. I guess you need to turn off sequential updates.

How to make python script update in realtime (run continuously)

Hello I am a beginner in python and I just learned the fundamentals and basics of programming in python. I wanted to make this program that will notify me when my class ends, however, once I run my program it only executes it once
When I loop it, it does not continuously access my date and time (instead it takes the time from when the code is executed). Any suggestion on how to resolve this problem?
import win10toast
import datetime
currentDT = datetime.datetime.now()
toaster = win10toast.ToastNotifier()
while (1):
def Period_A():
if currentDT.hour == 7 and currentDT.minute == 30:
toaster.show_toast('Shedule Reminder', 'It is Period A time!', duration=10)
I wanted the code to run in the background and update the value of the date and time continuously so that the notification will appear on the desired time not the time when the code is executed ;).
The line currentDT = datetime.datetime.now() is only called once throughout the whole program, and therefore stays constant to approximately the time you ran the script.
Since you're want to continuously check the time to compare it to a set time, you'll have to move that line to inside the loop.
Secondly, you define a function Period_A in the loop, which by itself does nothing because you don't call the function. If you don't need the abstraction a function gives you, there is no point in making one just to call it once.
import datetime
import win10toast
toaster = win10toast.ToastNotifier()
while 1:
currentDT = datetime.datetime.now()
if currentDT.hour == 7 and currentDT.minute == 30:
toaster.show_toast('Shedule Reminder', 'It is Period A time!', duration=10)

Python while True preventing previous code execution

I'm building a telegram bot using telepot(python) and a weird thing happened:
since the bot is supposed to keep running, I've set a
while 1:
time.sleep(.3)
at the end of my bot, right after I define how to handle the MessageLoop.
The bot has some print() to assert that the bot is setting up (or better, that it's setting up the message handler) and that it is reading the chat, waiting for any input.
The problem is that if I run the code without the
while 1:
time.sleep(.3)
it prints the messages and stops the execution (not having a loop to wait for new input), but if I add the while 1: (...) the code stops before being able to print anything.
Here's the code:
"""Launch the bot."""
import json
import telepot
from telepot.loop import MessageLoop
import time
from base import splitter
from base import handler
messageHandler = handler.Handler()
with open('triggers.json') as f:
triggers = json.load(f)
with open('config.json') as f:
config = json.load(f)
botKey = config['BOT_KEY']
# define the bot and the botname
bot = telepot.Bot(botKey)
botName = bot.getMe()['username']
# split commands in arrays ordered by priority
configSplitter = splitter.Splitter()
triggers = configSplitter.splitByPriority(triggers)
# define the handler
messageHandler.setBotname(botName)
messageHandler.setMessages(triggers)
# handle the messageLoop
print("setting up the bot...")
MessageLoop(bot, messageHandler.handle).run_as_thread()
print("Multibot is listening!")
# loop to catch all the messages
while 1:
time.sleep(.3)
Python version: 3.6 32-bit
The solution was to add sys.stdout.flush() after the various print()to restore the functionality of print(), while in order to make the code work again i had to change the telepot function
MessageLoop(bot, messageHandler.handle).run_as_thread()
which wasn't working properly to:
bot.message_loop(messageHandler.handle)

Resources