Code Monkey home page Code Monkey logo

python-hosts's Introduction

python-hosts

codecov Docs

This is a python library for managing a hosts file. It enables you to add and remove entries, or import them from a file or URL.

Documentation

The docs are hosted on RTD (Read The Docs) here:
http://python-hosts.readthedocs.org/en/latest/index.html.

Changelog available here.

Installation

pip install python-hosts

Example usage

Adding an entry to a hosts file

from python_hosts import Hosts, HostsEntry
hosts = Hosts(path='hosts_test')
new_entry = HostsEntry(entry_type='ipv4', address='1.2.3.4', names=['www.example.com', 'example'])
hosts.add([new_entry])
hosts.write()

Importing a list of host entries by URL

from python_hosts import Hosts
hosts = Hosts(path='hosts_test')
hosts.import_url(url='https://gist.githubusercontent.com/jonhadfield/5b6cdf853ef629f9b187345d89157280/raw/ddfa4a069fb12bf3c1f285249d44922aeb75db3f/hosts')
hosts.write()

CLI

A command line client using python-hosts can be found here: https://github.com/jonhadfield/hostman

Requirements

Tested on python 2.7, 3.5, 3.6, 3.7, 3.8, 3.9, pypy and pypy3

License

MIT

python-hosts's People

Contributors

dependabot[bot] avatar dotlambda avatar jayvdb avatar jonhadfield avatar koc avatar lucasfcnunes avatar moonbuggy avatar sebalis avatar tirkarthi avatar trim21 avatar tucked avatar twm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-hosts's Issues

Issue when forcing update via link

Hi,

I have started using this module and overall it is pretty usefull, but I miss one function or maybe I am just using it in incorrect way. I have a file with records, that is updated often.
i.e.
1.2.3.4 one.example.com two.example.com

When record in file changes, I expect that records would be updated,
1.2.3.4 one.example.com

Using the code below it never happens and two.example.com is never removed, even remote file is updated

hosts_path.import_url(url='https://dl.dropboxusercontent.com/s/nfivpnt39vua05v/hosts?dl=0',force=True)
hosts_path.write()

However if we I try to use for same scenario below code, it is working fine.

new_entry = HostsEntry(entry_type='ipv4', address='1.2.3.4', names=['one.example.com','two.example.com'])
hosts_path.add([new_entry],force=True)
hosts_path.write()

Could be there some bug or I am doing wrong, when passing file via link?

1.0.4 breaking change hosts_path -> path

We had some code that uses python-hosts break on update to 1.0.4 because Hosts.hosts_path was renamed to path in fa0e860. Easy to fix once you know about it, but would it be worth adding hosts_path back for backwards compatibility?

CLI?

Hey, this is a nice project. Nice work!

Question: would you be interested in adding a CLI entrypoint? Basically just a way to use this package from the commandline for simple use cases. I was thinking an interface similar to https://github.com/lextoumbourou/goodhosts

I could put a PR together.

utils.is_ipv6 is not supported in Windows

File "C:\Python27\lib\site-packages\python_hosts\hosts.py", line 144, in init
self.populate_entries()
File "C:\Python27\lib\site-packages\python_hosts\hosts.py", line 435, in populate_entries
entry_type = HostsEntry.get_entry_type(hosts_entry)
File "C:\Python27\lib\site-packages\python_hosts\hosts.py", line 103, in get_entry_type
if is_ipv6(entry_chunks[0]):
File "C:\Python27\lib\site-packages\python_hosts\utils.py", line 31, in is_ipv6
if socket.inet_pton(socket.AF_INET6, entry):
AttributeError: 'module' object has no attribute 'inet_pton'

utility.py - incompatible import

Hello,

just downloaded master of the packet.

Building it with BuildRoot and installing it on an embedded linux computer, it fails with:

File "/usr/lib/python3.9/site-packages/python_hosts/utils.py", line 7, in
ModuleNotFoundError: No module named 'win_inet_pton'

Just as a "quick issue", because I'm on a hurry ;-))

Poldi

Nonsensical results with shared names

I see strange results when entries share secondary names. In this example, I create a file where foo-1 and foo-2 both alias foo, then clear foo by name, and re-add foo-1 with a different address. The result is a file that only contains foo-2.

$ virtualenv hosts
New python executable in hosts/bin/python
Installing setuptools, pip, wheel...cdone.

$ hosts/bin/pip install python-hosts
...
Successfully installed python-hosts-0.3.2

