After watching https://www.youtube.com/watch?v=zi0rHwfiX1Q I tried to port the example from C (implementation) and Erlang (testing) to Python and Hypothesis. Given this implementation (the rem function emulates %'s C behavior):
import math
def rem(x, y):
res = x % y
return int(math.copysign(res,x))
class Queue:
def __init__(self, capacity: int):
self.capacity = capacity + 1
self.data = [None] * self.capacity
self.inp = 0
self.outp = 0
def put(self, n: int):
self.data[self.inp] = n
self.inp = (self.inp + 1) % self.capacity
def get(self):
ans = self.data[self.outp]
self.outp = (self.outp + 1) % self.capacity
return ans
def size(self):
return rem((self.inp - self.outp), self.capacity)
and this test code
import unittest
from hypothesis.stateful import rule, precondition, RuleBasedStateMachine
from hypothesis.strategies import integers
from myqueue import Queue
class QueueMachine(RuleBasedStateMachine):
cap = 1
def __init__(self):
super().__init__()
self.queue = Queue(self.cap)
self.model = []
#rule(value=integers())
#precondition(lambda self: len(self.model) < self.cap)
def put(self, value):
self.queue.put(value)
self.model.append(value)
#rule()
def size(self):
expected = len(self.model)
actual = self.queue.size()
assert actual == expected
#rule()
#precondition(lambda self: self.model)
def get(self):
actual = self.queue.get()
expected = self.model[0]
self.model = self.model[1:]
assert actual == expected
TestQueue = QueueMachine.TestCase
if __name__ == "__main__":
unittest.main()
The actual question is how to use Hypothesis to also parametrize over QueueMachine.cap instead of setting it manually in the test class.
You can set self.queue in an initialize method rather than __init__, using a suitable integers strategy for the capacity.
Related
I have the following code and it works until it gets to the 'union.set()' part. It says, "unhashable type: 'LinkedEdge' " . I am not sure why this is the case since I have looked at other sources on the web and in reference books to know that the 'g.addVertex()' method and the 'g.addEdge()' method as well as the arguments being passed should lead correctly to an output like this:
5 Vertices: A C B E D
5 Edges: A>B:3 A>C:2 B>D:1 C>D:1 D>E:2
class LinkedEdge(object):
def __init__(self, fromVertex, toVertex, weight = None):
self._vertex1 = fromVertex
self._vertex2 = toVertex
self._weight = weight
self._mark = False
def clearMark(self):
self._mark = False
def __eq__(self, other):
if self is other: return True
if type(self) != type(other):
return False
return self._vertex1 == other._vertex1 and self._vertex2 == other._vertex2
def getOtherVertex(self, thisVertex):
if thisVertex == None or thisVertex == self._vertex2:
return self._vertex1
else:
return self._vertex2
def getToVertex(self):
return self._vertex2
def getWeight(self):
return self._weight
def isMarked(self):
return self._mark
def setMark(self):
self._mark = True
def setWeight(self, weight):
self._weight = weight
def __str__(self):
return str(self._vertex1) + ">" + str(self._vertex2) + ":" + str(self._weight)
class LinkedVertex(object):
def __init__(self, label):
self._label = label
self._edgeList = []
self._mark = False
def clearMark(self):
self._mark = False;
def getLabel(self):
return self._label
def isMarked(self):
return self._mark
def setLabel(self, label, g):
g._vertices.pop(self._label, None)
g._vertices[label] = self
self._label = label
def setMark(self):
self._mark = True
def __str__(self):
return str(self._label)
def addEdgeTo(self, toVertex, weight):
edge = LinkedEdge(self, toVertex, weight)
self._edgeList.append(edge)
def getEdgeTo(self, toVertex):
edge = LinkedEdge(self, toVertex)
try:
return self._edgeList[self._edgeList.index(edge)]
except:
return None
def incidentEdges(self):
return iter(self._edgeList)
def neighboringVertices(self):
vertices = []
for edge in self._edgeList:
vertices.append(edge.getOtherVertex(self))
return iter(vertices)
def removeEdgeTo(self, toVertex):
edge = LinkedEdge(self, toVertex)
if edge in self._edgeList:
self._edgeList.remove(edge)
return True
else:
return False
class LinkedDirectedGraph(object):
def __init__(self, collection = None):
self._vertexCount = 0
self._edgeCount = 0
self._vertices = {}
if collection != None:
for label in collection:
self.addVertex(label)
# Methods for clearing, marks, sizes, string rep
def clear(self):
self._vertexCount = 0
self._edgeCount = 0
self._vertices = {}
def clearEdgeMarks(self):
for edge in self.edges():
edge.clearMark()
def clearVertexMarks(self):
for vertex in self.vertices():
vertex.clearMark()
def isEmpty(self):
return self._vertexCount == 0;
def sizeEdges(self):
return self._edgeCount
def sizeVertices(self):
return self._vertexCount
def __str__(self):
result = str(self.sizeVertices()) + " Vertices: "
for vertex in self._vertices:
result += " " + str(vertex)
result += "\n";
result += str(self.sizeEdges()) + " Edges: "
for edge in self.edges():
result += " " + str(edge)
return result
def addVertex(self, label):
self._vertices[label] = LinkedVertex(label)
self._vertexCount += 1
def containsVertex (self, label):
return label in self._vertices
def getVertex(self, label):
return self._vertices[label]
def removeVertex(self, label):
removedVertex = self._vertices.pop(label, None)
if removedVertex is None:
return False
# Examine all vertices
for vertex in self.vertices():
if vertex.removeEdgeTo(removedVertex):
self._edgeCount -= 1
self._vertexCount -= 1
return True
def addEdge(self, fromLabel, toLabel, weight):
fromVertex = self.getVertex(fromLabel)
toVertex = self.getVertex(toLabel)
fromVertex.addEdgeTo(toVertex, weight)
self._edgeCount += 1
def containsEdge(self, fromLabel, toLabel):
return self.getEdge(fromLabel, toLabel) != None
def getEdge(self, fromLabel, toLabel):
fromVertex = self._vertices[fromLabel]
toVertex = self._vertices[toLabel]
return fromVertex.getEdgeTo(toVertex)
def removeEdge (self, fromLabel, toLabel):
fromVertex = self.getVertex(fromLabel)
toVertex = self.getVertex(toLabel)
edgeRemovedFlg = fromVertex.removeEdgeTo(toVertex)
if edgeRemovedFlg:
self._edgeCount -= 1
return edgeRemovedFlg
# Iterators
def edges(self):
result = set()
for vertex in self.vertices():
edges = vertex.incidentEdges()
result = result.union(set(edges))
return iter(result)
def vertices(self):
return iter(self._vertices.values())
def incidentEdges(self, label):
return self._vertices[label].incidentEdges()
def neighboringVertices(self, label):
return self._vertices[label].neighboringVertices
g = LinkedDirectedGraph()
# Insert vertices
g.addVertex("John")
g.addVertex("Sam")
g.addVertex("Megan")
g.addVertex("Jennifer")
g.addVertex("Rick")
# Insert weighted edges
g.addEdge("John", "Sam", 3)
g.addEdge("John", "Megan", 2)
g.addEdge("Sam", "Jennifer", 1)
g.addEdge("Megan", "Jennifer", 1)
g.addEdge("Jennifer", "Rick", 2)
print(g)
If you override __eq__, then Python intentionally makes your class unhashable, since there is no longer a guarantee that the default hashing algorithm (based on the object's location in memory) is compatible with your __eq__ algorithm. "Compatible" here just means that equal objects must have equal hashes. By default, nothing is equal, so when you make some things equal using an __eq__ method, you impose a requirement on what a proper hash function must do.
If you want a custom class with a custom __eq__ method to be hashable, you must implement a __hash__ method yourself.
It could be as simple as being based on the hash of the corresponding tuple:
def __hash__(self):
return hash((type(self), self._vertex1, self._vertex2))
The Python docs explain this here.
I've recently stumbled upon this very useful code which I got from this link https://github.com/Douglas6/cputemp.
I've modified the code for clarity reasons and so "application" class is imported as an external class. I'm trying to understand why "set_temperature_callback" is called indefinitely in a loop. The interval of the loop is defined by NOTIFY_TIMEOUT. Here the interval is set to 1000 ms. I'm using this code as a peripheral for one of my Unity projects and it's working fine. I really appreciate any help!
import dbus
from advertisement import Advertisement
from service import Service, Characteristic, Descriptor
from gpiozero import CPUTemperature
#testing code
#------------------------------------------#
from application import Application
import inspect as i
import sys
def FindSource(method):
sys.stdout.write(i.getsource(method))
#------------------------------------------#
GATT_CHRC_IFACE = "org.bluez.GattCharacteristic1"
#the interval between sending messages, is counted in milliseconds, was 5000
NOTIFY_TIMEOUT = 1000
class ThermometerAdvertisement(Advertisement):
def __init__(self, index):
Advertisement.__init__(self, index, "peripheral")
self.add_local_name("Raspberry (thermometer)")
self.include_tx_power = True
class ThermometerService(Service):
#the service we're interested and is displayed in unity
THERMOMETER_SVC_UUID = "00000001-710e-4a5b-8d75-3e5b444bc3cf"
def __init__(self, index):
self.farenheit = True
Service.__init__(self, index, self.THERMOMETER_SVC_UUID, True)
self.add_characteristic(TempCharacteristic(self))
self.add_characteristic(UnitCharacteristic(self))
def is_farenheit(self):
return self.farenheit
def set_farenheit(self, farenheit):
self.farenheit = farenheit
class TempCharacteristic(Characteristic):
TEMP_CHARACTERISTIC_UUID = "00000002-710e-4a5b-8d75-3e5b444bc3cf"
def __init__(self, service):
self.notifying = False
Characteristic.__init__(
self, self.TEMP_CHARACTERISTIC_UUID,
["notify", "read"], service)
self.add_descriptor(TempDescriptor(self))
def get_temperature(self):
value = []
unit = "C"
# code here repeats
cpu = CPUTemperature()
temp = cpu.temperature
if self.service.is_farenheit():
temp = (temp * 1.8) + 32
unit = "F"
strtemp = str(round(temp, 1)) + " " + unit
for c in strtemp:
value.append(dbus.Byte(c.encode()))
return value
# the entire method will run on a loop when unity app hits "subscribe"
def set_temperature_callback(self):
if self.notifying:
print("running inside set_temperature_callback")
value = self.get_temperature()
self.PropertiesChanged(GATT_CHRC_IFACE, {"Value": value}, [])
return self.notifying
def StartNotify(self):
print("Start notify first time")
if self.notifying:
print("returning from start notify")
return
self.notifying = True
value = self.get_temperature()
self.PropertiesChanged(GATT_CHRC_IFACE, {"Value": value}, [])
self.add_timeout(NOTIFY_TIMEOUT, self.set_temperature_callback)
def StopNotify(self):
self.notifying = False
def ReadValue(self, options):
value = self.get_temperature()
return value
class TempDescriptor(Descriptor):
TEMP_DESCRIPTOR_UUID = "2901"
TEMP_DESCRIPTOR_VALUE = "CPU Temperature test"
def __init__(self, characteristic):
Descriptor.__init__(
self, self.TEMP_DESCRIPTOR_UUID,
["read"],
characteristic)
def ReadValue(self, options):
value = []
desc = self.TEMP_DESCRIPTOR_VALUE
for c in desc:
value.append(dbus.Byte(c.encode()))
return value
class UnitCharacteristic(Characteristic):
UNIT_CHARACTERISTIC_UUID = "00000003-710e-4a5b-8d75-3e5b444bc3cf"
def __init__(self, service):
Characteristic.__init__(
self, self.UNIT_CHARACTERISTIC_UUID,
["read", "write"], service)
self.add_descriptor(UnitDescriptor(self))
def WriteValue(self, value, options):
val = str(value[0]).upper()
if val == "C":
self.service.set_farenheit(False)
elif val == "F":
self.service.set_farenheit(True)
def ReadValue(self, options):
value = []
if self.service.is_farenheit(): val = "F"
else: val = "C"
value.append(dbus.Byte(val.encode()))
return value
class UnitDescriptor(Descriptor):
UNIT_DESCRIPTOR_UUID = "2901"
UNIT_DESCRIPTOR_VALUE = "Temperature Units (F or C)"
def __init__(self, characteristic):
Descriptor.__init__(
self, self.UNIT_DESCRIPTOR_UUID,
["read"],
characteristic)
def ReadValue(self, options):
value = []
desc = self.UNIT_DESCRIPTOR_VALUE
for c in desc:
value.append(dbus.Byte(c.encode()))
return value
app = Application()
app.add_service(ThermometerService(0))
app.register()
adv = ThermometerAdvertisement(0)
adv.register()
I have the following two classes:
class QPolygonModel(QtGui.QPolygon):
_idx = None
_selected = None
def __init__(self, idx, polygon: QtGui.QPolygon = None):
# Call default constructor
if polygon is None:
super().__init__()
# Call copy constructor
else:
super().__init__(polygon)
self._idx = idx
self._selected = False
#property
def idx(self):
return self._idx
#property
def is_selected(self):
return self._selected
#is_selected.setter
def is_selected(self, flag):
self._selected = flag
def get_points(self):
res = []
for i in range(0, self.size()):
res.append(self.point(i))
return res
This is a custom polygon class that inherits from QPolygon. Objects of this class are stored in a list in the "Scene" class:
class ImageAnnotatorState:
points = None
radius = None
image = None
polygons = None
_finished = None
multiselect = None
def __init__(self, image):
super().__init__()
self.points = QtGui.QPolygon()
self.radius = 8
self.image = image
self.polygons = self._init_polygons()
self.is_finished = False
self.multiselect = False
def _init_polygons(self):
result = []
for annotation in self.image.annotations:
polyline = QPolygonModel(annotation.get_id())
for point in annotation.points:
q_point = QPoint(point.x, point.y)
polyline.append(q_point)
result.append(polyline)
return result
#property
def is_finished(self):
return self._finished
#is_finished.setter
def is_finished(self, flag):
self._finished = flag
Now for the purpose of creating an undo function, I need to create a deepcopy of this scene class so I can store the state that was active before a scene change was made.
So in a QDialog form, I try to do the following:
class ImageAnnotator(QDialog):
_state = None
_previous_state = None
def __init__(self, image):
super().__init__()
self._state = ImageAnnotatorState(image)
self._previous_state = copy.deepcopy(self._state)
self.show()
The deepcopy call here fails with the following exception:
SystemError: attempt to pickle unknown type 'QPolygonModel'
What am I doing wrong?
EDIT:
Reproducible example:
from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QDialog
from PyQt5.QtWidgets import QApplication
import copy
import sys
class Test(QtGui.QPolygon):
idx = None
def __init__(self, z = None):
if z is None:
super().__init__()
else:
super().__init__(z)
class State:
test = None
def __init__(self):
self.test = [Test(), Test()]
print(self.test)
class Main(QDialog):
state = None
prev = None
def __init__(self):
super().__init__()
self.state = State()
prev = copy.deepcopy(self.state)
print(prev)
app = QApplication(sys.argv)
Main()
It seems that it is a bug similar to the one that ekhumoro points out in this answer. A workaround is to implement the __deepcopy__ method.
On the other hand if you want to set the default value in the case of QPolygon do not use None but an empty QPolygon.
With the above, I have implemented the following:
import copy
import random
from PyQt5 import QtCore, QtGui
class QPolygonModel(QtGui.QPolygon):
def __init__(self, idx, polygon=QtGui.QPolygon()):
super().__init__(polygon)
self._idx = idx
self._selected = False
#property
def idx(self):
return self._idx
#property
def is_selected(self):
return self._selected
#is_selected.setter
def is_selected(self, flag):
self._selected = flag
def get_points(self):
res = []
for i in range(0, self.size()):
res.append(self.point(i))
return res
# https://stackoverflow.com/a/10622689
def __deepcopy__(self, memo):
o = QPolygonModel(self.idx)
o.__dict__.update(self.__dict__)
ba = QtCore.QByteArray()
stream_w = QtCore.QDataStream(ba, QtCore.QIODevice.WriteOnly)
stream_w << self
stream_r = QtCore.QDataStream(ba, QtCore.QIODevice.ReadOnly)
stream_r >> o
return o
class State:
def __init__(self):
self.polylines = []
for _ in range(4):
poly = QtGui.QPolygon(
[QtCore.QPoint(*random.sample(range(10), 2)) for _ in range(4)]
)
polyline = QPolygonModel(random.randint(0, 10), poly)
self.polylines.append(polyline)
if __name__ == "__main__":
curr = State()
prev = copy.deepcopy(curr)
assert len(curr.polylines) == len(prev.polylines)
for polyline1, polyline2 in zip(curr.polylines, prev.polylines):
assert id(polyline1) != id(polyline2)
assert polyline1.size() == polyline2.size()
assert polyline1.is_selected == polyline2.is_selected
assert polyline1.idx == polyline2.idx
for i, j in zip(range(polyline1.size()), range(polyline2.size())):
assert polyline1.point(i) == polyline2.point(j)
I'm working through this book and am trying to extend its code to make a half adder and eventually a full adder.
I think I should be implementing a way to return the carry and bits from the half adder separately to facilitate connection to later gates. However, that's where I'm blanking. I also need some way to call performGateLogic on the HalfAdder and 'pipe' the inputs to both the XorGate and AndGate and have tried so with Connectors. My brain is just being tied in a pretzel over the method calling and class relations here and I'd appreciate someone straightening it out.
class LogicGate:
def __init__(self,n):
self.name = n
self.output = None
def getName(self):
return self.name
def getOutput(self):
self.output = self.performGateLogic()
return self.output
class BinaryGate(LogicGate):
def __init__(self,n):
LogicGate.__init__(self,n)
self.pinA = None
self.pinB = None
def getPinA(self):
if self.pinA == None:
return int(input("Enter Pin A input for gate "+self.getName()+"-->"))
else:
return self.pinA.getFrom().getOutput()
def getPinB(self):
if self.pinB == None:
return int(input("Enter Pin B input for gate "+self.getName()+"-->"))
else:
return self.pinB.getFrom().getOutput()
def setNextPin(self,source):
if self.pinA == None:
self.pinA = source
else:
if self.pinB == None:
self.pinB = source
else:
print("Cannot Connect: NO EMPTY PINS on this gate")
class AndGate(BinaryGate):
def __init__(self,n):
BinaryGate.__init__(self,n)
def performGateLogic(self):
a = self.getPinA()
b = self.getPinB()
if a==1 and b==1:
return 1
else:
return 0
class XorGate(BinaryGate):
def __init__(self,n):
BinaryGate.__init__(self,n)
def performGateLogic(self):
a = self.getPinA()
b = self.getPinB()
if (a ==1 and b==0) or (a==0 and b==1):
return 1
else:
return 0
class Connector:
def __init__(self, fgate, tgate):
self.fromgate = fgate
self.togate = tgate
tgate.setNextPin(self)
def getFrom(self):
return self.fromgate
def getTo(self):
return self.togate
class HalfAdder(BinaryGate):
def __init__(self,n):
BinaryGate.__init__(self,n)
self.bits, self.carry = None, None
self.a, self.b = None, None
self.xor = XorGate('XO')
self.and_ = AndGate('A')
self.c1 = Connector(self.xor.getPinA(), self.and_.getPinA())
self.c2 = Connector(self.xor.getPinB(), self.and_.getPinB())
def performGateLogic(self):
self.a = self.getPinA()
self.b = self.getPinB()
self.bits = 1 if (self.a ==1 and self.b==0) or (self.a==0 and self.b==1) else 0
self.carry = 1 if (self.a==1 and self.b ==1) else 0
return self.bits + self.carry
Running print(HalfAdder('HA').getOutput()) yields
File "./circuits.py", line 178, in __init__
self.c1 = Connector(self.xor.getPinA(), self.and_.getPinA())
File "./circuits.py", line 161, in __init__
tgate.setNextPin(self)
AttributeError: 'int' object has no attribute 'setNextPin'
Something is being set to an int but where, I can't find.
I have an entire Deque Array class that looks like this:
from collections import deque
import ctypes
class dequeArray:
DEFAULT_CAPACITY = 10 #moderate capacity for all new queues
def __init__(self):
self.capacity = 5
capacity = self.capacity
self._data = self._make_array(self.capacity)
self._size = 0
self._front = 0
def __len__(self):
return self._size
def __getitem__(self, k): #Return element at index k
if not 0 <= k < self._size:
raise IndexError('invalid index')
return self._data[k]
def isEmpty(self):
if self._data == 0:
return False
else:
return True
def append(self, item): #add an element to the back of the queue
if self._size == self.capacity:
self._data.pop(0)
else:
avail = (self._front + self._size) % len(self._data)
self._data[avail] = item
self._size += 1
#def _resize(self, c):
#B = self._make_array(c)
#for k in range(self._size):
#B[k] = self._A[k]
#self._data = B
#self.capacity = capacity
def _make_array(self, c):
capacity = self.capacity
return (capacity * ctypes.py_object)()
def removeFirst(self):
if self._size == self.capacity:
self._data.pop(0)
else:
answer = self._data[self._front]
self._data[self._front] = None
self._front = (self._front + 1) % len(self._data)
self._size -= 1
print(answer)
def removeLast(self):
return self._data.popleft()
def __str__(self):
return str(self._data)
and when I try to print the deque in the main it prints out something like this,
<bound method dequeArray.__str__ of <__main__.dequeArray object at 0x1053aec88>>
when it should be printing the entire array. I think i need to use the str function and i tried adding
def __str__(self):
return str(self._data)
and that failed to give me the output. I also tried just
def __str__(self):
return str(d)
d being the deque array but I still am not having any success. How do I do i get it to print correctly?
you should call the str function of each element of the array that is not NULL, can be done with the following str function:
def __str__(self):
contents = ", ".join(map(str, self._data[:self._size]))
return "dequeArray[{}]".format(contents)
What I get when I try to q = dequeArray(); print(q) is <__main__.py_object_Array_5 object at 0x006188A0> which makes sense. If you want it list-like, use something like this (print uses __str__ method implicitly):
def __str__(self):
values = []
for i in range(5):
try:
values.append(self._data[i])
except ValueError: # since accessing ctypes array by index
# prior to assignment to this index raises
# the exception
values.append('NULL (never used)')
return repr(values)
Also, several things about the code:
from collections import deque
This import is never user and should be removed.
DEFAULT_CAPACITY = 10
is never used. Consider using it in the __init__:
def __init__(self, capacity=None):
self.capacity = capacity or self.DEFAULT_CAPACITY
This variable inside __init__ is never user and should be removed:
capacity = self.capacity
def _make_array(self, c):
capacity = self.capacity
return (capacity * ctypes.py_object)()
Though this is a valid code, you're doing it wrong unless you're absolutely required to do it in your assignment. Ctypes shouldn't be used like this, Python is a language with automated memory management. Just return [] would be fine. And yes, variable c is never used and should be removed from the signature.
if self._data == 0
In isEmpty always evaluates to False because you're comparing ctypes object with zero, and ctypes object is definitely not a zero.