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_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 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 test_od_None(self): """ Tests that ommitting od results in min_od specified by the wire """ for testwire in [.25, .375, .5]: with self.subTest(testwire=testwire): self.assertEqual( classes.Spring(testwire).od, constants.WIRE[testwire]['min_od'])
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 test_build_sockets_bad(self): """ Bad arguments for build_sockets """ self.assertRaises(ValueError, methods.build_sockets, [ classes.Spring( wire=.1875, od=2.75, ), ], ["Standard 2 Spring"])
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 generate_single_spring(torque, turns, pipe = None): """ Generates a list of valid Assemblies """ pipe = validate_assembly_pipe(pipe) od = max([od for od in WIREODINDEX if od <= pipe.max_wireod]) ## Get a list of springs that will fit inside the OD potential_springs = [classes.Spring(wire = wire['wirediameter'], od = od, cycles = pipe.cycles) for wire in WIRE.values() if wire['min_od'] <= od] ## Set length of all springs to match torque for spring in potential_springs: spring.setlengthbytorque(torque) ## Validate springs valid_springs = list(filter(lambda spring: spring.validatemaxturns(turns),potential_springs)) ## Return valid springs return valid_springs
def test_compare_assembly(self): """ Simple test for compare_assembly """ a1, a2 = classes.Assembly(), classes.Assembly() self.assertEqual(methods.compare_assembly(a1, a2), []) s1 = nddmethods.build_sockets([ classes.Spring(.375), ], ["Standard 4 Pipe", "Standard 4 Spring"])[0] a1.addsocket(s1) self.assertEqual(methods.compare_assembly(a1, a2), [ Difference("Assembly Extra Socket", (1, s1)), ]) s2 = nddmethods.build_sockets([ classes.Spring(.3125), ], ["Standard 4 Pipe", "Standard 2 Spring"])[0] a2.addsocket(s2) self.assertEqual(methods.compare_assembly(a1, a2), [ Difference("Assembly Extra Socket", (1, s1)), Difference("Assembly Extra Socket", (2, s2)) ])
def test_get_all_compound_castings(self): """ Tests that get_all_compounds can be safely used without throwing Casting errors. """ ## Using a None-type pipe allows us to get all possible spring configurations pipe = pipecalculations.validate_assembly_pipe(None) ## _get_all_compound_springs is a testing/extension method that will avoid generating the Sockets immediately ## which allows us to see what Springs (if any) cannot be matched to a Casting configuration springs = pipecalculations._get_all_compound_springs() for pair in springs: with self.subTest(pair=pair): ## Cycles is probably unnecessary as we aren't validating here. springs = [ classes.Spring(**spring, cycles=pipe.cycles) for spring in pair ] ## See if this raises an exception methods.getcasting(*springs)
def parsesheet_toDoor(costingsheet: "CostingSheet") -> "NewDadsDoor.Door": """ Converts a CostingSheet Instance into a NewDadsDoor.Door """ ## Convert feet to inches (or otherwise could convert to a string) door = nddmethods.basic_torsion_door(costingsheet.width * 12, costingsheet.height * 12) table = get_table_by_name(costingsheet.workbook, "CostsTable") ## First item is header list _, *rows = table.todicts() springs = filter(lambda row: constants.SPRINGRE.match(row['Item']), rows) springs = [(constants.SPRINGRE.search(row['Item']), row['Unit/Qty'] * 12) for row in springs] wires = [ classes.Spring(wire=fixwire(spring['wire']), od=float(spring['size']), coiledlength=float(length)) for spring, length in springs ] castings = _convert_castings( filter(lambda row: constants.CASTINGRE.match(row['Item']), rows)) sockets = nddmethods.build_sockets(wires, castings) door.pipe.assembly = sockets shaft = list( filter( lambda row: row['Subcomponent'] == "Assembly" and "Solid Shaft" in row['Item'], rows)) if shaft: shaft = shaft[0] shaftsize = constants.SHAFTRE.match(shaft['Item']).group("shaftsize") shaftsize = Imperial(shaftsize) slats = list( filter( lambda row: row['Subcomponent'] == "Curtain" and "Slats" in row[ 'Item'], rows)) if slats: slats = slats[0] curtainslats = door.curtain.slatsections()[0] if "528" in slats['Item ID']: curtainslats.slat = "2 1/2 INCH FLAT SLAT" else: curtainslats.slat = "2 7/8 INCH CROWN SLAT" curtainslats.slats = slats['Qty'] return door
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 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 _get_all_compound_springs(pipe = None): """ For extension and testing purposes, the body of get_all_compounds was extracted so that its output is Class Agnostic. This function returns tuple-pairs of dicts (outer,inner) -> {wire:wirediameter [float], od:wire_od [float]} """ pipe = validate_assembly_pipe(pipe) maxindex = max([i for i,od in enumerate(WIREODINDEX) if od <= pipe.max_wireod]) ## If we can only use the smallest OD, then we can't generate any Compounds if maxindex < 1: return [] output = [] ## Stop before the smallest OD outerods = WIREODINDEX[maxindex:0:-1] for out_od in outerods: #print() #print(out_od) out_wires = [wire for wire in WIRE.values() if wire['min_od'] <= out_od] for outer in out_wires: #print(">>>",outer['wirediameter']) outerspring = classes.Spring(wire = outer, od = out_od, cycles = pipe.cycles) id = outerspring.id #print(">>>>>>>",id) ## Try for every possible id for in_od in [od for od in WIREODINDEX if od < id]: #print(">>>>>>>>>>>",in_od) ## Inner Wires are a natural subset of Outer Wires in_wires = [wire for wire in out_wires if wire['min_od'] <= in_od] for inner in in_wires: #print(">>>>>>>>>>>>>>>",inner['wirediameter']) ospring = dict(wire = outer['wirediameter'], od = out_od) ispring = dict(wire = inner['wirediameter'], od = in_od) output.append((ospring, ispring)) ## NOTE: I don't think this should ever need to be pared down (i.e.- I don't ## think it will ever produce duplicates) but it's something to keep in mind return output
""" NewDadsDoor.tests.utils.methods Utilties for testing NewDadsDoor.methods """ from NewDadsDoor import classes as c, constants 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,
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
Tests for the NewDadsDoor.classes module """ ## Test Target from NewDadsDoor import classes ## Test Framework 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):