def test_socket(self): """" Tests that sockets compare equally """ s1 = classes.Socket(classes.Spring()) s2 = classes.Socket(classes.Spring()) ## Something is seriously wrong if this first one doesn't pass... self.assertEqual(s1, s1) self.assertEqual(s1, s2)
def generate_compound_general(torque,turns,pipe = None): """ Uses the old method for constructing a Compound Assembly """ pipe = validate_assembly_pipe(pipe) for wire in [wire for wire in iterwire(reverse= True) if wire['min_od'] <= pipe.max_wireod]: spring = classes.Spring(wire, od = pipe.max_wireod, cycles= pipe.cycles) ## Strongest a spring can be is when turns is equal to max turns ## Max turns is MP / Torque, therefore Torque = MP / Max Turns ## 1.05 is a safety factor (increased from 1.015) st = spring.mp / turns / 1.05 ## If outerwire can do all the pulling itself, we won't return it with this method ## (generate_single_springs will return it) if st >= torque * .95: continue spring.setlengthbytorque(st) #print(torque, st, spring.lift) remaining = torque - spring.lift maxod = max(od for od in SPRINGOD if od and od < spring.id) modmp = turns * remaining / pipe.cyclerating inners = [wire for wire in iterwire(reverse = True) if wire['min_od'] <= maxod and wire['mp_base'] > turns * remaining / pipe.cyclerating] for inner in inners: innerspring = classes.Spring(inner, od = maxod, cycles = pipe.cycles) innerspring.setlengthbytorque(remaining) assembly = classes.Socket(spring,innerspring) if assembly.validate(turns): return assembly ## TODO: Mostly a placeholder; not sure whether to raise Exception if no compounds generated or just return an empty list. return []
def test_addsocket(self): """ Tests that Assembly.addsocket works as expected """ assem = classes.Assembly() socket = classes.Socket(classes.Spring()) assem.addsocket(socket) self.assertEqual(len(assem.sockets), 1) self.assertEqual(assem.sockets[0], socket)
def build_assemblywrapper_tests(): """ Separate Area for putting together the tests for test_assemblywrapper """ ## Test that a Single Spring output results in 1 Assembly with 1 Single-Spring Assembly test1 = [ classes.Spring(), ] assembly1 = classes.Assembly() assembly1.addsocket(classes.Socket(*test1)) ## Test that a list of springs gets turned into single-spring assemblies test2 = [classes.Spring(), classes.Spring()] assembly2 = [classes.Assembly() for spring in test2] for spring, assembly in zip(test2, assembly2): assembly.addsocket(classes.Socket(spring)) ## Test that a Single Socket output results in 1 Assembly with 1 Socket test3 = classes.Socket(classes.Spring()) assembly3 = classes.Assembly() assembly3.addsocket(test3) ## Test that list of sockets gets turned into single-socket Assemblies test4 = [ classes.Socket(classes.Spring()), classes.Socket(classes.Spring()) ] assembly4 = [classes.Assembly() for socket in test4] for socket, assembly in zip(test4, assembly4): assembly.addsocket(socket) ## Test that a mix of Sockets and Springs gets sorted into their own assemblies (adding sockets for individual springs) test5 = [classes.Spring(), classes.Socket(classes.Spring())] assembly5 = [classes.Assembly(), classes.Assembly()] assembly5[0].addsocket(classes.Socket(test5[0])) assembly5[1].addsocket(test5[1]) ## Test that a single assembly results in the assembly being outputted without change test6 = [ classes.Assembly(), ] test6[0].addsocket(classes.Socket(classes.Spring())) assembly6 = test6[0] return [ (test1, [ assembly1, ]), (test2, assembly2), (test3, [ assembly3, ]), (test4, assembly4), (test5, assembly5), (test6, [ assembly6, ]), ]
def API_setsprings(request): data = request.POST doorid = data.get("doorid") if doorid is None: return dhttp.HttpResponseServerError("Not Implemented") door = models.Door.objects.filter(doorid=doorid).first() if not door: return dhttp.HttpResponseBadRequest("Invalid Door ID") pipeobj = models.Pipe.objects.filter(door = door).first() pipesize = data.get("pipe") if not pipesize: if not pipeobj or not pipeobj.pipediameter: return dhttp.HttpResponseBadRequest("Door requires Pipe Size") pipesize = pipeobj.pipediameter else: pipeobj.pipediameter = pipesize assembly = data.get("assembly") if assembly: assembly = json.loads(assembly) castings = assembly.get("castings", False) if not assembly or not castings: return dhttp.JsonResponse({"success":False,"reason":"nocastings"}) doorinstance = dio.to_doorinstance(door) doorinstance.pipe.shell = pipesize oval.checkdefaults(doorinstance) #oval._set_slats(doorinstance) assemblyinstance = doorinstance.pipe.assembly assemblyinstance.clear() for casting in castings: castingobj = classes.Socket() for spring in casting: springobj = classes.Spring(wire = float(spring['gauge']), od = float(spring['od'])) springobj.coils = float(spring['coils']) castingobj.addspring(springobj) assemblyinstance.addsocket(castingobj) if not doorinstance.validatepipeassembly(): return dhttp.JsonResponse({"success":False,"reason":"badcastings"}) ## Remove previous springs models.Spring.objects.filter(pipe = pipeobj).delete() ## Save Springs for c,casting in enumerate(assemblyinstance.sockets): for i,spring in enumerate(casting.springs): models.Spring(pipe = pipeobj, spring_type = models.Spring.TYPE[i][0], outer_diameter = spring.od, wire_diameter = spring.wirediameter, uncoiledlength= spring.uncoiledlength, casting = c).save() orderid = door.order.pk return dhttp.JsonResponse({"success":True,"target": reverse("orderoverview",args = (orderid,))})
def get_all_compounds(pipe = None): """ Based on the given pipe, return a list of all 2-Spring Compound sockets that will fit inside. This only validates that each inner wire will fit inside the outer wire and that the outerwire will fit inside the pipe: it DOES NOT validate that the given set of springs will be valid for any given amount of required torque (if at all). """ pipe = validate_assembly_pipe(pipe) output = _get_all_compound_springs(pipe = pipe) return [classes.Socket(*[classes.Spring(**spring, cycles = pipe.cycles) for spring in springs]) for springs in output]
def test_compare_socket(self): """ Simple test for compare_socket """ s1, s2 = classes.Socket(), classes.Socket() self.assertEqual(methods.compare_socket(s1, s2), []) sp1 = classes.Spring(.5) s1.addspring(sp1) self.assertEqual(methods.compare_socket(s1, s2), [ Difference("Socket Difference", Difference("Extra Spring", (1, sp1))) ]) s2.addspring(sp1) self.assertEqual(methods.compare_socket(s1, s2), []) c1 = nddmethods.convert_to_casting("Standard 4 Pipe") s2.castings.addcasting(c1) self.assertEqual(methods.compare_socket(s1, s2), [ Difference("Socket Difference", Difference("Extra Casting", (2, c1))) ])
def test_getcasting(self): """ Tests the getcasting method for expected values. The expected output of this method should be inspected if castings are changed or added. """ for result, wires in [ (["Standard 4 Pipe", "Standard 2 Spring"], [ (.1875, 2.75), ]), ]: with self.subTest(result=result, wires=wires): result = classes.CastingSet(*result) springs = [classes.Spring(wire, od=od) for (wire, od) in wires] ## socket automatically runs getcasting when casting is False socket = classes.Socket(*springs, castings=False) self.assertEqual(socket.castings, result)
def convertitem(item): """ Convenience Function """ ## We don't recurse for Springs (which would then convert to Assembly) ## because this Spring may be part of a list of single-spring sockets if isinstance(item,classes.Spring): return classes.Socket(item) ## Sockets get converted to Assemblies if isinstance(item,classes.Socket): assembly = classes.Assembly() assembly.addsocket(item) return assembly ## Assemblies are already in the end state if isinstance(item,classes.Assembly): return item ## Lists that are passed to this function should only contain Sockets ## (which are used to construct an Assembly) if isinstance(item,(list,tuple)): if not all(isinstance(x,classes.Socket) for x in item): raise ValueError(f"Lists should only contain Sockets: {item}") asssembly = classes.Assembly() for socket in item: assembly.addsocket(socket) return assembly ## Anything else is an Exception raise ValueError(f"Invalid Item: {item}")
BUILD_SOCKET_VALUES = [ (([], []), []), ( ## 2.75 Inch Spring ## Test ([ c.Spring( wire=.1875, od=2.75, ), ], ["Standard 4 Pipe", "Standard 2 Spring"]), ## Result [ c.Socket(c.Spring( wire=.1875, od=2.75, ), castings=c.CastingSet("Standard 4 Pipe", "Standard 2 Spring")) ]), ( ## 3.75 Inch Spring ## Test ([ c.Spring( wire=.3125, od=3.75, ), ], ["Standard 4 Pipe", "Standard 4 Spring"]), ## Result [ c.Socket(c.Spring(wire=.3125, od=3.75), castings=c.CastingSet("Standard 4 Pipe",
def to_doorinstance(doorobj): """ Converts a Django Door Model to a NewDadsDoor Door Instance (as well as all components) """ if not isinstance(doorobj, models.Door): raise ValueError("to_doorinstance only accepts a Door Model instance") doorinstance = classes.Door(**doorobj.to_kwargs()) hood = doorinstance.sethood() tracksobj = models.Tracks.objects.filter(door=doorobj.pk).first() tracks = doorinstance.settracks() if tracksobj: doorinstance.bracketplatesize = float( tracksobj.brackets.bracket_size ) if tracksobj.brackets.bracket_size else tracksobj.brackets.bracket_size if tracksobj.outer_angle_height: tracks.outer = tracksobj.outer_angle_height if tracksobj.inner_angle_height: tracks.inner = tracksobj.inner_angle_height if tracksobj.wall_angle_height: tracks.wall = tracksobj.wall_angle_height pipeobj = models.Pipe.objects.filter(door=doorobj.pk).first() if pipeobj: pipe = doorinstance.setpipe(**pipeobj.to_kwargs()) assembly = pipe.setassembly() springs = models.Spring.objects.filter(pipe=pipeobj.pk) castings = sorted( list( set(spring.casting for spring in springs if spring is not None))) for casting in castings: ## Instead of referencing spring_type to determine order, we're just going to sort the od spngs = sorted(springs.filter(casting=casting), key=lambda spring: spring.outer_diameter, reverse=True) spngs = [classes.Spring(**spring.to_kwargs()) for spring in spngs] socket = classes.Socket(*spngs) assembly.addsocket(socket) else: pipe = doorinstance.setpipe() assembly = pipe.setassembly() curtain = doorinstance.setcurtain() for slatobj in models.Slats.objects.filter(door=doorobj.pk): slats = classes.SlatSection(curtain=curtain, **slatobj.to_kwargs()) curtain.append(slats) bbarobj = models.BottomBar.objects.filter(door=doorobj.pk).first() if bbarobj: bbar = classes.BottomBar(**bbarobj.to_kwargs()) curtain.append(bbar) accessories = [] for accessorytype in models.ACCESSORYLIST: for accessory in accessorytype.objects.filter(door=doorobj.pk): o = {"kind": accessory.kind, "description": accessory.description} ## TODO: expand this accessories.append(o) doorinstance.accessories = accessories return doorinstance
import unittest ## This module from NewDadsDoor import constants, pipecalculations, methods ## 3rd Party from alcustoms import measurement ## Basic Springs INNER1 = classes.Spring() OUTER1 = classes.Spring(wire=.375, od=3.75) OUTER2 = classes.Spring(wire=.5, od=5.625) INNER1.coiledlength = 40 OUTER1.coiledlength = 50 VALIDSOCKETS = [ classes.Socket(), ## Empty Socket classes.Socket(INNER1), ## Single Spring (smallest) classes.Socket(OUTER1), ## Single Spring (largest in 4" pipe) classes.Socket(OUTER1, INNER1), ## 4" Duplex ] class DoorCase(unittest.TestCase): """ Test case for the Door Class """ def test_setsizes(self): """ Test that doors can be initialized and later changed to different heights/widths in different formats and that they are always Measurments """ size = "12ft-0/1in" door = classes.Door(size, size) ## Initial initialization test self.assertEqual(door.clearopening_height, 144) self.assertEqual(door.clearopening_width, 144)
def build_sockets(springs, castings): """ Builds Sockets from a list of springs and a corresponding list of Castings. springs should be a list of classes.Spring instances. castings should be a list of dictionaries taken from constants.CASTINGS or the string ['name'] value taken from that list. Returns a list of castings. Castings without Springs will simply be discarded. At least one Pipe Casting is required if any Springs are passed. Every Spring requires a Spring Casting. If the Springs and either type of Castings are mismatched (either too many of one or not enough) a ValueError is raised. """ if not all(isinstance(spring, classes.Spring) for spring in springs): raise TypeError("Springs should be a list of Spring objects.") _c = [] for casting in castings: ## Check if castings are strings and try to convert them if necessary. casting = convert_to_casting(casting) _c.append(casting) castings = _c del _c ## Sort Castings into pipe/spring types pipecastings, springcastings = [], [] for casting in sorted(castings, key=lambda casting: max(casting['ods']), reverse=True): if casting['type'] == 'pipe': pipecastings.append(casting) else: springcastings.append(casting) ## If there are no Springs, we can return an empty list since all ## Castings are extra and therefore disregarded if not springs: return [] ## There should be atleast one Pipe Casting if len(pipecastings) < 1: raise ValueError("At least one Pipe Casting is required") ## Every spring should have its own Spring Casting if len(springs) != len(springcastings): raise ValueError("Insufficient Spring Castings") ## Sort Springs by OD, wire, and coiledlength (largest->smallest on all categories) springs = sorted(sorted(sorted(springs, key=lambda spring: spring.coiledlength, reverse=True), key=lambda spring: spring.wirediameter, reverse=True), key=lambda spring: spring.od, reverse=True) sockets = [] """ Dev Note: Algorithm ( While Pipe Casting and Springs: Check Socket: If no socket: pop Pipe casting ( for Springs Check Next Spring: Check pipe casting fit Check previous spring fit If Next Spring: ( for spring castings Check next Spring Casting fit ) ) If not Spring and Spring Casting: If Pipe Casting doesn't have a single successful spring: raise Error add Socket to output clear socket continue from beginning Pop Spring and Spring Casting Add Spring and Spring Casting to Socket If no slots open on Socket: add Socket to output clear socket ) """ socket = None while (socket or pipecastings) and springs: if not socket: pipecasting = pipecastings.pop(0) castingset = classes.CastingSet(pipecasting) socket = classes.Socket(castings=castingset) spring = None springcasting = None for pospring in springs: ## If pipe casting can't accept the spring, skip it if pospring.od not in pipecasting['ods'][len(socket.springs):]: continue ## If previous spring can't accept the spring, skip it if socket.springs and socket.springs[-1].id < pospring.od: continue ## Otherwise we can find a spring casting for it for pocast in springcastings: if pospring.od in pocast['ods']: springcasting = pocast break if springcasting: spring = pospring break if not spring or not springcasting: ## Socket does not have any springs at all if not socket.springs: raise ValueError("Mismatched Pipe Casting") ## Socket is not a compound: store and restart with no socket sockets.append(socket) socket = None continue springs.remove(spring) springcastings.remove(springcasting) socket.addspring(spring) castingset.addcasting(springcasting) ## Socket is full: store and restart with no socket if len(socket.springs) == socket.castings.maxsprings: sockets.append(socket) socket = None continue ## Mismatched Springs if springs: raise ValueError(f"Mismatched Springs: {springs}") ## Mismatched Spring Castings if springcastings: raise ValueError("Mismatched Spring Castings: {springcastings}") ## If there's an open socket, add it to output if socket: sockets.append(socket) return sockets