Python 3 - IPAddress check - python

New to python but trying to write something that will check a user entered IP against a CIDR to see which CIDR the IP is within if any... but getting some sort of str version error that makes little sense...
import ipaddress
ip2check = input("Enter IP Address:")
blocks = ['192.1.1.1/8', '0.0.0.0/16']
n = 1
print('Scanning through', len(blocks), 'CIDR blocks')
for x in blocks:
print('Checking', blocks[n])
breakpoint()
if ip2check in ipaddress.IPv4Network(blocks[n]):
print("IP is found in CIDR: ", blocks[n])
else:
print("IP not found in", blocks[n])
Error:
line 11, in
/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/codecs.py(309)init()
-> def init(self, errors='strict')
or maybe its:
AttributeError: 'str' object has no attribute '_version'

Well, you are trying to check the membership of the objec IPv4Network, if you check the overriden contains
import ipaddress
import inspect
lines = inspect.getsource(ipaddress.IPv4Network.__contains__)
You get
def __contains__(self, other):
# always false if one is v4 and the other is v6.
if self._version != other._version:
return False
# dealing with another network.
if isinstance(other, _BaseNetwork):
return False
# dealing with another address
else:
# address
return (int(self.network_address) <= int(other._ip) <=
int(self.broadcast_address))
This means that the object is checking whether the two objects you are comparing have the same version, network type.. etc but what you are doing is comparing a string with a IPv4Network, the piece in contains checks the versioning with self._version which the string object does not have, hence the error of 'string object does not have self._version'
In resume: You are comparing an string object with a IPv4Network object which you cannot do.

Related

I receive to many DNA objects in my read DNA function