$ hosts/bin/python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from python_hosts import Hosts, HostsEntry
>>> hosts = Hosts(path='foo_hosts')
>>> hosts.add([HostsEntry(entry_type='ipv4', address='1.2.3.4', names=['foo-1', 'foo']),
...            HostsEntry(entry_type='ipv4', address='2.3.4.5', names=['foo-2', 'foo'])])
{'ipv6_count': 0, 'ipv4_count': 2, 'invalid_count': 0, 'duplicate_count': 0, 'replaced_count': 0}
>>> hosts.write()
{'ipv4_entries_written': 2, 'ipv6_entries_written': 0, 'total_written': 2, 'comments_written': 0, 'blanks_written': 0}
>>> with open('foo_hosts') as f:
...     print f.read()
... 
1.2.3.4 foo-1 foo
2.3.4.5 foo-2 foo

>>> hosts = Hosts(path='foo_hosts')
>>> hosts.remove_all_matching(name='foo')
>>> hosts.add([HostsEntry(entry_type='ipv4', address='1.2.3.6', names=['foo-1', 'foo'])])
{'ipv6_count': 0, 'ipv4_count': 0, 'invalid_count': 0, 'duplicate_count': 1, 'replaced_count': 0}
>>> hosts.write()
{'ipv4_entries_written': 1, 'ipv6_entries_written': 0, 'total_written': 1, 'comments_written': 0, 'blanks_written': 0}
>>> with open('foo_hosts') as f:
...     print f.read()
... 
2.3.4.5 foo-2 foo

>>> 

I would expect this as the result:

1.2.3.6 foo-1 foo

Conditionals for remove_all_matching are always True

https://github.com/jonhadfield/python-hosts/blob/devel/python_hosts/hosts.py#L253

self.entries = [x for x in self.entries if not (lambda y: y.address == address)]

Since this lambda is not invoked, this is essentially doing bool(func) which is always True.

Python 2.7.9 (default, Mar  1 2015, 12:57:24) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> bool(bool)
True
Python 3.4.2 (default, Oct  8 2014, 10:45:20) 
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> bool(bool)
True

This would probably be better:

self.entries = list(filter(lambda entry: entry.address != address, self.entries))

Work with strings instead of files.

This library looks really handy 👍

Having to interact with files is a bit painful for my current use case, though, because I need to change the /etc/hosts on a remote host.
I believe that would mean:

  1. cat /etc/hosts on the remote host.
  2. Write stdout to a local tempfile.
  3. Give the path of the tempfile to Hosts.
  4. Do my changes.
  5. Hosts.write
  6. Read the tempfile.
  7. Tell the host to overwrite its /etc/hosts with str_from_reading_tempfile.
  8. Delete the tempfile.

Is this the correct / most optimal flow?


I think things would be simpler if this supported strings directly:

  1. cat /etc/hosts on the remote host.
  2. Feed stdout to Hosts.
  3. Do my changes.
  4. new_etc_hosts = Hosts.dumps() (like the json module)
  5. Tell the host to overwrite its /etc/hosts with new_etc_hosts.

Just a thought...

The future of coatldev/six:latest

Hello there,

I am the maintainer for coatldev/six and first, I'd like to thank you for using that image. Secondly, I would like to share my decision behind the future removal of the latest tag for that image.

coatldev/six was created because I had the need to test my packages were properly installed on Python 2, and running tests code formatters, linters and type checking using Python 3.10 because mypy[python2]==0.971 when 3.11.0 was released, it could not be installed, but recent tests show that it is now possible to install using 3.11 and even 3.12.0rc2.

Because of those reasons, coatldev/six is no longer exclusively for Python 3.10 and 2.7; it now has 3.11 and 3.12 as options, too. So a latest tag does not make sense anymore.

Instead of latest I would suggest "pinning" your dependency using any (or all) of the following tags: 3.10, 3.11, or 3.12.

I plan to completely remove the latest tag by the end of October or whenever this has been updated on this repo.

Regards,
César

ImportError: cannot import name 'Hosts' version 0.4.7

I am using Python 3.6 and python_hosts 0.4.7.

When running my script, I get the traceback:

Traceback (most recent call last):
  File "./install.py", line 9, in <module>
    import main
  File "/home/matt/dotfiles/.scripts/main.py", line 8, in <module>
    from python_hosts import Hosts
ImportError: cannot import name 'Hosts'

