def HoleBasic(D, d): '''D is hole size in inches. ''' shaft_size_in = D shaft_size_mm = D * in2mm print("Hole size is basic:") hole_size_in = float(D) hole_size_mm = in2mm * D print(''' Shaft size Clearance in mm mils mm ------- -------- ----- ------ '''[1:-1]) for name, constant, allowance in fits: correction = (allowance * hole_size_in + constant) / 1000 shaft_size_in = hole_size_in + correction shaft_size_mm = shaft_size_in * in2mm clearance_mils = (hole_size_in - shaft_size_in) * 1000 clearance_mm = clearance_mils * in2mm / 1000 s = " %-18s %10.4f %10.3f" % (name, shaft_size_in, shaft_size_mm) print(s, end=" ") s = "%8.1f %8.2f" % (clearance_mils, clearance_mm) color.fg(interference if clearance_mm < 0 else clearance) print(s) color.normal()
def Execute(cmd, d): '''cmd is of the form (src, dest, cmdlist) where src is the source file, dest is the destination file, and cmdlist is the set of commands to execute if src is newer than dest. ''' src, dest, cmdlist = cmd # Get last modification times try: tm_src = os.stat(src).st_mtime tm_dest = os.stat(dest).st_mtime except Exception as e: msg = "Couldn't get modification times for '%s' or '%s'" c.fg(c.yellow) print(msg % (src, dest)) c.normal() return if tm_src <= tm_dest: return # Execute commands because source is newer than destination print("'%s' is newer than '%s' [%s]" % (src, dest, GetTime(d))) for cmd in cmdlist: if d["-n"]: print("Dry run: ", cmd, "[%s]" % GetTime(d)) else: status = os.system(cmd) if status: c.fg(lred) print("'%s' returned nonzero status" % cmd) c.normal()
def Rename(fn, d): '''Rename the file named fn to all upper or lower case. Also append the tuple (oldname, newname) to let us write a command to reverse the renamings made. NOTE: we don't save the commands to undo directory name changes because there are cases where it's not easy to recover. ''' new_name = GetNewName(fn, d) is_dir = os.path.isdir(fn) arrow, s = "-->", "/" if is_dir else "" msg = "mv '{}{}' {} '{}{}'".format(fn, s, arrow, new_name, s) if fn != new_name: if is_dir and os.path.isdir(new_name): print("Can't " + msg + ":", file=sys.stderr) print(" Directory already exists", file=sys.stderr) elif os.path.isfile(fn) and os.path.isfile(new_name): print("Can't " + msg + ":", file=sys.stderr) print(" File already exists", file=sys.stderr) if d["-x"] or d["-X"]: try: os.rename(fn, new_name) s = msg.replace(arrow, "") if not is_dir: d["log"].append((fn, new_name)) except os.error: c.fg(c.lblue) print("Couldn't {}".format(msg)) c.normal() else: if is_dir: c.fg(c.lred) print(msg) c.normal()
def Quotient(d, ratio): # Ignore a requested ratio of 1, as any pair of resistors will work if ratio == 1: out("Quotient cannot be 1") exit(1) d["resistances"], t, Ratio = set(), d["-t"], float(ratio) for R1, R2 in combinations(d["R"], 2): q1 = R1/R2 q2 = 1/q1 if (1 - t)*Ratio <= q1 <= (1 + t)*Ratio: d["resistances"].add((q1, R1, R2)) elif (1 - t)*Ratio <= q2 <= (1 + t)*Ratio: d["resistances"].add((q2, R2, R1)) # Print report res = list(d["resistances"]) if not res: out("No resistor combinations that meet tolerance") return res.sort() out("Desired ratio = ", ratio, ", tolerance = ", sig(d["-t"]*100, 2), "%", sep="") out() out("% dev from") out("desired ratio R1 R2") out("------------- ---------- ----------") for val, r1, r2 in res: dev = 100*((val - Ratio)/Ratio) pct = sig(dev, 2) if dev >= 0: pct = " " + pct R1, R2 = fp.engsi(r1), fp.engsi(r2) if not dev: fg(highlight) out(" {0:10} {1:^10} {2:^10}".format(pct, R1, R2)) normal()
def Divider(d, ratio): d["divider"] = set() # First check using equal resistors for R in d["R"]: Div(d, float(ratio), R, R) for R1, R2 in combinations(d["R"], 2): Div(d, float(ratio), R1, R2) # Print report div = list(d["divider"]) if not div: out("No divider can be made") return div.sort() out("Voltage divider with ratio = ", ratio, ", tolerance = ", sig(d["-t"]*100, 2), "%", sep="") out() out("% dev from") out("desired ratio R1 R2 Total Res.") out("------------- ---------- ---------- ----------") for rat, r1, r2 in div: dev = 100*((rat - float(ratio))/float(ratio)) pct = sig(dev) if dev >= 0: pct = " " + pct R1, R2, R = fp.engsi(r1), fp.engsi(r2), fp.engsi(r1 + r2) if not dev: fg(highlight) out(" {0:10} {1:^10} {2:^10} {3:^10}".format(pct, R1, R2, R)) normal()
def Resistance(d, resistance): d["resistances"] = set() # First see if we have an exact match if resistance in d["R"]: d["resistances"].add((resistance, "e", resistance, 0)) else: # First check using equal resistors for R in d["R"]: Res(d, resistance, R, R) for R1, R2 in combinations(d["R"], 2): Res(d, resistance, R1, R2) res = list(d["resistances"]) if not res: out("No resistor combinations that meet tolerance") return # Check if we have too many entries; if so, whittle down the list to # the closest N. clipped = False if len(res) > d["-n"]: # Sort by absolute value of tolerance tol = lambda tgt, val: abs(val - tgt)/val r = [(tol(resistance, i[0]), i) for i in res] # Decorate with abs val r.sort() res = [i[1] for i in r[:d["-n"]]] clipped = True # Print report res.sort() out("Desired resistance = ", d["desired"], " = ", sig(d["res"]) + ", tolerance = ", sig(d["-t"]*100, 2), "%", sep="") if clipped: out("Closest %d matches shown" % d["-n"]) out() out("% dev from") out("desired res. R1 R2 Connection") out("------------- ---------- ---------- ----------") for val, c, r1, r2 in res: dev = 100*((val - resistance)/resistance) pct = sig(dev, 2) if dev >= 0: pct = " " + pct R1, R2 = fp.engsi(r1), fp.engsi(r2) conn = {"s":"series", "p":"parallel", "e":"exact"}[c] if (d["-p"] and c == "s") or (d["-s"] and c == "p"): continue if not dev: fg(highlight) if c == "e": out(" {0:10} {1:^10} {2}".format(pct, R1, conn)) else: out(" {0:10} {1:^10} {2:^10} {3}".format(pct, R1, R2, conn)) normal()
def CalculateFit(cmdline, D, d): '''hole_size_inches is diameter of hole in inches. d is the settings dictionary. ''' Dmm = D * in2mm print("Diameter = " + cmdline) print(" = %.4f" % D, "inches") print(" = %.3f" % Dmm, "mm") if have_color: print(" " * 20, "Color coding: ", end=" ") color.fg(interference) print("interference", end=" ") color.fg(clearance) print("clearance") color.normal() else: print() HoleBasic(D, d) ShaftBasic(D, d)
def EraseFiles(project, info, d): '''Erase this project's destination files. project is project's name like 'elec/bnc'. info is d["data"][project]. ''' d["top_level_dirs"].add(os.path.split(project)[0]) if d["-F"]: # Force removal of directory and all files, even those that # were not copied by this script. shutil.rmtree(project, ignore_errors=True) return subdirs = set() # Keep track of subdirectories for src, dest in info["files"]: destfile = os.path.join(project, dest) try: subdirs.add(os.path.split(destfile)[0]) if os.path.isfile(destfile): os.remove(destfile) if not d["-q"]: print("Removed %s" % destfile) except Exception: c.fg(c.lred) print("Couldn't remove '%s'" % destfile) c.normal() # Remove subdirectories for subdir in subdirs: try: os.rmdir(subdir) if not d["-q"]: print("Removed directory %s" % subdir) except Exception: if os.path.isdir(subdir): print("Couldn't remove directory %s" % subdir) # All files erased, now remove project directory. An exception # means the directory probably isn't empty. try: os.rmdir(project) if not d["-q"]: print("Removed directory %s" % project) except Exception: if os.path.isdir(project): print("Couldn't remove directory %s" % project)
def MakeSoftlinks(d): Message("Making softlinks", c.lblue) for src, dest in softlinks: if not os.path.isfile(src): Error("'%s' is missing in MakeSoftlinks()" % src) if os.path.islink(dest): os.remove(dest) elif os.path.isfile(dest): Error("'%s' exists in MakeSoftlinks()" % dest) try: abs_src_dir = os.path.abspath(src) dest_dir, dest_file = os.path.split(dest) if not dest_dir: Error("ln -s '%s' '%s' on empty dir" % (src, dest)) curdir = os.getcwd() try: # Remove any existing link or file os.remove(dest) except OSError: pass # Change to the destination diretory so we can get a # relative path to the file we want to point to. if dest_dir: os.chdir(dest_dir) # Get the source directory relative to current directory relsrc = os.path.relpath(abs_src_dir) # Make the link os.symlink(relsrc, dest_file) if dest_dir: os.chdir(curdir) c.fg(c.lblue) print(" ln -s '%s' <-- '%s'" % (src, dest)) c.normal() except Exception as e: msg = ["Couldn't make softlink '%s' --> '%s'" % (src, dest)] msg += [" %s" % e] Error('\n'.join(msg))
def OO_PictureFiles(d): '''Check each file in oo_files for pictures; print out any that are missing (these then need to be added to the project's data). Note they are printed out in 'File(...)' form, allowing them to be inserted in this script's data verbatim. ''' error = False Message("Checking OO picture files", c.yellow) for path in oo_files: if not os.path.isfile(path): Error("OO_PictureFiles(): '%s' doesn't exist" % path) image_files = loo.GetImages(path) # Ignore embedded files # The returned container has elements of (path, state) where path # is relative to the OO doc's location and state is one of # "", "notrel", or "missing". Print out messages about notrel # or missing files. dir, name = os.path.split(path) # Check each picture file missing = [] for picfile, state in image_files: if state == "missing": missing.append((picfile, state)) elif state == "notrel": Error("'%s' notrel in '%s'" % (picfile, path)) if missing: if not error: print() c.fg(c.lred) print("One or more OO files missing images:") c.normal() print("\n") print("OO file '%s' missing images:" % path) for picfile, state in missing: print(' File("%s")' % picfile) error = True if error: exit(1)
def ProcessFile(oofile, d): '''Print out any linked image files in the Open Office file oofile. d is the options directory. ''' if not os.path.isfile(oofile): err("'%s' is not a file%s" % (oofile, nl)) return colors = { "missing" : (c.lwhite, c.red), "notrel" : (c.lwhite, c.magenta), "embedded" : c.lgreen, } image_files = GetImages(oofile, ignore_embedded=not d["-e"]) if not image_files and not d["-m"]: # List the file out("%s%s" % (oofile, nl)) return some_missing = any([i[1] == "missing" for i in image_files]) some_notrel = any([i[1] == "notrel" for i in image_files]) some_embedded = any([i[1] == "embedded" for i in image_files]) if d["-m"] and not (some_missing or some_notrel): # If we're only supposed to list missing stuff and this OO # file had neither, then return. return if d["-l"]: # Only list the OO files, not their contents. We'll color # code them to indicate missing or notrel content. "missing" # takes precedence over "notrel" and both take precedence over # "embedded". if some_embedded: c.fg(colors["embedded"]) if some_notrel: c.fg(colors["notrel"]) if some_missing: c.fg(colors["missing"]) out(oofile) c.normal() out(nl) return if d["-m"]: # image_files can be empty or only contain embedded files, in # which case we should return. if not image_files: return if all([IsEmbeddedImage(i[0]) for i in image_files]): return c.normal() out(oofile) out(nl) for name, state in image_files: if IsEmbeddedImage(name) and not d["-e"]: continue if d["-m"] and not state: continue out(" "*4) out(name) out(" ") if state in ("missing", "notrel", "embedded"): c.fg(colors[state]) out("[%s]" % state) c.normal() out(nl)
def Message(s, fg, bg=c.black): c.fg(fg, bg) print(s) c.normal()
def Dump(opt): '''Print a listing to stdout. ''' Colors = { 0 : { "name" : c.yellow, "files" : c.lmagenta, "softlinks" : c.lblue, "todo" : c.lred, "srcdir" : c.lgreen, }, 1 : { "name" : c.gray, "files" : c.gray, "softlinks" : c.gray, "todo" : c.gray, "srcdir" : c.gray, }, } projects = list(data.keys()) projects.sort() for project in projects: d = data[project] if d["ignore"] is not None and not opt["-i"]: continue if d["ignore"] is not None: C = Colors[1] c.normal(c.gray, c.black) else: C = Colors[0] c.normal(c.white, c.black) c.fg(C["name"]) print(project, end="") c.normal() if d["ignore"] is not None: print(" ignored: %s" % d["ignore"]) else: print() keys = list(d.keys()) keys.sort() for k in keys: if k == "files": c.fg(C["files"]) print(" Files:") for f in d["files"]: c.fg(C["files"]) if isinstance(f, (list, tuple)) and len(f) == 1: print(" %s -> %s" % (f, f)) elif isinstance(f, str): print(" %s -> %s" % (f, f)) else: print(" %s -> %s" % tuple(f)) c.normal() elif k == "softlinks": if not d[k]: continue c.fg(C["softlinks"]) print(" Softlinks:") for f in d["softlinks"]: c.fg(C["softlinks"]) print(" %s -> %s" % tuple(f)) c.normal() elif k == "descr": print(" %s =" % k) t = dedent(d[k]) print(tw.fill(t)) #for line in t.strip().split("\n"): # print(" %s" % line) elif k == "todo": c.fg(C["todo"]) if d[k] is not None: print(" %s = %s" % (k, d[k])) c.normal() elif k == "srcdir": print(" srcdir = ", end="") c.fg(C["srcdir"]) print(d[k]) c.normal() elif k == "ignore": pass elif k in ("category", "python3", "tests"): print(" %s = %s" % (k, d[k])) else: Error("Unhandled category %s" % k) print(" %s = %s" % (k, d[k])) print() c.fg(c.white, c.black) print("%d total packages" % len(data))
def Error(msg, status=1): c.fg(c.lred) print(msg) c.normal() exit(status)
# If we need to launch a file with its registered app, we use the following # command. if on_windows: start = Join(cygwin, "/usr/bin/cygstart") else: start = "exo-open" # On Linux # If a package is to be made with the -z option, this directory is where # the packages will reside (it's separate from the repository). package_dir = cygwin + "/home/Don/hobbyutil_packages" # Escape sequences for colors fz = c.fg(c.lblue, s=True) # Frozen st = c.fg(c.lred, s=True) # Stale no = c.normal(s=True) # Normal color # Text wrapper tw = textwrap.TextWrapper() tw.width = int(os.environ.get("COLUMNS", 80)) - 5 tw.replace_whitespace = True tw.fix_sentence_endings = True tw.initial_indent = tw.subsequent_indent = " " * 4 # Names of the output directories output_directories = set() # Name of the project list markdown file pl = "project_list" project_list_markdown = "{}.md".format(pl) project_list_rst = "{}.rst".format(pl)
def PrintSize(size, stream, d): if d["-c"]: c.fg(GetColor(size)) print("%d" % size, file=stream, end="") if d["-c"]: c.normal()