class DnaSeq:
def __init__(self, accession, seq):
self.accession = accession
self.seq = seq
def __len__(self):
if self.seq == None:
raise ValueError
elif self.seq =='':
raise ValueError
else:
return len(self.seq)
def __str__(self):
if self.accession =='':
raise ValueError
elif self.accession == None:
raise ValueError
else:
return f"<DnaSeq accession='{self.accession}'>"
def read_dna(filename):
DnaSeq_objects = []
new_dna_seq = DnaSeq("s1", "AAA")
with open(filename, 'r') as seq:
for line in seq.readlines():
if line.startswith('>'):
new_dna_seq.accession = line
else:
new_dna_seq.seq = line.strip()
DnaSeq_objects.append(new_dna_seq)
return DnaSeq_objects
this is the .fa file I tried to read
> s0
> ATGTTTGTTTTTCTTGTTTTATTGCCACTAGTCTCTAGTCAGTGT GTTAATCTTACAACCAGAACTCAAT
> s1
> GTTAATCTTACAACCAGAACTCAATTACCCCCTGCATACACTAATTCTTTCACACGTGGTGTTTATTACCCTGACAAAGTTTTCAGATCCTCAGTTTTACATTCAACTCAGGACTTGTTCTTACCTTTCTTTTCCAATGTTACTTGGTTCCATGCTATACATGTC
> s2
> ACTCAGGACTTGTTCTTACCTTTCTTTTCCAATGTTACTTGGTTCCATGCTATACATGTCTCTGGGACCAATGGTACTAAGAGGTTTGATAACCCTGTCCTAC
> s3
> TCTGGGACCAATGGTACTAAGAGGTTTGATAACCCTGTCCTACCATTTAATGATGGTGTTTATTTTGCTTCCACTGAGAAGTCTAACATAATAAGAGGCTGGATTTTTGGTACTACTTTAGATTCGAAGACCCAGTCCCT
> s4
> AGACCCAGTCCCTACTTATTGTTAATAACGCTACTAATGTTGTTATTAAAGTCTGTGAATTTCAATTTTGTAATGATCCATTT
> s5
> TTTGTAATGATCCATTTTTGGGTGTTTATTACCACAAAAACAACAAAAGTTGGATGGAAAGTGAGTTCAGAGTTTATTCTAGTGCGA
It's supposed to return 6 DNA objects but I received too many.
read_dna('ex1.fa')
[<__main__.DnaSeq object at 0x000001C67208F820>,
<__main__.DnaSeq object at 0x000001C67208F820>,
<__main__.DnaSeq object at 0x000001C67208F820>,
<__main__.DnaSeq object at 0x000001C67208F820>,
<__main__.DnaSeq object at 0x000001C67208F820>,
<__main__.DnaSeq object at 0x000001C67208F820>,
<__main__.DnaSeq object at 0x000001C67208F820>,
<__main__.DnaSeq object at 0x000001C67208F820>,
<__main__.DnaSeq object at 0x000001C67208F820>,
<__main__.DnaSeq object at 0x000001C67208F820>,
<__main__.DnaSeq object at 0x000001C67208F820>,
<__main__.DnaSeq object at 0x000001C67208F820>
]
How can I fix this, so that it receives the right amount
Your code is reading every line beginning with > as an accession, but it's not populating the .seq attribute because it's not finding any sequences. In the FASTA format, only the header/description/accession ID line begins with >. The sequence line(s) don't have any prefix, they're just single-letter bases or amino acids.
There's actually a lot more you need to do. You need to have a default value for self.seq, you need to parse the sequences for spaces and other irrelevant characters, and you need to be able to concatenate multiple sequence lines. Instead of rolling your own code, I highly recommend checking out Biopython.
I decided to give you some example code that will help you on your way, using a couple of neat Python constructs to condense things down a bit and clean up your original code. Please don't use this exact code as your assignment! It may contain concepts that you haven't learned about yet, or that you don't fully understand, and your professor will quickly be able to see it's not your original work. Play around with the code, make sure you understand what it does, try to think of any edge cases where it might not work as expected (such as having an accession without a sequence, or having a sequence spread over multiple lines). Then, come up with your own algorithm and submit that.
class DnaSeq:
def __init__(self, accession, seq):
self.accession = accession
self.seq = seq
def __len__(self):
if self.seq:
return len(self.seq)
else:
raise ValueError("Sequence missing")
def __repr__(self):
if self.accession and self.seq:
return f"<DnaSeq accession='{self.accession}', seq='{self.seq[:15]}...'>"
else:
raise ValueError("Accession ID or sequence missing")
def read_dna(filename):
DnaSeq_objects = []
with open(filename, 'r') as f:
# get rid of any whitespace on either end of the line
contents = [line.strip() for line in f.readlines()]
while len(contents): # while there are lines left to process
if len(contents[0]) == 0: # there was just whitespace and now it's an empty string
contents.pop(0) # pull the first item off the list
continue # go to the next line in the list
# no point in creating dummy values when we can use the real thing
new_dna_seq = DnaSeq(contents.pop(0).lstrip("> "), contents.pop(0))
DnaSeq_objects.append(new_dna_seq)
return DnaSeq_objects
results = [str(seq_obj) for seq_obj in read_dna("ex1.fa")]
print("\n".join(results))
# "<DnaSeq accession='s0', seq='ATGTTTGTTTTTC...'>",
# "<DnaSeq accession='s1', seq='GTTAATCTTACAA...'>",
# "<DnaSeq accession='s2', seq='ACTCAGGACTTGT...'>",
# "<DnaSeq accession='s3', seq='TCTGGGACCAATG...'>",
# "<DnaSeq accession='s4', seq='AGACCCAGTCCCT...'>",
# "<DnaSeq accession='s5', seq='TTTGTAATGATCC...'>"
In Your Loop You Should change The condition:
for line in seq.readlines():
if line.startswith('>'):
new_dna_seq.accession = line
else:
new_dna_seq.seq = line.strip()
DnaSeq_objects.append(new_dna_seq)
To:
for line in seq.readlines():
if line.startswith('> s'):
new_dna_seq.accession = line.strip().replace('> ', '')
else:
new_dna_seq.seq = line.strip().replace('> ', '')
DnaSeq_objects.append(new_dna_seq)
in Your, if statement checks if the line starts with '> s' and indent the object appending within the else block.
I have also removed'>', from your accession and sequence as That seems unnecessary.
since DnaSeq_objects is a list, just return DnaSeq_objects[:6]. Even if the list contains less than 6 elements, this syntax will not throw an error and will just return all elements

Python class and objects within another function

