Detect changes in an array and run command for new values - python

I have an array of IP's that changes from time to time and i want for every new IP that comes up to run a command.
The code I have is:
while (network.status!="connected"):
p=network.connections
for i in p:
print i.ip #checks the IP's in the array i
time.sleep(10)
So i want whenever there is a new value in the array i to run a specific command.
What's the most efficient way to do this in python.

Use a set and look at the difference in each loop:
old = set()
while network.status != "connected":
p = set(network.connections)
for i in p - old:
print i.ip # new ips that were added
for i in old - p:
print i.ip # old ips that were removed
old = p
time.sleep(10)

How about subclassing the list and connecting it to some handler?
Have a look here:
https://stackoverflow.com/a/12203829/1091116
What you want to do is to rename 'validate' and make it react to adding items in the list.

Related

I do not understand why this function reverses the string

This function requests a string input and reverses it. For some reason, I just cannot wrap my head around the logic behind it.
def reverse(s):
new = ""
for i in s:
print(new)
new = i + new
return new
oldStr = input("String?")
newStr = reverse(oldStr)
print(newStr)
print(reverse("good bye"))
A friend suggested I print the variable new in the string which I added and it helped a little, but I just don't understand it.
It looks to me as if you are in a stage where you want to learn how to debug small programs.
For questions on StackOverflow, you want to provide a minimal reproducible example. What does that mean in your case?
"repoducible" means that you should not depend on user input. Replace user input by hardcoded values.
"minimal" means that you don't call the function twice. Once is enough.
For that reason, I'll not walk you through your original program, but through this one instead:
def reverse(s):
new = ""
for i in s:
print(new)
new = i + new
return new
print(reverse("abcdef"))
I'll use a free program called PyCharm Community Edition. You set a breakpoint where you want to understand how things work. Since you don't understand the reverse() method, put it right at the beginning of that method. You do that by clicking between the line number and the text:
Even if your code has no bug, go to the Run/Debug menu:
Execution will stop at the breakpoint and you'll now be able to see all the variables and step through your code line by line.
Look at all the variables after each single line. Compare the values to what you think the values should be. If there is a mismatch, it's likely a misunderstanding on your side, not by Python. Do that a few times and it'll be obvious why and how the string is reversed.
Let analysis it:
Iteration 1:
new = 'A', i = g
Perform new = i + new : new = gA
Iteration 2:
new = gA, i = o
Perform new = i + new: new = ogA
.
.
.
This happens because we add new i before we add the existing string from previous iteration.
the key is in "new = i + new" note that new is the previous iteration character and is in the right side of the current character, this cause the string to reverse

How to achieve big growing Python lists backed by a file and not loaded into memory at any point

I have a python script that needs to maintain some values as list and append to the list every n seconds for an indefinite period until the user quits the script. I want the list to be file backed to which i can append without loading the list contents into memory, the only part that will be in memory will be the value that is to be appended.
I tried Shelve but after running some tests i found out that at some point of time i will have to have to load the existing persisted list into memory and append to it, with writeback = true, it keeps the whole file into memory and writes to file at the end only.
The script goes like this:-
d = shelve.open( reportDir+curDatName+ ( processName.rsplit('.', 1)[0] if processName.endswith('.exe') else processName ))
global counter
global startTime
d['CPU|'+pid] = []
d['RAM|'+pid] = []
d['THREADS|'+pid] = []
startTime = datetime.datetime.now()
while(not quit):
print('Took a snapshot')
counter = counter + 1
p = psutil.Process(int(pid))
list = d['CPU|'+pid]
print(list)
list.append(p.cpu_percent(0.1)/psutil.cpu_count(0.1))
d['CPU|'+pid] = list
print('CPU '+ str(p.cpu_percent(0.1)/psutil.cpu_count(0.1)))
list = d['RAM|'+pid]
list.append(p.memory_percent())
d['RAM|'+pid] = list
print('RAM '+ str(p.memory_percent()))
list = d['THREADS|'+pid]
list.append(p.num_threads())
d['THREADS|'+pid] = list
print('Threads- '+ str(p.num_threads()))
print(d['RAM|'+pid])
i=0
while(not quit and i < interval/chunkWait): #wait in chunks
i = i+1
time.sleep(chunkWait)
Is there any other package that can achieve the desired functionality for me?
You want to use a list, which is an in-memory data structure, to store data that is too big to fit conveniently in memory. You are asking for some package that will allow you to pretend that you are using a list when in fact you are dealing with a list-like interface that in actuality has a disk-based backing store. That would be convenient, and there is at least one first-class proprietary API that I know that does it, for the vendor's own database (so not generic). And no doubt someone somewhere has come up with a generic list-like interface to a database table, but that would simply be syntactic sugar. I suspect you are going to have to abandon your list approach and learn a database API. This is not a forum for such recommendations, but I think I won't get flamed or downvoted for saying that mysql is free and has a very good reputation.

