Get a list of subnets matching a given CIDR - python

I'm trying to take a known subnet ID and CIDR mask, e.g., 10.0.0.0/22, and get a list like this:
[('10.0.0.0', '10.0.3.255'),
('10.0.4.0', '10.0.7.255'),
...
('10.255.252.0', '10.255.255.255')]
I've tried a few existing modules like ipcalc, but it doesn't seem to have a feature like that. I'm not sure what kind of math is necessary for me to write my own module to do it, either.

You can use ipaddress module if you use Python 3.3+:
>>> import ipaddress
>>> it = ipaddress.ip_network('10.0.0.0/8').subnets(new_prefix=22)
>>> networks = [(str(n.network_address), str(n.broadcast_address)) for n in it]
>>> len(networks)
16384
>>> networks[0]
('10.0.0.0', '10.0.3.255')
>>> networks[-1]
('10.255.252.0', '10.255.255.255')
In Python 2.x, use ipaddr:
>>> import ipaddr
>>> it = ipaddr.IPNetwork('10.0.0.0/8').subnet(new_prefix=22)
>>> networks = [(str(n.network), str(n.broadcast)) for n in it]
>>> len(networks)
16384
>>> networks[0]
('10.0.0.0', '10.0.3.255')
>>> networks[-1]
('10.255.252.0', '10.255.255.255')
UPDATE
There's Python 2.7 backport of Python 3.3 ipaddress: py2-ipaddress.

Use the new ipaddress module in Python 3.3:
import ipaddress
for i in ipaddress.ip_network('10.0.0.0/8').subnets(new_prefix=22):
print(i)

Related

Best implementation of dual-side dict in Python

I mean a dictionary where of you could get the value by key or the key by value depending on what you need.
You could use bidict package which provides a bidirectional map. The syntax looks as follows (taken from the documentation):
>>> from bidict import bidict
>>> element_by_symbol = bidict(H='hydrogen')
>>> element_by_symbol
bidict({'H': 'hydrogen'})
>>> element_by_symbol['H']
'hydrogen'
>>> element_by_symbol.inv
bidict({'hydrogen': 'H'})
>>> element_by_symbol.inv['hydrogen']
'H'
>>> element_by_symbol.inv.inv is element_by_symbol
True
Or you can implement it yourself, for example using one of the solutions provided here.

extract list or tuple inside string

I am getting input from an external device connected via Ethernet, and it is passing several values of string type e.g. value = '(2,2)\n'. I would like to assign these values to a list or tuple variable e.g. final_value = (2,2).
The code I am using is the following:
import socket
sock = socket.socket()
value =sock.recv(buffersize=2048)
formatted_value = eval(value)
I read that the eval function I am using at this moment to get the list is not a very safe approach, as the external device could pass a dangerous script. So, I would like to know if there is any alternative, similar to the function int(), which can be used to get an integer from a string.
Use ast module literal_eval method for a safer eval
import ast
formatted_value = ast.literal_eval(value)
If you know the input contains a tuple
from ast import literal_eval as make_tuple
make_tuple(value)
Well to give the alternative approach you can do.
s = '(2, 2)\n'
s = s.strip()
if s.startswith('(') and s.endswith(')'):
tup = tuple(int(i) for i in s[1:-1].split(','))
print(tup)
Or if you want a list
s = '(2, 2)\n'
s = s.strip()
if s.startswith('(') and s.endswith(')'):
lst = [int(i) for i in s[1:-1].split(',')]
print(lst)

How to convert this string to Unix time?

How to convert this string to Unix time?
t = '20160224122738'
I can write a function to do this, but wanted to know if there was an already-existing simple method that I could use.
An easy way that comes to mind would be:
>>> import time
>>> import datetime
>>> t = '20160224122738'
>>> time.mktime(datetime.datetime.strptime(t, "%Y%m%d%H%M%S").timetuple())
1456309658.0
Try this,
>>> import datetime
>>> t = '20160224122738'
>>> int(datetime.datetime.strptime(t, '%Y%m%d%H%M%S').strftime("%s"))
1456297058

Why doesn't **kwargs interpolate with python ConfigObj?

I'm using ConfigObj in python with Template-style interpolation. Unwrapping my config dictionary via ** doesn't seem to do interpolation. Is this a feature or a bug? Any nice workarounds?
$ cat my.conf
foo = /test
bar = $foo/directory
>>> import configobj
>>> config = configobj.ConfigObj('my.conf', interpolation='Template')
>>> config['bar']
'/test/directory'
>>> '{bar}'.format(**config)
'$foo/directory'
I'd expect the second line to be /test/directory. Why doesn't interpolation work with **kwargs?
When unpacking the keyword argument, then a new object is created: of type dict. This dictionary contains the the raw-values of the configuration (no interpolation)
Demonstration:
>>> id(config)
31143152
>>> def showKeywordArgs(**kwargs):
... print(kwargs, type(kwargs), id(kwargs))
...
>>> showKeywordArgs(**config)
({'foo': '/test', 'bar': '$foo/directory'}, <type 'dict'>, 35738944)
To resolve your problem you could create an expanded version of your configuration like this:
>>> expandedConfig = {k: config[k] for k in config}
>>> '{bar}'.format(**expandedConfig)
'/test/directory'
Another more elegant way is to simply avoid unpacking: This can be achieved by using the function string.Formatter.vformat:
import string
fmt = string.Formatter()
fmt.vformat("{bar}", None, config)
I have had a similar problem.
A workaround is to use configobj's function ".dict()". This works because configobj returns a real dictionary, which Python knows how to unpack.
Your example becomes:
>>> import configobj
>>> config = configobj.ConfigObj('my.conf', interpolation='Template')
>>> config['bar']
'/test/directory'
>>> '{bar}'.format(**config.dict())
'/test/directory'

Convert an IPv4 range (start and end) to slash notation in Python?

Is there a script available to convert a starting and ending IP address to a slash notation?
Example:
>>> ip_long = '10.182.71.0-10.182.75.255'
>>> convert_to_slash(ip_long)
10.182.71.0/24, 10.182.72.0/22
Use summarize_address_range() from ipaddress, which is part of the Python 3 standard library (and backported to Python 2).
>>> import ipaddress
>>> first = ipaddress.IPv4Address('10.182.71.0')
>>> last = ipaddress.IPv4Address('10.182.75.255')
>>> summary = ipaddress.summarize_address_range(first, last)
>>> list(summary)
[IPv4Network('10.182.71.0/24'), IPv4Network('10.182.72.0/22')]
Google's ipaddr-py library has a method called summarize_address_range(first, last).
summarize_address_range(first, last):
"""Summarize a network range given the first and last IP addresses.
Example:
>>> summarize_address_range(IPv4Address('1.1.1.0'),
IPv4Address('1.1.1.130'))
[IPv4Network('1.1.1.0/25'), IPv4Network('1.1.1.128/31'),
IPv4Network('1.1.1.130/32')]
Args:
first: the first IPv4Address or IPv6Address in the range.
last: the last IPv4Address or IPv6Address in the range.
Returns:
The address range collapsed to a list of IPv4Network's or
IPv6Network's.
Raise:
TypeError:
If the first and last objects are not IP addresses.
If the first and last objects are not the same version.
ValueError:
If the last object is not greater than the first.
If the version is not 4 or 6.
"""
Another solution:
from ipaddress import IPv4Address, summarize_address_range
a=" ".join(map(str, summarize_address_range(IPv4Address('8.8.8.8'), IPv4Address('8.8.9.1'))))
print(a)

Categories

Resources