5

I am trying to bind hosts to specified ips in my python program. Just make it affect in the python program, so I am not going to modify the /etc/hosts file.

I tried to add a bit code to the create_connection function in socket.py for host-ip translation, like this:

host, port = address  # the original code in socket.py
# My change here:
if host == "www.google.com":
    host = target_ip  
for res in getaddrinfo(host, port, 0, SOCK_STREAM): # the original code in socket.py

I found it works fine.

And now I want the host-ip translation only works in this python program.

So my question is: how can I make my python program import this socket.py not the build-in one when using import socket?

To make it clear, here is an example. Suppose 'test' is my work directory:

test
|--- main.py
|--- socket.py

In this case:

  1. How can I make main.py use test/socket.py by import socket?

  2. How can I make another modules use test/socket.py when they are using import socket?

I think changing the module find path order may help. But I found that even if the current path('') is in the first place of sys.path already and import socket still imports the built-in scoket module.

WKPlus
  • 6,955
  • 2
  • 35
  • 53
  • 2
    A good practice is to get the standard `socket` when you `import socket`, and explictly import the alternative when you want the alternative, e.g. `from test import socket` or `from . import socket`. Explicit is better than implicit. – shx2 Jul 25 '14 at 06:54
  • @shx2 In this way, when work together with a third party module, such as `requests`, I need to change every import statement using the third party module. – WKPlus Jul 25 '14 at 08:41

2 Answers2

5

You can monkey-patch sys.modules, placing your own module instead of the standard socket, before importing any other module which might be using it.

# myscript.py

from myproject import mysocket
import sys
sys.modules['socket'] = mysocket

# ... the rest of your code
import requests
...

For that, mysocket should expose everything which the standard socket does.

# mysocket.py

import socket as _std_socket
from socket import *  # expose everything

def create_connection(address, *args, **kwargs):
    if address == ...:
       address = ...
    return _std_socket.create_connection(address, *args, **kwargs)

This might be an over-simplification of what mysocket.py should look like. Youd' likely need to add some definitions before this can be used in production, but you get the idea.


Another approach would be to monkey-patch the socket module itself, i.e. overwrite names inside the original module.

# myscript.py
import socket

def create_connection2(...):
    ...

socket.create_connection = create_connection2

# ... the rest of your code
import requests
...

I prefer the former approach, becuase it is cleaner in the sense you don't need to go inside the module, only to hide it and override some things in it from the outside.

shx2
  • 61,779
  • 13
  • 130
  • 153
1

You can use relative imports to locally use a socket.py module. However, to do this your project must be structured as a package.

from . import socket
Community
  • 1
  • 1
Andrew Johnson
  • 3,078
  • 1
  • 18
  • 24