I have also tried this with version 0.4.5, and I get the same error. It successfully detects the presence of the python_hosts installation, but gives me this import error. My PYTHONPATH is empty. I'm really not sure what is causing this error. This is the same error as reported in #23 , but on a different version. I think it is being caused by something else.

'HostsEntry' object is not iterable

Hey there, thanks for this lib!
I have an issue, but not sure, about expected behavior of the code. So I have 2 lists:

addresses = ['127.0.0.1', '127.0.1.1']
names = ['google.com', 'microsoft.com']

And want to run my tests in all possible variations:

for test in tests:
    for address in addresses:
        hosts.add(HostsEntry(entry_type='ipv4', address=address, names=names))
        hosts.write()
        for name in names:
            cmd = ['ruby', test, name]
            run = Popen(cmd, stdout=PIPE)

unfortunatelly exception appears:

 File "/usr/local/lib/python2.7/dist-packages/python_hosts/hosts.py", line 354, in add for entry in entries:
TypeError: 'HostsEntry' object is not iterable

probably, I missed something but, anyway, looking forward your assist.
thx, ^_^

support duplicate names

e. g.:

1.2.3.4 examle1.com managed
5.6.7.8 example2.com managed

adding a new entry:

9.10.11.12 example3.com managed

does not work - nothing is added - but, using force=True, it deletes all the existing entries

The bug may be here:

if set(entry.names).intersection(existing_names):

No support for adding comments

No matter what permutation I try of args I cannot create a HostsEntry that is a comment nor does comment as an arg do anything significant.

I'll continue to test and if possible make a PR that solves the issue. I would have thought entry_type=comment with comment arg with value would have created a comment entry but apparently not?

Deprecation warning due to invalid escape sequences

Deprecation warning due to invalid escape sequences. Using raw strings or escaping them again helps in resolving this. Check https://github.com/asottile/pyupgrade/ for automatic fix of this.

find . -iname '*.py' | grep -Ev 'rdf4|tool|doc' | xargs -P4 -I{} python3.8 -Wall -m py_compile {}
./python_hosts/utils.py:46: DeprecationWarning: invalid escape sequence \d
  allowed = re.compile('(?!-)[A-Z\d-]{1,63}(?<!-)$', re.IGNORECASE)
