import ssl
from socket import socket
class testsock(socket):
def __init__(self, tls=True):
super(testsock, self).__init__()
self.connect(('192.168.0.1', 443))
if tls:
self = ssl.wrap_socket(self) # Ugly "handover"
testsock(tls=True)
This code works, it's the second ugliest bodge I've done as of today.
But it works with the behavior I desire, that .send()
and .close()
etc are "intact".
However, if I ever try to add any other values to my custom class testsock
those will effectively be gone, since I replace self
with whatever wrap_socket
spits out.
I could use something that looks like this:
class testsock():
def __init__(self, tls=True):
self.s = socket()
...
self.s = ssl.wrap_socket(self.s)
def send(self, data):
self.s.send(data)
But that goes against the elegance of inheriting the socket object and not having to create all the functions you'd expect out of a ordinary socket. (I know, lazy programming, but it looks cleaner without all the definitions).
I could probably iterate over all the .__dict__
or inspect.getmembers() functions and replace them with the matching available items from wrap_socket
, but that would also cause for concerns later on, but it would look something like:
for name, obj in inspect.getmembers(self):
print(name, obj)
It would yield something like:
close <bound method socket.close of <__main__.testsock fd=...>>
I'm not sure how I'd get socket
from this, obj.__class__.__name__
doesn't yield this. If I could some how get socket
from the object I would know that it's a socket() bound method, and replace the corresponding method from wrap_socket()
return.
I've heard of metaclass programming, and I'm having a go at it.
But my question is, out of all the options - Which would be the best according to the community?
Would it be possible to inline-replace the inherited socket object with whatever ssl.wrap_socket
returns?
1 Answer 1
You don't need a class here, a simple function will do:
import ssl
from socket import socket
def testsock(tls=True):
sock = socket()
sock.connect(('192.168.0.1', 443))
if tls:
sock = ssl.wrap_socket(sock)
return sock
testsock(tls=True)
Returned objects are either plain sockets or ssl sockets but they share some common behaviour (like send
or recv
). If you need to add attributes, you can do that before the return
statement.
In case you wish to be able to extend it better, you can still use the socket as an attribute on a custom class and expose the socket
API through __getattr__
:
class TestSock(object):
def __init__(self, tls=True):
sock = socket()
sock.connect(('192.168.0.1', 443))
if tls:
sock = ssl.wrap_socket(sock)
self.socket = sock
# other attributes
def __getattr__(self, attribute_name):
"""Defer unknown behaviour to the socket"""
return getattr(self.socket, attribute_name)
# other methods
But you don't need it for now.
-
\$\begingroup\$ I do wish to keep it as a class in order to expand this further in the future. That's one of my statements above. But this is the type of meta-programming I was beginning to explore, the use of hooking into the function calls and map it against either socket or wrap_socket functions. I'm willing to accept this as a reasonable answer even tho it's not quite what I had in mind. I was hoping for a way to replace the inherited structure of
socket
with that ofwrap_socket
. But I guess it's not really possible. So the closest I'll get is local variables and hook into__getattr__
etc. \$\endgroup\$Torxed– Torxed2017年01月19日 15:26:10 +00:00Commented Jan 19, 2017 at 15:26 -
\$\begingroup\$ Took a while for me to find the word I was looking for, I want to re-inherit my class to match the
wrap_socket
object. Your approach would fully simulate this - absolutely. So might go with this instead of my bodge that Im afraid of posting here haha. \$\endgroup\$Torxed– Torxed2017年01月19日 15:32:28 +00:00Commented Jan 19, 2017 at 15:32 -
\$\begingroup\$ I've found no better way to re-intialize a inheritance in a class, so this is probably the best option. \$\endgroup\$Torxed– Torxed2017年01月23日 19:28:01 +00:00Commented Jan 23, 2017 at 19:28
Explore related questions
See similar questions with these tags.
self
? \$\endgroup\$print(class_handle)
it will result in<ssl.SSLSocket fd=...>
instead of<__main__.testsock fd=...>
. \$\endgroup\$self
but I see none in your code. Is that the code you are using then, or is this a draft where you want to add the desired behaviour of being able to add attributes? \$\endgroup\$self.moo = 'cow'
either in__init__
or later on in a function, that would never be possible because anything in__init__
will be overwritten and any functions defined will also be gone. \$\endgroup\$self
may be mutable, but reassigning it replaces it, it doesn't mutate it. It won't change the object that you get from runningsock = testsock(tls=True)
;sock
will never be SSL. The only way that replacement would work is if literally all of your code using thetestsock
is run under__init__
. Otherwise, whentls=True
, no modifications toself
after that line will be reflected in the final object you get from construction (and it will never be SSL enabled in any event, unless thewrap_socket
function is actually mutating the socket it's passed in some way). \$\endgroup\$