Python Forum

Full Version: Help copying a column from a csv to another file with some extras
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hello,

I need to copy the contents of a .csv, that gets dumped from SQL each night to a folder location on my Ubuntu server that contains 100s of IP addresses to an area within a .conf file. Well I'm happy to create a new file rather than try and open an existing file and insert.

I'm a novice at Python, but getting this working will help. VScode is amazing to.

The csv puts all the IP addresses on the first column:

ip_address
192.168.0.1
192.168.0.2
192.168.0.3
192.168.0.4 
ect...
And I need it to put into a file called something like routers.conf like this on row 2, but I need it be formatted like below and include the " instead of 'around the IP, add the :161 etc and inject into row 2 and replace what is there. Plus add the rest of the config.

[[inputs.snmp]]
  agents ["192.168.0.1:161","192.168.0.2:161","192.168.0.3:161","192.168.0.4:161"]
  version = 2
  community = "publicblah"
  interval = "120s"
  timeout = "5s"
  retries = 0
Could Python do this?

I'm currently using this to open and view it:

    with open("ip.csv", 'r', encoding='utf-8-sig') as infile:
    reader = csv.reader(infile, delimiter=" ")
    header = next(reader)
    print(header)
I've been reading through - https://realpython.com/python-csv/

I did have a play with the outfile = open and outfile.write options, but get lost as this just writes a new .csv.

Any help to copy this data, format it, and create a new file with the addition config file would be most welcome.
Is the delimiter a whitespace? If it's the case, you can use split instead.
Here is an example with csv, where the delimiter is a ,.

To validate an IP-Address, you can use ipaddress.ip_address.
If the str is not a valid IPv4- or IPv6-Address, a ValueError is thrown.

IPv4Address/IPv6Address are sortable.


import csv
from collections.abc import Generator
from ipaddress import ip_address
from pathlib import Path


template = """
[[inputs.snmp]]
  agents [{ips}]
  version = 2
  community = "publicblah"
  interval = "120s"
  timeout = "5s"
  retries = 0
"""


def reader(file: str | Path) -> Generator[str, None, None]:
    with open(file, newline="") as fd:
        for ip, *_ in csv.reader(fd):
            # validation of ip
            try:
                ip = ip_address(ip)
            except ValueError:
                print(f"Invalid IP: '{ip}' skipping...")
                continue

            yield ip


def make_conf(infile: str | Path, outfile: str | Path) -> None:
    ips = [f'"{ip}"' for ip in sorted(reader(infile))]
    with open(outfile, "w") as fd_out:
        fd_out.write(template.format(ips=",".join(ips)))


if __name__ == "__main__":
    infile = Path.home().joinpath("Desktop", "data.csv")
    outfile = Path.home().joinpath("Desktop", "snmp.conf")
    make_conf(infile, outfile)
@DeaD_EyE

In

def reader(file: str | Path) -> Generator[str, None, None]
What does this do?

Quote:Generator[str, None, None]

Do str, None, None represent send(), throw() and close()??

The function reader works without Generator being explicitly declared. Is that just extra error catching?
It's a function definition with TypeHints for arguments and the return type.
After the colon are the expected types.

It helps the IDE to know the expected types. This code does not do any checks during runtime.

def reader(file: str | Path) -> Generator[str, None, None]
The first argument should be a str or path. The return type is a generator, which yields str. The Generator does not have a SendType nor a ReturnType.

Syntax for Generator
Generator[YieldType, SendType, ReturnType]
The same signature without TypeHints is easier to understand:
def reader(file):
The whole Code without TypeHints is shorter:
import csv
from ipaddress import ip_address
from pathlib import Path
 
 
template = """
[[inputs.snmp]]
  agents [{ips}]
  version = 2
  community = "publicblah"
  interval = "120s"
  timeout = "5s"
  retries = 0
"""
 
 
def reader(file):
    with open(file, newline="") as fd:
        for ip, *_ in csv.reader(fd):
            # validation of ip
            try:
                ip = ip_address(ip)
            except ValueError:
                print(f"Invalid IP: '{ip}' skipping...")
                continue
 
            yield ip
 
 
def make_conf(infile, outfile):
    ips = [f'"{ip}"' for ip in sorted(reader(infile))]
    with open(outfile, "w") as fd_out:
        fd_out.write(template.format(ips=",".join(ips)))
 
 
if __name__ == "__main__":
    infile = Path.home().joinpath("Desktop", "data.csv")
    outfile = Path.home().joinpath("Desktop", "snmp.conf")
    make_conf(infile, outfile)