I know that I can use email.utils.parseaddr to parse out an email address properly, even a tricksy one:
>>> parseaddr('Bad Horse <bad.horse#example(no one expects the #-ish inquisition!).com')
('Bad Horse (no one expects the #-ish inquisition!)', 'bad.horse#example.com')
(So good, Python! So good!)
However, that's just a string:
>>> type(parseaddr('Bad Horse <bad.horse#example(no one expects the #-ish inquisition!).com')[-1])
<class 'str'>
In the typical case I can just do .rsplit('#', maxsplit=1)[-1] to get the domain. But what if I'm just sending local mail without a domain?
>>> parseaddr('Wayne <wayne>')[-1].rsplit('#', maxsplit=1)[-1]
'wayne'
That's not quite what I want - I'd prefer maybe None or 'localhost'.
Does anything like that come in Python's included batteries?
I haven't been able to find anything yet, so my current approach is to make a slight adjustment:
try:
domain = parseaddr('Wayne <wayne>')[-1].rsplit('#', maxsplit=1)[1]
except IndexError:
# There was no '#' in the email address
domain = None # or 'localhost'
In the absence of a better way, this works and gets me what I need.
I have managed to compile two lists of IP addresses. used and unused ips as such
unused_ips = ['172.16.100.0/32', '172.16.100.1/32', '172.16.100.2/32', '172.16.100.3/32', '172.16.100.4/32', '172.16.100.5/32', '172.16.100.6/32', '172.16.100.7/32', '172.16.100.8/32', '172.16.100.9/32'...]
used_ips = ['172.16.100.1/32','172.16.100.33/32']
what I want to be able to do now is compare these lists and return the next free IP. in the above example the next ip would be 172.16.100.2/32, until it handed out all of those from 1 to 32 then it would hand out 34.
im not sure where to begin with this, I can convert these to IPv4Network objects if there is something built in for this but I couldn't find anything in documentation
Thanks
I'd keep a set of ipaddress objects and manipulate them to allocate and de-allocate the addresses, like so:
import ipaddress
def massage_ip_lists():
global unused_ips, used_ips
unused_ips = set(ipaddress.ip_address(ip.replace('/32', ''))
for ip in unused_ips)
used_ips = set(ipaddress.ip_address(ip.replace('/32', ''))
for ip in used_ips)
def allocate_next_ip():
new_ip = min(unused_ips - used_ips)
used_ips.add(new_ip)
return new_ip
unused_ips = [
'172.16.100.0/32',
'172.16.100.1/32',
'172.16.100.2/32',
'172.16.100.3/32',
'172.16.100.4/32',
'172.16.100.5/32',
'172.16.100.6/32',
'172.16.100.7/32',
'172.16.100.8/32',
'172.16.100.9/32']
used_ips = ['172.16.100.1/32', '172.16.100.33/32']
massage_ip_lists()
print(allocate_next_ip())
print(allocate_next_ip())
Note:
/32 is a nomenclature for IP networks, not IP hosts.
ipaddress objects are comparable, so functions like min() work on them.
172.16.100.0 is a perfectly valid IP address, depending upon the netmask. If you don't want to allocate it, either keep it out of unused_ips, or make the program aware of the netmask in use.
You want ips that are in unused but not used:
available_ips = [ip for ip in unused_ips if ip not in used_ips]
You want to sort them to get the one that's closest to zero. Naive sorting will not work as you have strings; 172.16.xxx.xxx is sorted higher than 172.100.xxx.xxx for example. You can convert the IPs into lists of numbers to sort them correctly.
import re
available_ips = sorted(available_ips, key=lambda ip: (int(n) for n in re.split(r'[./]', ip)))
If you're just trying to iterate through a list of the available ips, you could do something like this:
# Filter unavailable ips from the list of all ips
available_ips = set(unused_ips) - set(used_ips)
# Iterate through list of available ips
for ip in available_ips:
print(ip) # Or whatever you want to do with the next available ip
I want to write a short script using python that read my ip address conversely , so when I write 127.0.0.1 I should find as a result 1.0.0.127.
any help please
Try this
ip = '127.0.0.1'
ip = ip.split('.')
ip.reverse()
print('.'.join(ip))
If you want to preserve the original ip. it's very easy since strings are immutable in python assign it to a new variable and just call reversed on it instead of calling the list's reverse() so you don't alter the list also (if you want that)
ip = '127.0.0.1'
new = ip.split('.')
new = reversed(new)
print('.'.join(new))
print(ip)
You can use this :
def reverseIP(ip):
ip = ip.split(".")
ip.reverse()
return '.'.join(ip)
Example :
print(reverseIP("127.0.0.1")) # Prints 1.0.0.127
I want to ssh to another node on my network as part of a larger python script, I am using pexpect which works when I do something like this:
session=spawn('ssh root#172.16.210.254')
I want to replace the address with a variable so I can cycle through addresses in a list however when I try:
address = "172.16.210.253"
session=spawn('ssh root#'address)
It doesn't work as using address in this way is invalid syntax. What is the correct syntax for this?
session=spawn('ssh root#' + address) to concatenate the strings
I am writing a simple client and server and want to introduce some simple bounds checking to insure the IP address entered by a user is in the correct format i.e.(int.int.int.int), does anybody have any suggestions as to hwo this can be done at the moment my code just accepts the value and will throw an OS error if its invalid. But I want to stop a user being able to enter anything in here.
def ipEntered():
global ipEntered
ipEntered = input("Please enter the ip address of the server you wish to connect with:")
Thanks
Use the ipaddress module (introduced in Python 3.3):
import ipaddress
def ipEntered():
while True:
try:
val = input("Please enter the ip address of the server you wish to connect with:")
return ipaddress.ip_address(val)
except ValueError:
print("Not a valid IP address")
which will accept IPv4 addresses of the form "100.200.30.40", e.g. a dotted quad, and IPv6 addresses in both longhand form (8 groups of 4 hexadecimal characters separated by :) and shorthand forms.
If you only want to accept IPv4 addresses, use return ipaddress.IPv4Address(val) instead.