Format the output data

I'm a novice in programming. Faced with such a problem. Are monitoring servers using Zabbix. It has its own API. The challenge is through a script in Python to connect to the monitor server and get information about printers and their counters and put in the file. The output file should have the format:
name printer \tab counter printer
Like that:
HP1212 124512
I connect and receive data, but cannot record it in two columns using a '\t'.
My code:
`
from pyzabbix import ZabbixAPI
zapi = ZabbixAPI("http://*****/zabbix")
zapi.login("******", "*******")
item_name='Print_counter'
hosts = zapi.host.get( #get printers name
groupids=8,
output=['name'])
items = zapi.item.get( #get printers counter
groupids=8,
output=['lastvalue'],
filter={'name':item_name})`
I understand that the problem is likely trivial, but how to solve I don't know.
I edited my question:
If im use:
for host in hosts:
a = host['name']
print a
.. I get:
tpr001
tpr002
...
tpr020
it my printers.
If i use:
for item in items:
b = host['value']
print b
I get:
12456
34645
...
56468
It counters off my printers.
I want to group the output of my query like this:
tpr001 12456
tpr002 34645
... ...
tpr020 56468
I think you need something like this :
for host in hosts:
a=host['name']
for item in items:
b=item['lastvalue']
print a,'\t',b`
I do not know what exactly is given by your zapi.host.get and zapi.item.get, but your loops dont work, as you expect.
In your first loop a gets a new value in each cycle so you find the last value in it, if the loop ends. And because of your print command after the loop you see exact that value.
Maybe you should put second loop into the first like
for host in hosts:
a=host['name']
for item in items:
b=item['lastvalue']
print a,'\t',b`
But in this case you would combine each row from hosts with each row from items.
Maybe your items.get- command needs the name es filter, something like
for host in hosts:
a=host['name']
items = zapi.item.get( #get printers counter
groupids=8,
output=['lastvalue'],
filter={'name':a})
Maybe you even do not need to ask for hosts, because all your information are inside items
for item in items:
b=item['lastvalue']
a=item['name']
print a,'\t',b
Hope, this helps, but I think you should learn about basics in programming, if you want to go further (and it is easier to understand, if you give speaking names instead of a and b, so not only we better understand, what you expect
It sounds strange to me, that you want to rely on Output order of two different lists. But if so, you could try
for i in range(len(Hosts)):
host = Hosts[i]
item = Items[i]
a=host['name']
b=item['lastvalue']
print a,'\t',b

Pass statement if previous magnet URL is the same

I'm writing a simple script in python 2.7 that receives multiple data sets every second over UDP. Then places each of these data sets into individual magnet URLs and opens them.
Many times, a data set can be the same as the previous one(s), and therefore I don't want to open the same magnet URL multiple times.
Here is a portion of my code:
while True:
var = s.recv(30)
url = "magnet://myhost.com/{0}".format(var)
os.startfile(url)
As an example, I can receive the following data sets:
a
a
a
b
b
a
a
e
e
e
Essentially, if two data sets are the same, then the same magnet URLs are produced. In the example above, I would like it to open the first magnet URL (a), but skip (pass) the next two a's. Then open the first b URL but skip the next b. If data set a is sent again, then open the first one but skip the following a's. So on and so forth.
I'm guessing that I could use an if/else and a pass statement for this, but I'm not sure how. Any ideas?
Ok, if you only need to skip a value if it is the same of the previous one, just use a simple variable to keep trace of it :
old = None
while True:
var = s.recv(30)
if var != old:
old = var
url = "magnet://myhost.com/{0}".format(var)
os.startfile(url)
You can construct a set of previously seen items:
seen = set()
while True:
var = s.recv(30)
if var not in seen:
url = "magnet://myhost.com/{0}".format(var)
os.startfile(url)
seen.add(var)

Help with Python loop weirdness?

I'm learning Python as my second programming language (my first real one if you don't count HTML/CSS/Javascript). I'm trying to build something useful as my first real application - an IRC bot that alerts people via SMS when certain things happen in the channel. Per a request by someone, I'm (trying) to build in scheduling preferences where people can choose not to get alerts from between hours X and Y of the day.
Anyways, here's the code I'm having trouble with:
db = open("db.csv")
for line in db:
row = line.split(",") # storing stuff in a CSV, reading out of it
recipient = row[0] # who the SMS is going to
s = row[1] # gets the first hour of the "no alert" time range
f = row[2] # gets last hour of above
nrt = [] # empty array that will store hours
curtime = time.strftime("%H") # current hour
if s == "no":
print "They always want alerts, sending email" # start time will = "no" if they always want alerts
# send mail code goes here
else:
for hour in range(int(s), int(f)): #takes start, end hours, loops through to get hours in between, stores them in the above list
nrt.append(hour)
if curtime in nrt: # best way I could find of doing this, probably a better way, like I said I'm new
print "They don't want an alert during the current hour, not sending" # <== what it says
else:
# they do want an alert during the current hour, send an email
# send mail code here
The only problem I'm having is somehow the script only ends up looping through one of the lines (or something like that) because I only get one result every time, even if I have more than one entry in the CSV file.
If this is a regular CSV file you should not try to parse it yourself. Use the standard library csv module.
Here is a short example from the docs:
import csv
reader = csv.reader(open("some.csv", "rb"))
for row in reader:
print row
There are at least two bugs in your program:
curtime = time.strftime("%H")
...
for hour in range(int(s), int(f)):
nrt.append(hour)
# this is an inefficient synonym for
# nrt = range(int(s), int(f))
if curtime in nrt:
...
First, curtime is a string, whereas nrt is a list of integers. Python is strongly typed, so the two are not interchangeable, and won't compare equal:
'4' == 4 # False
'4' in [3, 4, 5] # False
This revised code addresses that issue, and is also more efficient than generating a list and searching for the current hour in it:
cur_hour = time.localtime().tm_hour
if int(s) <= cur_hour < int(f):
# You can "chain" comparison operators in Python
# so that a op1 b op2 c is equivalent to a op1 b and b op2c
...
A second issue that the above does not address is that your program will not behave properly if the hours wrap around midnight (e.g. s = 22 and f = 8).
Neither of these problems are necessarily related to "the script only ends up looping through one of the lines", but you haven't given us enough information to figure out why that might be. A more useful way to ask questions is to post a brief but complete code snippet that shows the behavior you are observing, along with sample input and the resulting error messages, if any (along with traceback).
Have you tried something more simple? Just to see how your file is actually read by Python:
db = open("db.csv")
for line in db:
print line
There can be problem with format of your csv-file. That happens, for instance, when you open Unix file in Windows environment. In that case the whole file looks like single string as Windows and Unix have different line separators. So, I don't know certain cause of your problem, but offer to think in that direction.
Update:
Your have multiple ways through the body of your loop:
when s is "no": "They always want alerts, sending email" will be printed.
when s is not "no" and curtime in nrt: "They don't want an alert during the current hour, not sending" will be printed.
when s is not "no" and curtime in nrt is false (the last else): nothing will be printed and no other action undertaken.
Shouldn't you place some print statement in the last else branch?
Also, what is exact output of your snippet? Is it "They always want alerts, sending email"?
I would check the logic in your conditionals. You looping construct should work.
You could go thro an existing well written IRC bot in Python Download
Be explicit with what's in a row. Using 0, 1, 2...n is actually your bug, and it makes code very hard to read in the future for yourself or others. So let's use the handy tuple to show what we're expecting from a row. This sort of works like code as documentation
db = open("db.csv")
for line in db.readlines():
recipient, start_hour, end_hour = line.split(",")
nrt = []
etc...
This shows the reader of your code what you're expecting a line to contain, and it would have shown your bug to you the first time you ran it :)

Categories