./python_hosts/hosts.py:2: DeprecationWarning: invalid escape sequence \w
  """ This module contains classes:

ipv4 host added to bottom of /etc/hosts and not in the ipv4 section

from python_hosts.hosts import Hosts, HostsEntry

fz = "friendzone.red"
target = "10.10.10.123"

hosts = Hosts(path="hosts")
new_entry = HostsEntry(entry_type="ipv4", address=target, names=[fz])
hosts.add([new_entry])
hosts.write()

output:

127.0.0.1       localhost
127.0.1.1       kali.kali kali

#10.10.10.145   player.htb

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
10.10.10.123    friendzone.red

It's not a huge deal but for organizational purposes it would be nice if 10.10.10.123 friendzone.red test.htb was added either above or below #10.10.10.145 player.htb in the "ipv4" section. Also. I mentioned this in a closed issue, but if I run hosts.write() with a different host for the same IPV4 address, it doesn't append the new host to the existing line or anywhere for that matter. Being a library solely dedicated to working with the /etc/hosts file , it would be optimal to have the feature to append new hosts to an existing line. The CLI pyhostman doesn't work either for this purpose. You can use --force but that will remove the other hosts which is annoying as I'm writing a python script and in multiple functions it appends hosts to the /etc/hosts file for the same ipv4 address. I've already written this program in bash and it works great but i have to do a lot of if grep -q $htbdomain /etc/hosts; then sed -i $"/$rhost/ s/$/\t$htbdomain/" /etc/hosts etc.... Cool project by the way, but it could really use the appending feature

cannot import name 'Hosts'

Hi, at 0.4.6 version had error with command:
from python_hosts import Hosts, HostsEntry

Error:"cannot import name Hosts"

At version 0.4.5 anythink work perfect

Exception: Address and Name(s) must be specified.

It was actually working, i was in the process of adding a file read, when it quit working. Here is the code (the example from the manual)

from python_hosts import Hosts, HostsEntry
my_hosts = Hosts()
new_entry = HostsEntry(entry_type='ipv4', address='1.2.3.4', names=['example.com', 'example'])
my_hosts.add([new_entry])
my_hosts.write()
print(new_entry)

The execution and error

$ sudo python3 IPHostUpdate.py 1 ⨯
Traceback (most recent call last):
File "/home/kali/Desktop/IPHostUpdate.py", line 2, in
my_hosts = Hosts()
File "/usr/local/lib/python3.9/dist-packages/python_hosts/hosts.py", line 144, in init
self.populate_entries()
File "/usr/local/lib/python3.9/dist-packages/python_hosts/hosts.py", line 470, in populate_entries
HostsEntry(
File "/usr/local/lib/python3.9/dist-packages/python_hosts/hosts.py", line 54, in init
raise Exception('Address and Name(s) must be specified.')
Exception: Address and Name(s) must be specified.

I have uninstalled, and re-installed the app.

Any thoughts?

PermissionError on Windows

How could I elevate to get permission to edit the host file. Running the Script as described drops me Errno 13, Permission Denied. Ive even already tried using this: https://pypi.org/project/pyuac/, which works for any file located on the root drive but not inside the Windows\System32 folder.

Verify against an object

This is more or less a feature request. I'd like to be able to verify the existence of some hosts entries. I may go ahead and do a PR to implement this. I'm already doing this through putting each line into a hash and splitting it.

Cannot Remove/Override the existing host records

I've got below error when i was trying to remove_all_matching by using name or set the force=True in adding a host record.

Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/python_hosts/hosts.py", line 371, in add
self.remove_all_matching(name=entry.names)
File "/usr/local/lib/python2.7/dist-packages/python_hosts/hosts.py", line 264, in remove_all_matching
self.entries = list(filter(func, self.entries))
File "/usr/local/lib/python2.7/dist-packages/python_hosts/hosts.py", line 261, in
func = lambda entry: entry.comment or name not in entry.names
TypeError: argument of type 'NoneType' is not iterable

remove_all_matching(None, name) broken in 0.3.4 if hosts file contains comments.

PR #6 that was merged in 03.4 breaks remove_all_matching for line identified as comments.

Since entry.names is initialized as None by default, comment entries have a None value in the names property. The filtering used in remove_all_matching() in 0.3.4 breaks in those cases.

To replicate simply have a hosts file with comments and invoke remove_all_matching(None, name) to remove an entry by name.

Permission denied: '/etc/hosts'

How to deal with:
PermissionError: [Errno 13] Permission denied: '/etc/hosts'
when I can't change perms on hosts file? (default ubuntu setting)

Feature request: A way to get all matching hostentries.

I would like a method in the hosts-module, a way to get a hostentry based on a name.

This is how I'm solving it right now:

    api = next(iter([
        host
        for host in hosts.entries
        if host.names and N_API_URL in host.names
    ]), None)

No support while there is Chinese in hosts file

If there is any comments written in Chinese, the module will throw an error.

Traceback (most recent call last):
File "D:\456\akamTester\akamTester.py", line 113, in
fastHosts = Hosts()
File "%AppData%\Local\Programs\Python\Python37\lib\site-packages\python_hosts\hosts.py", line 144, in init
self.populate_entries()
File "%AppData%\Local\Programs\Python\Python37\lib\site-packages\python_hosts\hosts.py", line 433, in populate_entries
hosts_entries = [line for line in hosts_file]
File "%AppData%\Local\Programs\Python\Python37\lib\site-packages\python_hosts\hosts.py", line 433, in
hosts_entries = [line for line in hosts_file]
UnicodeDecodeError: 'gbk' codec can't decode byte 0xbf in position 2: illegal multibyte sequence

can't add ipv6 entry

Hello! I have next code:

#!/usr/bin/python3
from python_hosts import Hosts, HostsEntry

hosts = Hosts(path='/etc/hosts')

ip4_localhost_entries = list(filter(lambda host_entry: host_entry.address == '127.0.0.1' and 'mc.yandex.ru' in host_entry.names, hosts.entries))
ip6_localhost_entries = list(filter(lambda host_entry: host_entry.address == '::1' and 'mc.yandex.ru' in host_entry.names, hosts.entries))

if len(ip4_localhost_entries) == 0:
    new_entry = HostsEntry(entry_type='ipv4', address='127.0.0.1', names=['mc.yandex.ru'])
    hosts.add([new_entry])

if len(ip6_localhost_entries) == 0:
    new_entry = HostsEntry(entry_type='ipv6', address='::1', names=['mc.yandex.ru'])
    hosts.add([new_entry])

hosts.write()

I'm expecting to see in /etc/hosts 2 records: 127.0.0.1 mc.yandex.ru and ::1 mc.yandex.ru, but only first is appeared.

Did i something wrong?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.