sanketsudake / ifconfig-parser

Parse ifconfig output collected from local/remote server and retrieve values with goodies

Home Page:https://pypi.python.org/pypi/ifparser/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

AttributeError: can't set attribute

akr8986 opened this issue · comments

I am using python version 3.5

$ python --version
Python 3.5.1

I am facing the below error when i am importing the ifparser package i am seeing an attribute error:

In [1]: from ifparser import Ifcfg
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-1-e4742fe46d86> in <module>()
----> 1 from ifparser import Ifcfg

/*****/site-packages/ifparser/__init__.py in <module>()
----> 1 from .ifconfig import Ifcfg, Interface
      2
      3 __title__ = 'ifparser'
      4 __version__ = '0.5.0'
      5 __author__ = 'Sanket Sudake'

/******/site-packages/ifparser/ifconfig.py in <module>()
     51
     52
---> 53 class Ifcfg(object):
     54     scanner = Scanner([
     55         ('process_interface', r"(?P<interface>^[a-zA-Z0-9:-]+)\s+"

/******/site-packages/ifparser/ifconfig.py in Ifcfg()
     67          ".*?mtu (?P<mtu>[0-9]+).*"),
     68         ('process_ignore', r"(Ifconfig|Infiniband|Because)\s.*"),
---> 69         ('process_ignore', r"\s+.*"),
     70     ])
     71

/***********/site-packages/ifparser/re_scan.py in __init__(self, rules, flags)
     99         pattern = Pattern()
    100         pattern.flags = flags
--> 101         pattern.groups = len(rules) + 1
    102         _og = pattern.opengroup
    103         pattern.opengroup = lambda n: _og(n and '%s\x00%s' % (name, n) or n)

AttributeError: can't set attribute

@akr8986 Currently python 3 support is not completely added. I am planning to add it.

The issue seems to be with re_scan.py file.. The pattern object doesnt allow to set the value of groups variable..It auto-populates the variable value during execution.. i tried removing the line and executing the script.. it works fine... Not sure if its the right fix though!!

I have tried it earlier. Test didn't pass. I am exploring it. Let me know if all tests pass with your solution.

GIT DIFF:

git diff ifparser/re_scan.py
diff --git a/ifparser/re_scan.py b/ifparser/re_scan.py
index 4085365..ce9ba7f 100644
--- a/ifparser/re_scan.py
+++ b/ifparser/re_scan.py
@@ -98,7 +98,6 @@ class Scanner(object):
     def __init__(self, rules, flags=0):
         pattern = Pattern()
         pattern.flags = flags
-        pattern.groups = len(rules) + 1
         _og = pattern.opengroup
         pattern.opengroup = lambda n: _og(n and '%s\x00%s' % (name, n) or n)

UT Result:

Results (1.82s):
2 passed
5 failed

     - /phaedrus/home/abaskaran/Py3rdParty/ifconfig-parser/ifparser/ifconfig.py:136: KeyError: 'vcsbr'
     - /phaedrus/home/abaskaran/Py3rdParty/ifconfig-parser/ifparser/ifconfig.py:136: KeyError: 'p1p1'
     - /phaedrus/home/abaskaran/Py3rdParty/ifconfig-parser/tests/test_ifcfg_parser.py:77: IndexError: list index out of range
     - /phaedrus/home/abaskaran/Py3rdParty/ifconfig-parser/tests/test_ifcfg_parser.py:71: AssertionError: dict_keys(['lo        Link encap:Local Lo[128 chars]  ']) != ['lo', 'docker0', 'eth0']
     - /phaedrus/home/abaskaran/Py3rdParty/ifconfig-parser/tests/test_ifcfg_parser.py:97: AssertionError: dict_keys(['lo', 'eth0', 'wlan0']) != ['lo', 'wlan0', 'eth0']

The last assert seems wrong to me.. since both of them have same elements but only in a different order. am not sure about the other errors!

Thanks for pointing out and debugging. I have updated interfaces property to return sorted list instead of directly returning from dictionary keys list. With it 2 testcases are fixed. I also focusing on rest to include python 3 support. Temporarily I am setting pattern groups len for python 2 only.

The last assert seems wrong to me.. since both of them have same elements but only in a different order. am not sure about the other errors!

There are few more things for which support has to be added..

  1. i see some more flags for the interfaces in my machines : 'PROMISC', 'NOARP', 'SIMPLEX',. These flags have to be added in the _flags forzenset.

  2. Support for IPV6:

     inet 10.31.96.29  netmask 255.255.255.0  broadcast 10.31.96.255
     inet6 fe80::20c:29ff:fe91:a979  prefixlen 64  scopeid 0x20<link>
     ether <.........>  txqueuelen 1000  (Ethernet)
    
  3. I have a ifconfig ouput where the RX and TX bytes are not parsed from the output.

    RX packets 198237  bytes 283303360 (270.1 MiB)
    RX errors 0  dropped 0  overruns 0  frame 0
    TX packets 21948  bytes 2979032 (2.8 MiB)
    TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    The current regExp doesnt take care of packets and bytes info present in the same line..
    
  4. A format of ifconfig doesnt seem to be handled:

eth0      Link encap:Ethernet  HWaddr <dummy_val>
          inet addr:10.31.96.30  Bcast:10.31.96.255  Mask:255.255.255.0
          inet6 addr: fe80::20c:29ff:fecc:1ede/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:330418 errors:0 dropped:0 overruns:0 frame:0
          TX packets:38340 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:464157333 (442.6 MiB)  TX bytes:6906511 (6.5 MiB)