I’m trying to learn how to utilize class and objects within my Python code. I'm totally overwhelmed by the fact that is is suppose to be a begginingers class and I got this assignment where if something like this:
Class name is IPAdress and there I want properties IP, hostname, ASN and ISP. Also, it has a method which creates similar print like this:
IP: 85.76.129.254
Hostname: 85-76-129-254-nat.elisa-mobile.fi
ASN: 719
ISP: Elisa Mobile
Method can be named as PrintDetails.
Once the class is ready, I want to use it within my Osio9 function as following
Function asks user to input IP, hostname, ASN and ISP. Object is created according to this information.
Object is added to list (initially empty) and information is printed by using the PrintDetails -method
After this user is asked if he/she wants to create a new IP and if answer is yes -> repeat the above process (ask for input), add the new object to a list and print all information from the list with PrintDetails
After input, the list is looped through and it calls each IPAddress object with PrintDetails -method. (Print can look like the example above)
If user doesn’t want to continue inputting IP-addresses, exit the function
I have no clue how to proceed and answer I receive from my teacher is to look from google so here I am.
class IPAddress: ##define class
def __init__(self, IP, hostname, ASN, ISP):
self.ip = ip
self.hostname = hostname
self.asn = asn
self.isp = isp
def PrintDetails(self): ## construction method
print("IP-address: " + str(self.ip) + " | Hostname: " + str(self.hostname) + " | ASN: " + str(self.asn) + "ISP: " + str(self.isp))
def Osio9():
addresses = []
while(true):
ip = str (input("Enter IP address: ")) #ask for user input
hostname = str (input("Enter Hostname: "))
asn = str (input("Enter ASN: "))
isp = str (input("Enter ISP: "))
address = IPAddress
address.isp = isp
addresses.append(address)
for IPAddress in addresses:
IPAddress.PrintDetails(self)
# continueInput = str (input("Do you want to add more IP-addresses (y/n): "))
# if (continueInput == "y"):
# return addresses
#
# else break
I just saw your last update and there are some good ideas in it. Here is one version of the program, which does not completely correspond to your assignment as the main execution is not within a loop but in a if __name__ == '__main__': statement which will execute only when the program is called directly, and not when it is imported or when function part of this program are imported. I highly encourage you to try a small part of the code, one at a time, and then to adapt it to your specific need.
Let's go piece by piece:
#%% Definition of IPAddress
class IPAddress:
def __init__(self, ip, hostname, asn, isp):
self.ip = ip
self.hostname = hostname
self.asn = asn
self.isp = isp
def prettyprint(self):
str2print = f' | IP: {self.ip}\n' +\
f' | Hostname: {self.hostname}\n' +\
f' | ASN: {self.asn}\n' +\
f' | ISP: {self.isp}\n'
print (str2print)
def __key(self):
"""
key method to uniquely identify an object IPAddress.
I defined it as a tuple of the 4 main attributes, but if one of them is
unique it could be directly used as a key.
"""
return (self.ip, self.hostname, self.asn, self.isp)
def __eq__(self, other):
""" == comparison method."""
return isinstance(self, type(other)) and self.__key() == other.__key()
def __ne__(self, other):
""" != comparison method."""
return not self.__eq__(other)
def __hash__(self):
"""Makes the object hashable. Sets can now be used on IPAddress."""
return hash(self.__key())
I am using spyder as an IDE, and the symbol #%% creates sections of code, very similar to matlab, which can be executed in the current console by doing Right-Click -> Run Cell.
I changed the print function to make it more explicit. Strings object can be denoted by 3 symbols: 'str', "str", """str""". Additionnaly, a flag in front can change the behavior of the string. The most usefull ones are f and r.
Formatting a string with either .format() method or the f flag.
value = 1
str1 = 'string to format with value v = {}'.format(value)
str2 = f'string to format with value v = {value}'
You can print both string to see that they are equivalent. The flag f is similar to a .format() call. It allows the element within the brackets {} to be executed before the print. It is especially usefull when you format a string with multiple values.
v1 = 1
v2 = 2
str1 = 'string to format with value v = {} and {}'.format(v1, v2)
str2 = f'string to format with value v = {v1} and {v2}'
I still chose to split the sring into 4 strings and to add them together for a cleaner look of the code. The backslash \ at the end of each line allows python to consider the current line and the next one as the same line. It's a line-split character.
N.B: If you want to know what the flag r does, look into the escape character ;) r flag is especially usefull when working with paths.
Objects can be compared together. For instace, if you try 5==3, python will return False because the integer object 5 is different from the integer object 3. You can implement the == and != method in any object/class you develop. To do so, I first define a unique key for this object in the function __key(). Then the function __eq__ implements == and returns True if both objects compared are created from the same class and have the same key. The method __ne__ implements != and returns True if __eq__ is not True.
N.B: I also added the hash method to make the object hashable. Once the key is define, creating a hash is trivial, since the idea is to be able to uniquely identify each object, which is also done by the key. This definition allows the use of sets, for instance to check if a list has multiple occurence of the same object.
def add_IPAddress(ListOfIPAddresses, IPAddress):
"""
Function adding IPAddress to ListOfIPAddresses if IPAddress is not already
in ListOfIPAddresses.
"""
if IPAddress not in ListOfIPAddresses:
ListOfIPAddresses.append(IPAddress)
print ('IP Address appended:')
IPAddress.prettyprint()
def input_IPAddress():
"""
Ask a user input to create an IPAddress object.
"""
ip = input("Enter IP address: ")
hostname = input("Enter Hostname: ")
asn = input("Enter ASN: ")
isp = input("Enter ISP: ")
return IPAddress(ip, hostname, asn, isp)
Then I splitted the input from the user and the addition to a list of objects into 2 different functions. The function input() already returns a string, thus I removed the str() call to convert.
N.B: Watchout when asking users to input numbers, usually you forget that the input is a string and then your code raises an error because you forget to convert the string to integer or float.
Improvements: I didn't do it here, but usually when using user input, you have to check if the input given is correct. Some simple syntax checks (e.g. the number of '.' characters in the ipadress) can already improve the robustness of a piece of code. You could also use regular expressions with regex to check if the input is conform.
The query_yes_no() is a clean yes/no util which I copied from somewhere.. I usually place it in a util module: folder within the environment path named util with a __init__.py file. More information if you look into the creation of python module.
#%% Main
if __name__ == '__main__':
ListOfIPAddresses = list()
while True:
if not query_yes_no('Do you want to input IP Address?'):
break
ListOfIPAddresses.append(input_IPAddress())
for ipaddress in ListOfIPAddresses:
ipaddress.prettyprint()
print ('--------------------------') # Just pretting a separator
Finally, in the main part, an infinite while loop is broke only if the user replies no (or any of the other negative keyworkds defined in query_yes_no()). Until it is broken, the user will be asked to add a new IPAddress to the list ListOfIPAddresses which will be added if it is not already present inside.
Full code snippet:
# -*- coding: utf-8 -*-
import sys
#%% Definition of IPAddress
class IPAddress:
def __init__(self, ip, hostname, asn, isp):
self.ip = ip
self.hostname = hostname
self.asn = asn
self.isp = isp
def prettyprint(self):
str2print = f' | IP: {self.ip}\n' +\
f' | Hostname: {self.hostname}\n' +\
f' | ASN: {self.asn}\n' +\
f' | ISP: {self.isp}\n'
print (str2print)
def __key(self):
"""
key method to uniquely identify an object IPAddress.
I defined it as a tuple of the 4 main attributes, but if one of them is
unique it could be directly used as a key.
"""
return (self.ip, self.hostname, self.asn, self.isp)
def __eq__(self, other):
""" == comparison method."""
return isinstance(self, type(other)) and self.__key() == other.__key()
def __ne__(self, other):
""" != comparison method."""
return not self.__eq__(other)
def __hash__(self):
"""Makes the object hashable. Sets can now be used on IPAddress."""
return hash(self.__key())
#%% Functions
def add_IPAddress(ListOfIPAddresses, IPAddress):
"""
Function adding IPAddress to ListOfIPAddresses if IPAddress is not already
in ListOfIPAddresses.
"""
if IPAddress not in ListOfIPAddresses:
ListOfIPAddresses.append(IPAddress)
print ('IP Address appended:')
IPAddress.prettyprint()
def input_IPAddress():
"""
Ask a user input to create an IPAddress object.
"""
ip = input("Enter IP address: ")
hostname = input("Enter Hostname: ")
asn = input("Enter ASN: ")
isp = input("Enter ISP: ")
return IPAddress(ip, hostname, asn, isp)
#%% Util
def query_yes_no(question, default="yes"):
"""Ask a yes/no question via raw_input() and return their answer.
"question" is a string that is presented to the user.
"default" is the presumed answer if the user just hits <Enter>.
It must be "yes" (the default), "no" or None (meaning
an answer is required of the user).
The "answer" return value is True for "yes" or False for "no".
"""
valid = {"yes": True, "y": True, "ye": True,
"no": False, "n": False}
if default is None:
prompt = " [y/n] "
elif default == "yes":
prompt = " [Y/n] "
elif default == "no":
prompt = " [y/N] "
else:
raise ValueError("invalid default answer: '%s'" % default)
while True:
sys.stdout.write(question + prompt)
choice = input().lower()
if default is not None and choice == '':
return valid[default]
elif choice in valid:
return valid[choice]
else:
sys.stdout.write("Please respond with 'yes' or 'no' "
"(or 'y' or 'n').\n")
#%% Main
if __name__ == '__main__':
ListOfIPAddresses = list()
while True:
if not query_yes_no('Do you want to input IP Address?'):
break
ListOfIPAddresses.append(input_IPAddress())
for ipaddress in ListOfIPAddresses:
ipaddress.prettyprint()
print ('--------------------------') # Just pretting a separator

