Python-ELMO is a Python library which offers an encapsulation of the binary tool ELMO, in order to manipulate it easily in Python and SageMath script.

4 роки тому
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import os
  2. import json
  3. class ClosureException(Exception):
  4. pass
  5. # https://stackoverflow.com/questions/20007319/how-to-do-a-large-text-file-transfer-in-python
  6. class SocketTool:
  7. @classmethod
  8. def convert_to_bytes(cl, no):
  9. result = bytearray()
  10. result.append(no & 255)
  11. for i in range(3):
  12. no = no >> 8
  13. result.append(no & 255)
  14. return result
  15. @classmethod
  16. def bytes_to_number(cl, b):
  17. import sys
  18. b = b if (sys.version_info > (3, 0)) else map(ord, b)
  19. res = 0
  20. for i in range(4):
  21. res += b[i] << (i*8)
  22. return res
  23. @classmethod
  24. def send_file(cl, s, filename, mode='rb'):
  25. length = os.path.getsize(filename)
  26. s.send(cl.convert_to_bytes(length)) # has to be 4 bytes
  27. with open(filename, mode) as infile:
  28. d = infile.read(1024*64) # We send by pack of 64 ko
  29. while d:
  30. s.send(d)
  31. d = infile.read(1024*64)
  32. @classmethod
  33. def get_file(cl, s):
  34. size = s.recv(4) # assuming that the size won't be bigger then 1GB
  35. size = cl.bytes_to_number(size)
  36. current_size = 0
  37. buffer = b''
  38. while current_size < size:
  39. data = s.recv(1024*64)
  40. if not data:
  41. break
  42. if len(data) + current_size > size:
  43. data = data[:size-current_size] # trim additional data
  44. buffer += data
  45. # you can stream here to disk
  46. current_size += len(data)
  47. # you have entire file in memory
  48. return buffer
  49. @classmethod
  50. def send_data(cl, s, data):
  51. data = json.dumps(data)
  52. data = data.encode('utf-8')
  53. s.send(cl.convert_to_bytes(len(data))) # has to be 4 bytes
  54. s.send(data)
  55. @classmethod
  56. def get_data(cl, s):
  57. import sys
  58. exception_class = json.decoder.JSONDecodeError if (sys.version_info > (3, 0)) else ValueError
  59. try:
  60. size = s.recv(4)
  61. if not size:
  62. return None
  63. size = cl.bytes_to_number(size)
  64. data = s.recv(size)
  65. data = data.decode('utf-8')
  66. data = json.loads(data)
  67. return data
  68. except exception_class:
  69. return None
  70. @classmethod
  71. def send_ack(cl, s, positive=True):
  72. data = 'OK' if positive else 'NO'
  73. s.send(data.encode('ascii'))
  74. @classmethod
  75. def get_ack(cl, s):
  76. data = s.recv(2).decode('ascii')
  77. return (data == 'OK')
  78. class Protocol:
  79. def __init__(self, clientsocket):
  80. self.clientsocket = clientsocket
  81. def send_file(self, filename, mode='rb'):
  82. SocketTool.send_file(self.clientsocket, filename, mode)
  83. def get_file(self):
  84. return SocketTool.get_file(self.clientsocket)
  85. def send_data(self, data):
  86. SocketTool.send_data(self.clientsocket, data)
  87. def get_data(self):
  88. return SocketTool.get_data(self.clientsocket)
  89. def send_ack(self, positive=True):
  90. SocketTool.send_ack(self.clientsocket, positive)
  91. def send_nack(self, positive=True):
  92. SocketTool.send_ack(self.clientsocket, not positive)
  93. def get_ack(self):
  94. return SocketTool.get_ack(self.clientsocket)
  95. def please_assert(self, condition):
  96. if not condition:
  97. self.send_nack()
  98. self.clientsocket.close()
  99. raise ClosureException
  100. def get_object_or_nack(self, model, **kwargs):
  101. try:
  102. return model.objects.get(**kwargs)
  103. except model.DoesNotExist:
  104. self.send_nack()
  105. self.clientsocket.close()
  106. raise ClosureException
  107. def close(self):
  108. self.clientsocket.close()