eth1      Link encap:Ethernet  HWaddr <dummy_val>
          inet addr:2.0.0.3  Bcast:2.255.255.255  Mask:255.0.0.0
          inet6 addr: fe80::20c:29ff:fecc:1ee8/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:28041 errors:0 dropped:0 overruns:0 frame:0
          TX packets:37411 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:7572430 (7.2 MiB)  TX bytes:8171676 (7.7 MiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:3617825 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3617825 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:778195827 (742.1 MiB)  TX bytes:778195827 (742.1 MiB)

For inet6 i defined a new method:

    def process_ipV6(self, group, groupdict, matched_str):
        if 'inet6 addr:' in matched_str:
            splitStr = matched_str.strip().lower().replace('inet6 addr:',
                                                           'ipv6').split()
            setattr(self._interfaces[self.curr_interface], 'ipv6', splitStr[1])
        else:
            map_dict = {'inet6': 'ipv6', 'prefixlen': 'prefix', 'scopeid': 'scope'}
            kv = iter(matched_str.split())
            for k, v in zip(kv, kv):
                groupdict[map_dict[k]] = v
            self.set_curr_interface_attr(groupdict)

For other two issues i did not see any other way other than creating new methods and new set of RegExp..

After modification my RegExp list fed to Scanner class is below:

    scanner = Scanner([
        ('process_interface', r"(?P<interface>^[a-zA-Z0-9:-]+)\s+"
         "Link encap:(?P<itype>[A-Za-z]+)"
         "((?:Loopback)|(?:HWaddr\s(?P<hwaddr>[0-9A-Fa-f:]+))).*"),
        ('process_any', r"\s+ether\s(?P<hwaddr>[0-9A-Fa-f:]+).*"),
        ('process_ip', r"\s+inet[\s:].*"),
        ('process_ipV6', r"\s+inet6[\s:].*"),
        ('process_mtu', r"\s+(?P<states>[A-Z\s]+\s*)+MTU:(?P<mtu>[0-9]+).*"),
        ('process_any', r"\s+RX bytes:(?P<rxbytes>\d+).*?"),
        ('process_any', r"\s+TX bytes:(?P<txbytes>\d+).*?"),
        ('process_any', r"\s+RX packets:(?P<rxpkts>\d+).*"),
        ('process_any', r"\s+TX packets:(?P<txpkts>\d+).*"),
        ('process_RxTx', r"\s+RX packets\s(?P<rxpkts>\d+)\s+bytes\s(?P<rxbytes>\d+).*"),
        ('process_RxTx', r"\s+TX packets\s(?P<txpkts>\d+)\s+bytes\s(?P<txbytes>\d+).*"),
        ('process_interface2',
         r"(?P<interface>^[a-zA-Z0-9-]+).*?<(?P<states>[A-Z,]+\s*)>"
         ".*?mtu (?P<mtu>[0-9]+).*"),
        ('process_interface3', r"(?P<interface>^[a-zA-Z0-9:-]+)\s+"
         "Link encap:(?P<itype>.*)$"),
        ('process_ignore', r"(Ifconfig|Infiniband|Because)\s.*"),
        ('process_ignore', r"\s+.*"),
    ])

process_RxTx method is simple..


    def process_RxTx(self, group, groupdict, matched_str):
        self.set_curr_interface_attr(groupdict)

and process_interface3 is just a copy of process_interface2.. i had to create a new method since Scanner class was cribbing about having same name (which is our func ptr)..

  1. i see some more flags for the interfaces in my machines : 'PROMISC', 'NOARP', 'SIMPLEX',. These flags have to be added in the _flags forzenset.

Mostly I have added things as I found them, I havn't referred ifconfig(net-tools) source as such. Might have missed these flags. Of course, we can add as we explore.

  1. Support for IPV6:

     inet 10.31.96.29  netmask 255.255.255.0  broadcast 10.31.96.255
     inet6 fe80::20c:29ff:fe91:a979  prefixlen 64  scopeid 0x20<link>
     ether <.........>  txqueuelen 1000  (Ethernet)
    

As you have worked out we can add ipv6 support. Though will need to add testcases around this.

  1. I have a ifconfig ouput where the RX and TX bytes are not parsed from the output.

    RX packets 198237  bytes 283303360 (270.1 MiB)
    RX errors 0  dropped 0  overruns 0  frame 0
    TX packets 21948  bytes 2979032 (2.8 MiB)
    TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    The current regExp doesnt take care of packets and bytes info present in the same line..
    

We can merge following regexes as there is only difference of optional ':' character.

        ('process_any', r"\s+RX packets:(?P<rxpkts>\d+).*"),
        ('process_any', r"\s+TX packets:(?P<txpkts>\d+).*"),
        ('process_RxTx', r"\s+RX packets\s(?P<rxpkts>\d+)\s+bytes\s(?P<rxbytes>\d+).*"),
        ('process_RxTx', r"\s+TX packets\s(?P<txpkts>\d+)\s+bytes\s(?P<txbytes>\d+).*"),

Also you don't need to define separate process_RxTx method as it does same work as process_any, so you can keep process_any as handler for regex.

  1. A format of ifconfig doesn't seem to be handled:

Can you share txt file of your output (may be filtered) ? Seems like process_interface3 is subset of process_interface . Might need few tweaks in process_interface

    ('process_interface3', r"(?P<interface>^[a-zA-Z0-9:-]+)\s+"
     "Link encap:(?P<itype>.*)$"),

Thanks for all great findings, I would really appreciate if you raise pull request for your changes and I can also have deep look at changes.

Hi,

process_interface3 is just a copy of process_interface method..

scanner class was throwing an error if i tried to reuse the same method. I dint debug further why..

And the issue (which is solved by process_interface3) can be reproduced with the ifconfig output i have given above..

@akr8986 Can you please create pull request with your changes ? We will take this forward from there.

Related #15 . Closing this for now.