Strange result when binding Tab to readline.completion in Python 3.8

I am running Ubuntu 20.4 w/ Python 3.8.2 and coming across a strange behavior with the readline interface in Python.
My target is to provide an input facility that allows at a given location on the terminal to choose from a list of given strings, or - alternatively - simply inputting a desired string. My code does work (almost), until for some reasons for certain strings the result gets corrupted.
My code looks like this
import readline
class __readlineCompleter(object):
"""
Cycles through a list of potential strings the user might want to enter
"""
def __init__(self, options):
self.options = list(options) #sorted([item for item in options])
self.index = 0
return
def complete(self, text, state):
if state == 0:
if text and not text in self.options:
self.options.append(text)
self.index += 1
if self.index >= len(self.options):
self.index = 0
return self.options[self.index]
else:
return None
def input_at(x_pos, y_pos, _text, _prefill, _choices):
"""
positions the cursor at x_pos, y_pos, prints text if given and reads a string from stdin
#param x_pos(int): row to print at
#param y_pos(int): columns to print at
#param _text(string): text to print before the input field
#param _prefill(string): text as default input
#param _choices(list): list of strings as proposed input values
#return: (string): input given by user, or False
"""
_myPrompt = "\033[{};{}H{}\033[0m".format(x_pos, y_pos, _text)
if type(_choices) in (set, list) and len(_choices):
_choices = set([x for x in _choices])
readline.set_completer(__readlineCompleter(_choices).complete)
readline.set_completer_delims('')
readline.parse_and_bind('tab: menu-complete')
try:
_input = input(_myPrompt)
except KeyboardInterrupt as EOFError:
_input = False
return _input
As I said this works pretty well, once pressing TAB the user gets presented a different option from _choices, pressing Enter returns the chosen entry. Alternatively the user can enter a string manually. So this was what I intended, until it comes to certain strings; so when I call above code like this
_temp = [ 'Julius Papp', 'J‐Live', 'Mr. Electric Triangle', 'MullerAnustus Maximilian']
_result = input_at(15, 0, "Name: ", _temp[0], _temp)
The cli looks like this (after each line I pressed Tab and the next line shows the output)
Name:
Name: Julius Papp
Name: J-Live
Name: Mr. Electric Triangle
Name: MullerAnustus Maximilian
Name: MullerAnustJulius Papp
***********
(I inserted the stars in the latter output to show the "wrong" display)
So somehow the final attempt destroyed the linebuffer; any subsequent Tab works as expected. Nevertheless the resulting _input is a valid member of _choices, so this only seems to be a displaying issue.
Does anyone have an idea why the string MullerAnustus Maximilian behaves this strange?
I solved this issue myself, by using the rl 2.4 – GNU Readline Bindings library.

Python: Using try/except in function and return value to list

I have a small function to loop a list of ipaddresses and do a dns lookup on them.
def lookup(addr):
try:
x = socket.gethostbyaddr(addr)
return
except socket.herror:
x = addr
print (addr, "not found")
return None
However insted of just printing the ipaddresses with missing dns record i want to save them to a list. But when i try to return a value on the socket.herror i get "NameError: name 'missing' is not defined" when trying to access it in anyway.
def lookup(addr):
try:
x = socket.gethostbyaddr(addr)
return
except socket.herror:
x = addr
print (addr, "not found")
return missing
I have not really find a similar example of this type of function so maybe i have missunderstod the use of try/except?
You are never defining "missing" as a variable before trying to return it.The other issue you have is that you are trying to return nothing or return something, so you'll have to build logic on the outside that isn't included here to make it work.
Consider this (similar) approach which takes the whole input list and just returns a list with the missing addresses:
def find_missing(addr_list):
missing = []
for addr in addr_list:
try:
x = socket.gethostbyaddr(addr)
except socket.herror:
missing.append(addr)
return missing

Work around python's json module not liking circular references

Other than using an external library (like maybe jsonpickle, though I haven't tried it), is there a way to get python's json module to dump a dictionary (or list, etc) that has circular references (just dropping the reference, that is)?
I only want to use json to more easily see some debug output.
Well, avoiding anything but standard modules, here's one solution which utilizes repr for handling the circular references. EDIT: For the latest, see all-purpose function for dumping any python thing in a mostly-readable manner (aka dump)
# MAGIC-NUMBER: max length is just some guess at a reasonable size, e.g. 80 cols by 100 lines
def dump(value, msg='DUMP', max_length=80 * 100, stdout=False, pick=None):
"""
Write as verbose of a description of the value as possible to logging.DEBUG.
See http://stackoverflow.com/q/27830888/116891
:param value: The item of interest.
:type value: object
:param msg: Prefix for the logged item (default='DUMP')
:type msg: basestring
:param max_length: Longest allowed string length (set to None for unlimited)
:type max_length: int
:param stdout: If true, print instead of logging (default=False)
:type stdout: bool
:param pick: If specified, dump only values for these keys of the item
(value must be a dict or allow __dict__ access).
The name comes from http://underscorejs.org/#pick.
:type pick: iterable of basestring
:return: True if message dumped
:rtype: bool
"""
if not logging.getLogger().isEnabledFor(logging.DEBUG) and not stdout:
return
if pick:
d = value if isinstance(value, dict) else value.__dict__
filtered = {
property_name: d[property_name]
for property_name in pick
if property_name in d
}
value = filtered
kwargs = dict(indent=2, sort_keys=True)
try:
import json
info = json.dumps(value, **kwargs)
except:
# JSON doesn't like circular references :/
try:
string_repr = repr(value)
# Replace python primitives, single-quotes, unicode, etc
string_repr = string_repr\
.replace('None', 'null')\
.replace('True', 'true')\
.replace('False', 'false')\
.replace("u'", "'")\
.replace("'", '"')
# Replace object and function repr's like <MyObject ...>
string_repr = re.sub(r':(\s+)(<[^>]+>)', r':\1"\2"', string_repr)
# Replace tuples with lists, very naively
string_repr = string_repr.replace('(', '[').replace(')', ']')
info = json.dumps(json.loads(string_repr), **kwargs)
except:
from pprint import pformat
info = pformat(value, indent=2)
def _out(formatted_string, *format_args):
"""Format the string and output it to the correct location."""
if stdout:
print(formatted_string % format_args)
else:
logging.debug(formatted_string, *format_args)
if max_length is None or len(info) <= max_length:
_out('%s: %s', msg, info)
return True
else:
_out(
'Did not dump "%s" due to length restriction. Increase max_length if desired.', msg
)
return False

Categories

Resources