install script, good progress with constraint listings and editing
This commit is contained in:
parent
f4478533d0
commit
f662ce3b52
|
@ -0,0 +1,589 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import sys, os, random, copy
|
||||||
|
|
||||||
|
from operator import attrgetter
|
||||||
|
|
||||||
|
import xml.etree.ElementTree as etree
|
||||||
|
|
||||||
|
import pylab
|
||||||
|
from PyQt4 import QtGui, QtCore
|
||||||
|
|
||||||
|
from numpy import arange, sin, pi, array, linspace, arange
|
||||||
|
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
|
||||||
|
from matplotlib.figure import Figure
|
||||||
|
from matplotlib.lines import Line2D
|
||||||
|
from matplotlib.path import Path
|
||||||
|
import matplotlib.patches as patches
|
||||||
|
#from mpltools import annotation
|
||||||
|
|
||||||
|
|
||||||
|
progname = os.path.basename(sys.argv[0])
|
||||||
|
progversion = "0.1"
|
||||||
|
|
||||||
|
PSTEP_COLORS = ("lightgreen", "yellow", "orange", "red")
|
||||||
|
|
||||||
|
|
||||||
|
class State(object):
|
||||||
|
def __init__(self, name, temp):
|
||||||
|
self.name = name
|
||||||
|
self.temp = temp
|
||||||
|
|
||||||
|
|
||||||
|
class Solder(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.psteps = []
|
||||||
|
self.durations = list()
|
||||||
|
self.rates = list()
|
||||||
|
self.name = None
|
||||||
|
|
||||||
|
#start = self.add_state("start", 25)
|
||||||
|
#ps = self.add_state("preheat start", 150)
|
||||||
|
#pe = self.add_state("preheat end", 185)
|
||||||
|
#tal = self.add_state("tal", 220)
|
||||||
|
#peak = self.add_state("peak", 250)
|
||||||
|
#end = self.add_state("end", 25)
|
||||||
|
|
||||||
|
#self.add_duration((ps, pe), 100)
|
||||||
|
#self.add_duration((tal, peak, tal), 100)
|
||||||
|
|
||||||
|
#self.add_rate((start, ps), 1)
|
||||||
|
#self.add_rate((ps, pe), 1)
|
||||||
|
#self.add_rate((pe, tal), 1)
|
||||||
|
#self.add_rate((tal, end), -2)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return unicode(self.name)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def color(self, index):
|
||||||
|
return PSTEP_COLORS[index]
|
||||||
|
|
||||||
|
def add_state(self, name, temp):
|
||||||
|
s = State(name, temp)
|
||||||
|
self.psteps.append(s)
|
||||||
|
return s
|
||||||
|
|
||||||
|
def add_rate(self, states, rate):
|
||||||
|
self.rates.append((states, rate))
|
||||||
|
|
||||||
|
def add_duration(self, states, duration):
|
||||||
|
self.durations.append((states, duration))
|
||||||
|
|
||||||
|
def get_state(self, name):
|
||||||
|
for i in self.psteps:
|
||||||
|
if i.name == name:
|
||||||
|
return i
|
||||||
|
return None
|
||||||
|
|
||||||
|
def calc_profile(self):
|
||||||
|
|
||||||
|
x = list()
|
||||||
|
y = list()
|
||||||
|
duration_points = dict()
|
||||||
|
rate_points = dict()
|
||||||
|
self.time = 0
|
||||||
|
used_steps = set()
|
||||||
|
for ix, pstep in enumerate(self.psteps):
|
||||||
|
#print "-- ", repr(pstep.name), pstep.temp, pstep.used, self.time, x, y
|
||||||
|
|
||||||
|
if pstep != self.psteps[0] and pstep not in used_steps:
|
||||||
|
ix = self.psteps.index(pstep)
|
||||||
|
raise Exception("step %r not connected to step %r or step %r" % (pstep.name, self.psteps[ix-1].name, self.psteps[ix+1].name))
|
||||||
|
|
||||||
|
psteps = None
|
||||||
|
duration = None
|
||||||
|
for sts, dur in self.durations:
|
||||||
|
if sts[0] == pstep:
|
||||||
|
duration = dur
|
||||||
|
psteps = sts
|
||||||
|
break
|
||||||
|
|
||||||
|
if pstep not in used_steps:
|
||||||
|
used_steps.add(pstep)
|
||||||
|
x.append(self.time)
|
||||||
|
y.append(pstep.temp)
|
||||||
|
|
||||||
|
if duration is not None:
|
||||||
|
if len(psteps) == 3:
|
||||||
|
used_steps.add(psteps[1])
|
||||||
|
used_steps.add(psteps[2])
|
||||||
|
|
||||||
|
self.time += duration / 2
|
||||||
|
x.append(self.time)
|
||||||
|
y.append(psteps[1].temp)
|
||||||
|
|
||||||
|
#print "3er duration", (self.time, psteps[1].temp)
|
||||||
|
|
||||||
|
self.time += duration / 2
|
||||||
|
x.append(self.time)
|
||||||
|
y.append(psteps[2].temp)
|
||||||
|
|
||||||
|
duration_points[ix] = (x[-3:], y[-3:])
|
||||||
|
|
||||||
|
#print "3er duration", (self.time, psteps[2].temp)
|
||||||
|
else:
|
||||||
|
y.append(psteps[1].temp)
|
||||||
|
used_steps.add(psteps[1])
|
||||||
|
self.time += duration
|
||||||
|
x.append(self.time)
|
||||||
|
duration_points[ix] = (x[-2:], y[-2:])
|
||||||
|
#print "2er duration", (self.time, psteps[1].temp)
|
||||||
|
else:
|
||||||
|
for ex, (sts, rate) in enumerate(self.rates):
|
||||||
|
if sts[0] == pstep:
|
||||||
|
used_steps.add(sts[1])
|
||||||
|
duration = (sts[1].temp - pstep.temp) / rate
|
||||||
|
self.time += duration
|
||||||
|
x.append(self.time)
|
||||||
|
y.append(sts[1].temp)
|
||||||
|
#print "rate", (self.time, sts[1].temp)
|
||||||
|
rate_points[ex] = (x[-2:], y[-2:])
|
||||||
|
|
||||||
|
|
||||||
|
return array(map(float, x)), array(map(float, y)), max(x), max(y), duration_points, rate_points
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def unpack(filename):
|
||||||
|
xmltree = etree.parse(filename)
|
||||||
|
root = xmltree.getroot()
|
||||||
|
s = Solder()
|
||||||
|
s.name = root[0].attrib["name"]
|
||||||
|
for state in root[0].findall("state"):
|
||||||
|
s.add_state(state.attrib["name"], int(state.attrib["temperature"]))
|
||||||
|
for duration in root[0].findall("duration"):
|
||||||
|
states = list()
|
||||||
|
for state in duration:
|
||||||
|
states.append(s.get_state(state.attrib["name"]))
|
||||||
|
s.add_duration(states, int(duration.attrib["value"]))
|
||||||
|
for rate in root[0].findall("rate"):
|
||||||
|
#print rate
|
||||||
|
states = list()
|
||||||
|
for state in rate:
|
||||||
|
states.append(s.get_state(state.attrib["name"]))
|
||||||
|
s.add_rate(states, int(rate.attrib["value"]))
|
||||||
|
|
||||||
|
return s
|
||||||
|
|
||||||
|
def serialize(self, pstep_list):
|
||||||
|
return ", ".join(map(attrgetter("name"), pstep_list))
|
||||||
|
|
||||||
|
|
||||||
|
class SolderListModel(QtCore.QAbstractListModel):
|
||||||
|
def __init__(self, parent=None, *args):
|
||||||
|
""" datain: a list where each item is a row
|
||||||
|
"""
|
||||||
|
super(SolderListModel, self).__init__(parent, *args)
|
||||||
|
|
||||||
|
dirname = os.path.join(os.path.dirname(__file__), "solder_types")
|
||||||
|
dirlisting = os.listdir(dirname)
|
||||||
|
self.listdata = []
|
||||||
|
for p in dirlisting:
|
||||||
|
#try:
|
||||||
|
self.listdata.append(Solder.unpack(os.path.join(dirname, p)))
|
||||||
|
#except Exception:
|
||||||
|
#pass
|
||||||
|
|
||||||
|
def rowCount(self, parent=QtCore.QModelIndex()):
|
||||||
|
return len(self.listdata)
|
||||||
|
|
||||||
|
|
||||||
|
def headerData(self, col, orientation, role):
|
||||||
|
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
|
||||||
|
return QtCore.QVariant("Solder Paste")
|
||||||
|
return QtCore.QVariant()
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if index.isValid() and role == QtCore.Qt.DisplayRole:
|
||||||
|
return QtCore.QVariant(self.listdata[index.row()].name)
|
||||||
|
else:
|
||||||
|
return QtCore.QVariant()
|
||||||
|
|
||||||
|
|
||||||
|
class PStepModel(QtCore.QAbstractTableModel):
|
||||||
|
def __init__(self, parent=None, *args):
|
||||||
|
super(PStepModel, self).__init__(parent, *args)
|
||||||
|
self.psteps = list()
|
||||||
|
self.headerdata = [u"Name", u"Temperature (°C)"]
|
||||||
|
|
||||||
|
def headerData(self, col, orientation, role):
|
||||||
|
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
|
||||||
|
return QtCore.QVariant(self.headerdata[col])
|
||||||
|
return QtCore.QVariant()
|
||||||
|
|
||||||
|
def rowCount(self, parent):
|
||||||
|
return len(self.psteps)
|
||||||
|
|
||||||
|
def columnCount(self, parent):
|
||||||
|
return 2
|
||||||
|
|
||||||
|
def data(self, index, role):
|
||||||
|
if not index.isValid():
|
||||||
|
return QtCore.QVariant()
|
||||||
|
|
||||||
|
if role == QtCore.Qt.DisplayRole:
|
||||||
|
col = index.column()
|
||||||
|
if col == 0:
|
||||||
|
return QtCore.QVariant(self.psteps[index.row()].name)
|
||||||
|
else:
|
||||||
|
return QtCore.QVariant(self.psteps[index.row()].temp)
|
||||||
|
|
||||||
|
if index.column() == 0 and role == QtCore.Qt.DecorationRole:
|
||||||
|
p = QtGui.QPixmap(10,10)
|
||||||
|
cr = row = index.row()
|
||||||
|
color = index.row() in (0, len(self.psteps)-1) and QtGui.QColor("black") or QtGui.QColor(PSTEP_COLORS[cr-1])
|
||||||
|
p.fill(color)
|
||||||
|
return p
|
||||||
|
|
||||||
|
return QtCore.QVariant()
|
||||||
|
|
||||||
|
def remove_pstep(self, index):
|
||||||
|
del self.psteps[index]
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
def add_pstep(self, index, pstep):
|
||||||
|
self.psteps.insert(index, pstep)
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
def setSteps(self, steps):
|
||||||
|
assert isinstance(steps, list)
|
||||||
|
self.psteps = steps
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class MyDynamicMplCanvas(FigureCanvas):
|
||||||
|
"""A canvas that updates itself every second with a new plot."""
|
||||||
|
def __init__(self, parent, myapp, width, height, dpi):
|
||||||
|
self.fig = Figure(figsize=(width, height), dpi=dpi)
|
||||||
|
super(MyDynamicMplCanvas, self).__init__(self.fig)
|
||||||
|
self.axes = self.fig.add_subplot(111)
|
||||||
|
|
||||||
|
## We want the axes cleared every time plot() is called
|
||||||
|
self.axes.set_axis_bgcolor('black')
|
||||||
|
self.axes.set_title(u'reflow profile', size=12)
|
||||||
|
self.axes.set_xlabel(u'time (seconds)', size=12)
|
||||||
|
self.axes.set_ylabel(u'temperature (°C)', size=12)
|
||||||
|
|
||||||
|
#pylab.setp(self.axes.get_xticklabels(), fontsize=8)
|
||||||
|
#pylab.setp(self.axes.get_yticklabels(), fontsize=8)
|
||||||
|
|
||||||
|
self.setParent(parent)
|
||||||
|
self.myapp = myapp
|
||||||
|
|
||||||
|
self.solder = None
|
||||||
|
|
||||||
|
self.plot_data, = self.axes.plot([], linewidth=1.0, color=(0,0,1), zorder=10)
|
||||||
|
self.selection_data, = self.axes.plot([], linewidth=1.0, color=(1,1,1), zorder=5)
|
||||||
|
|
||||||
|
FigureCanvas.setSizePolicy(self,
|
||||||
|
QtGui.QSizePolicy.Expanding,
|
||||||
|
QtGui.QSizePolicy.Expanding)
|
||||||
|
FigureCanvas.updateGeometry(self)
|
||||||
|
|
||||||
|
timer = QtCore.QTimer(self)
|
||||||
|
|
||||||
|
self.counter = list()
|
||||||
|
QtCore.QObject.connect(timer, QtCore.SIGNAL("timeout()"), self.update_figure)
|
||||||
|
timer.start(1000)
|
||||||
|
|
||||||
|
|
||||||
|
def update_figure(self):
|
||||||
|
#Build a list of 4 random integers between 0 and 10 (both inclusive)
|
||||||
|
x, y, xmax, ymax, duration_points, rate_points = self.solder.calc_profile()
|
||||||
|
|
||||||
|
lines = list()
|
||||||
|
legend = list()
|
||||||
|
|
||||||
|
#for states, value in self.durations.iteritems():
|
||||||
|
#annotation.slope_marker((states[0])
|
||||||
|
|
||||||
|
self.fig.lines = lines
|
||||||
|
|
||||||
|
self.axes.set_xbound(lower=0, upper=xmax + 20)
|
||||||
|
self.axes.set_ybound(lower=0, upper=ymax + 20)
|
||||||
|
self.axes.set_ymargin(0)
|
||||||
|
self.axes.set_xmargin(0)
|
||||||
|
|
||||||
|
self.axes.set_yticks([state.temp for state in self.solder.psteps])
|
||||||
|
self.axes.set_xticks(x)
|
||||||
|
|
||||||
|
self.plot_data.set_xdata(x)
|
||||||
|
self.plot_data.set_ydata(y)
|
||||||
|
self.plot_data.set_zorder(20)
|
||||||
|
|
||||||
|
duration_widget = self.myapp.duration_widget
|
||||||
|
|
||||||
|
#self.selection_data.set_xdata(array(da))
|
||||||
|
#self.selection_data.set_ydata(array(db))
|
||||||
|
|
||||||
|
for ix, i in enumerate(self.solder.psteps[1:-1]):
|
||||||
|
line = Line2D([0, xmax + 20], [i.temp, i.temp],
|
||||||
|
transform=self.axes.transData, figure=self.fig, color=self.solder.color(ix), label="name", zorder=1)
|
||||||
|
lines.append(line)
|
||||||
|
|
||||||
|
self.axes.legend(("Estimated profile",))
|
||||||
|
self.draw()
|
||||||
|
|
||||||
|
|
||||||
|
# contraint_list | label - checkboxes
|
||||||
|
# label - value
|
||||||
|
|
||||||
|
|
||||||
|
class ConstraintWidget(QtGui.QWidget):
|
||||||
|
def __init__(self, name):
|
||||||
|
super(ConstraintWidget, self).__init__()
|
||||||
|
self.name = name
|
||||||
|
self.solder = None
|
||||||
|
|
||||||
|
self.value = QtGui.QSpinBox(self)
|
||||||
|
self.value.setRange(-300, 400)
|
||||||
|
self.constraint_model = QtGui.QStringListModel(self) # constraint selection
|
||||||
|
self.all_psteps = PStepModel(self) # pstep selection pool
|
||||||
|
self.selected_psteps = PStepModel(self) # selected psteps
|
||||||
|
|
||||||
|
#self.all_psteps.setSteps(self.solder.psteps)
|
||||||
|
|
||||||
|
self.add_button = QtGui.QPushButton("Add", self)
|
||||||
|
self.remove_button = QtGui.QPushButton("Remove", self)
|
||||||
|
|
||||||
|
bg = QtGui.QWidget(self)
|
||||||
|
gbl = QtGui.QVBoxLayout(bg)
|
||||||
|
|
||||||
|
gbl.addWidget(self.add_button)
|
||||||
|
gbl.addWidget(self.remove_button)
|
||||||
|
gbl.addStretch(5)
|
||||||
|
gbl.addWidget(self.value)
|
||||||
|
|
||||||
|
|
||||||
|
self.constraint_list_view = QtGui.QListView(self)
|
||||||
|
self.constraint_list_view.setModel(self.constraint_model)
|
||||||
|
|
||||||
|
self.all_psteps_view = QtGui.QListView(self)
|
||||||
|
self.all_psteps_view.setModel(self.all_psteps)
|
||||||
|
|
||||||
|
self.selected_psteps_view = QtGui.QListView(self)
|
||||||
|
self.selected_psteps_view.setModel(self.selected_psteps)
|
||||||
|
|
||||||
|
#self.left = QtGui.QWidget(self)
|
||||||
|
#gl = QtGui.QGridLayout(self.left)
|
||||||
|
#gl.addWidget(QtGui.QLabel(u"Steps"), 0,0)
|
||||||
|
#gl.addWidget(QtGui.QLabel(name), 1,0)
|
||||||
|
#gl.addWidget(self.checkboxes_group, 0, 1)
|
||||||
|
#gl.addWidget(self.value, 1, 1)
|
||||||
|
#self.gl = gl
|
||||||
|
|
||||||
|
|
||||||
|
h = QtGui.QHBoxLayout()
|
||||||
|
h.addWidget(self.constraint_list_view)
|
||||||
|
h.addWidget(self.all_psteps_view)
|
||||||
|
h.addWidget(bg)
|
||||||
|
h.addWidget(self.selected_psteps_view)
|
||||||
|
self.setLayout(h)
|
||||||
|
|
||||||
|
self.connect(
|
||||||
|
self.constraint_list_view,
|
||||||
|
QtCore.SIGNAL("clicked(QModelIndex)"),
|
||||||
|
self.constraint_clicked)
|
||||||
|
|
||||||
|
self.connect(self.add_button, QtCore.SIGNAL("clicked()"), self.add_constraint)
|
||||||
|
self.connect(self.remove_button, QtCore.SIGNAL("clicked()"), self.remove_constraint)
|
||||||
|
|
||||||
|
def add_constraint(self):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def remove_constraint(self):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def setData(self, solder):
|
||||||
|
self.solder = solder
|
||||||
|
#for k,v in self.checkboxes.iteritems():
|
||||||
|
#self.cl.removeWidget(v)
|
||||||
|
#self.checkboxes = dict()
|
||||||
|
self.all_psteps.setSteps(self.solder.psteps)
|
||||||
|
|
||||||
|
#for i in solder.psteps:
|
||||||
|
#cb = QtGui.QCheckBox(self, checked=False)
|
||||||
|
#label = QtGui.QLabel(i.name, self)
|
||||||
|
#label.setBuddy(cb)
|
||||||
|
#self.checkboxes[i] = cb
|
||||||
|
##self.cl.addWidget(label)
|
||||||
|
##self.cl.addWidget(cb)
|
||||||
|
|
||||||
|
self.getConstraints()
|
||||||
|
|
||||||
|
|
||||||
|
def getConstraints(self):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def constraint_clicked(self, index):
|
||||||
|
#for cb in self.checkboxes.itervalues():
|
||||||
|
#cb.setChecked(False)
|
||||||
|
|
||||||
|
self.handle_clicked(index)
|
||||||
|
|
||||||
|
def handle_clicked(self, index):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
class DurationConstraintWidget(ConstraintWidget):
|
||||||
|
|
||||||
|
def getConstraints(self):
|
||||||
|
tmp = QtCore.QStringList()
|
||||||
|
for ix in xrange(len(self.solder.durations)):
|
||||||
|
tmp << unicode(ix + 1)
|
||||||
|
|
||||||
|
self.constraint_model.setStringList(tmp)
|
||||||
|
k, t = self.solder.durations[0]
|
||||||
|
|
||||||
|
self.value.setValue(t)
|
||||||
|
self.constraint_list_view.setCurrentIndex(self.constraint_model.index(0, 0))
|
||||||
|
|
||||||
|
def add_constraint(self):
|
||||||
|
self.selected_psteps.psteps.append(self.all_psteps.psteps[self.all_psteps_view.currentIndex().row()])
|
||||||
|
self.selected_psteps.reset()
|
||||||
|
#self.selected_psteps_view.setCurrentIndex(QtCore.QModelIndex())
|
||||||
|
self.selected_psteps_view.clearSelection()
|
||||||
|
|
||||||
|
def remove_constraint(self):
|
||||||
|
del self.selected_psteps.psteps[self.selected_psteps_view.currentIndex().row()]
|
||||||
|
self.selected_psteps.reset()
|
||||||
|
#self.selected_psteps_view.setCurrentIndex(QtCore.QModelIndex())
|
||||||
|
self.selected_psteps_view.clearSelection()
|
||||||
|
|
||||||
|
def handle_clicked(self, index):
|
||||||
|
psteps, value = self.solder.durations[index.row()]
|
||||||
|
self.selected_psteps.setSteps(psteps)
|
||||||
|
self.value.setValue(value)
|
||||||
|
|
||||||
|
|
||||||
|
class RateConstraintWidget(ConstraintWidget):
|
||||||
|
|
||||||
|
def getConstraints(self):
|
||||||
|
tmp = QtCore.QStringList()
|
||||||
|
for ix in xrange(len(self.solder.durations)):
|
||||||
|
tmp << unicode(ix + 1)
|
||||||
|
|
||||||
|
self.constraint_model.setStringList(tmp)
|
||||||
|
k, t = self.solder.rates[0]
|
||||||
|
|
||||||
|
self.value.setValue(t)
|
||||||
|
self.constraint_list_view.setCurrentIndex(self.constraint_model.index(0, 0))
|
||||||
|
|
||||||
|
def handle_clicked(self, index):
|
||||||
|
psteps, value = self.solder.durations[index.row()]
|
||||||
|
self.selected_psteps.setSteps(psteps)
|
||||||
|
self.value.setValue(value)
|
||||||
|
|
||||||
|
class ApplicationWindow(QtGui.QMainWindow):
|
||||||
|
def __init__(self):
|
||||||
|
QtGui.QMainWindow.__init__(self)
|
||||||
|
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
||||||
|
self.setWindowTitle("application main window")
|
||||||
|
|
||||||
|
self.file_menu = QtGui.QMenu('&File', self)
|
||||||
|
self.file_menu.addAction('&Quit', self.fileQuit,
|
||||||
|
QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
|
||||||
|
self.file_menu.addAction('&Save plot', self.save_plot,
|
||||||
|
QtCore.Qt.CTRL + QtCore.Qt.Key_S)
|
||||||
|
self.menuBar().addMenu(self.file_menu)
|
||||||
|
|
||||||
|
self.help_menu = QtGui.QMenu('&Help', self)
|
||||||
|
self.menuBar().addSeparator()
|
||||||
|
self.menuBar().addMenu(self.help_menu)
|
||||||
|
|
||||||
|
self.help_menu.addAction('&About', self.about)
|
||||||
|
|
||||||
|
self.main_widget = QtGui.QWidget(self)
|
||||||
|
self.profile_widget = QtGui.QWidget(self)
|
||||||
|
self.steps_box = QtGui.QGroupBox(self)
|
||||||
|
|
||||||
|
self.tab_widget = QtGui.QTabWidget(self)
|
||||||
|
self.duration_widget = DurationConstraintWidget(u"Duration (s)")
|
||||||
|
self.rate_widget = RateConstraintWidget(u"Rate (°C/s)")
|
||||||
|
self.tab_widget.addTab(self.duration_widget, u"Duration (s)")
|
||||||
|
self.tab_widget.addTab(self.rate_widget, u"Rate (°C/s)")
|
||||||
|
|
||||||
|
self.dpi = 100
|
||||||
|
|
||||||
|
pl = QtGui.QHBoxLayout(self.profile_widget)
|
||||||
|
sl = QtGui.QVBoxLayout(self.steps_box)
|
||||||
|
|
||||||
|
self.solder_model = SolderListModel(self)
|
||||||
|
self.pstep_model = PStepModel(self)
|
||||||
|
|
||||||
|
self.pstep_view = QtGui.QTableView()
|
||||||
|
self.pstep_view.setModel(self.pstep_model)
|
||||||
|
self.pstep_view.verticalHeader().setVisible(False)
|
||||||
|
self.pstep_view.resizeColumnsToContents()
|
||||||
|
|
||||||
|
self.solder_view = QtGui.QListView()
|
||||||
|
self.solder_view.setModel(self.solder_model)
|
||||||
|
self.connect(
|
||||||
|
self.solder_view,
|
||||||
|
QtCore.SIGNAL("clicked(QModelIndex)"),
|
||||||
|
self.solder_selected)
|
||||||
|
|
||||||
|
pl.addWidget(self.solder_view, 1)
|
||||||
|
pl.addWidget(self.pstep_view, 2)
|
||||||
|
pl.addWidget(self.tab_widget, 7)
|
||||||
|
#pl.addWidget(self.duration_widget)
|
||||||
|
#pl.addWidget(self.rate_widget)
|
||||||
|
|
||||||
|
l = QtGui.QVBoxLayout(self.main_widget)
|
||||||
|
self.dc = MyDynamicMplCanvas(self, self, width=5, height=4, dpi=self.dpi)
|
||||||
|
|
||||||
|
self.solder_view.setCurrentIndex(self.solder_model.index(0,0))
|
||||||
|
self.solder_selected(self.solder_model.index(0,0))
|
||||||
|
|
||||||
|
l.addWidget(self.profile_widget, 2)
|
||||||
|
l.addWidget(self.dc, 8)
|
||||||
|
|
||||||
|
self.main_widget.setFocus()
|
||||||
|
self.setCentralWidget(self.main_widget)
|
||||||
|
|
||||||
|
self.statusBar().showMessage("I'm in reflow heaven", 2000)
|
||||||
|
|
||||||
|
def solder_selected(self, index):
|
||||||
|
if index.isValid():
|
||||||
|
self.dc.solder = self.solder_model.listdata[index.row()]
|
||||||
|
self.pstep_model.setSteps(self.dc.solder.psteps)
|
||||||
|
self.pstep_view.resizeColumnsToContents()
|
||||||
|
self.duration_widget.setData(self.dc.solder)
|
||||||
|
self.rate_widget.setData(self.dc.solder)
|
||||||
|
|
||||||
|
def save_plot(self):
|
||||||
|
file_choices = "PNG (*.png)|*.png"
|
||||||
|
|
||||||
|
filename = QtGui.QFileDialog.getSaveFileName(self, 'Save File', 'qtplot.png')
|
||||||
|
print type(filename), dir(filename)
|
||||||
|
self.dc.print_figure(str(filename), dpi=self.dpi)
|
||||||
|
|
||||||
|
def fileQuit(self):
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def closeEvent(self, ce):
|
||||||
|
self.fileQuit()
|
||||||
|
|
||||||
|
def about(self):
|
||||||
|
QtGui.QMessageBox.about(self, "About %s" % progname,
|
||||||
|
u"%(prog)s version %(version)s\n" \
|
||||||
|
u"Copyright \N{COPYRIGHT SIGN} 2012 Stefan Kögl\n\n" \
|
||||||
|
u"reflowctl frontend" % {"prog": progname, "version": progversion})
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
qApp = QtGui.QApplication(sys.argv)
|
||||||
|
|
||||||
|
aw = ApplicationWindow()
|
||||||
|
aw.setWindowTitle("%s" % progname)
|
||||||
|
aw.show()
|
||||||
|
sys.exit(qApp.exec_())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
413
reflowctl_gui.py
413
reflowctl_gui.py
|
@ -1,413 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
import sys, os, random
|
|
||||||
|
|
||||||
import xml.etree.ElementTree as etree
|
|
||||||
|
|
||||||
import pylab
|
|
||||||
from PyQt4 import QtGui, QtCore
|
|
||||||
|
|
||||||
from numpy import arange, sin, pi, array, linspace, arange
|
|
||||||
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
|
|
||||||
from matplotlib.figure import Figure
|
|
||||||
from matplotlib.lines import Line2D
|
|
||||||
from matplotlib.path import Path
|
|
||||||
import matplotlib.patches as patches
|
|
||||||
|
|
||||||
from scipy.interpolate import *
|
|
||||||
|
|
||||||
progname = os.path.basename(sys.argv[0])
|
|
||||||
progversion = "0.1"
|
|
||||||
|
|
||||||
|
|
||||||
class State(object):
|
|
||||||
def __init__(self, name, temp):
|
|
||||||
self.name = name
|
|
||||||
self.temp = temp
|
|
||||||
|
|
||||||
|
|
||||||
class Solder(object):
|
|
||||||
def __init__(self):
|
|
||||||
self.psteps = []
|
|
||||||
self.durations = dict()
|
|
||||||
self.rates = dict()
|
|
||||||
self.name = None
|
|
||||||
|
|
||||||
#start = self.add_state("start", 25)
|
|
||||||
#ps = self.add_state("preheat start", 150)
|
|
||||||
#pe = self.add_state("preheat end", 185)
|
|
||||||
#tal = self.add_state("tal", 220)
|
|
||||||
#peak = self.add_state("peak", 250)
|
|
||||||
#end = self.add_state("end", 25)
|
|
||||||
|
|
||||||
#self.add_duration((ps, pe), 100)
|
|
||||||
#self.add_duration((tal, peak, tal), 100)
|
|
||||||
|
|
||||||
#self.add_rate((start, ps), 1)
|
|
||||||
#self.add_rate((ps, pe), 1)
|
|
||||||
#self.add_rate((pe, tal), 1)
|
|
||||||
#self.add_rate((tal, end), -2)
|
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
return unicode(self.name)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
|
|
||||||
def add_state(self, name, temp):
|
|
||||||
s = State(name, temp)
|
|
||||||
self.psteps.append(s)
|
|
||||||
return s
|
|
||||||
|
|
||||||
def add_rate(self, states, rate):
|
|
||||||
self.rates[states] = rate
|
|
||||||
|
|
||||||
def add_duration(self, states, duration):
|
|
||||||
self.durations[states] = duration
|
|
||||||
|
|
||||||
def get_state(self, name):
|
|
||||||
for i in self.psteps:
|
|
||||||
if i.name == name:
|
|
||||||
return i
|
|
||||||
return None
|
|
||||||
|
|
||||||
def calc_profile(self):
|
|
||||||
|
|
||||||
x = list()
|
|
||||||
y = list()
|
|
||||||
self.time = 0
|
|
||||||
used_steps = set()
|
|
||||||
for pstep in self.psteps:
|
|
||||||
#print "-- ", repr(pstep.name), pstep.temp, pstep.used, self.time, x, y
|
|
||||||
|
|
||||||
if pstep != self.psteps[0] and pstep not in used_steps:
|
|
||||||
ix = self.psteps.index(pstep)
|
|
||||||
raise Exception("step %r not connected to step %r or step %r" % (pstep.name, self.psteps[ix-1].name, self.psteps[ix+1].name))
|
|
||||||
|
|
||||||
psteps = None
|
|
||||||
duration = None
|
|
||||||
for sts, dur in self.durations.iteritems():
|
|
||||||
if sts[0] == pstep:
|
|
||||||
duration = dur
|
|
||||||
psteps = sts
|
|
||||||
break
|
|
||||||
|
|
||||||
if pstep not in used_steps:
|
|
||||||
used_steps.add(pstep)
|
|
||||||
x.append(self.time)
|
|
||||||
y.append(pstep.temp)
|
|
||||||
|
|
||||||
if duration is not None:
|
|
||||||
if len(psteps) == 3:
|
|
||||||
used_steps.add(psteps[1])
|
|
||||||
used_steps.add(psteps[2])
|
|
||||||
|
|
||||||
self.time += duration / 2
|
|
||||||
x.append(self.time)
|
|
||||||
y.append(psteps[1].temp)
|
|
||||||
#print "3er duration", (self.time, psteps[1].temp)
|
|
||||||
|
|
||||||
self.time += duration / 2
|
|
||||||
x.append(self.time)
|
|
||||||
y.append(psteps[2].temp)
|
|
||||||
|
|
||||||
#print "3er duration", (self.time, psteps[2].temp)
|
|
||||||
else:
|
|
||||||
y.append(psteps[1].temp)
|
|
||||||
used_steps.add(psteps[1])
|
|
||||||
self.time += duration
|
|
||||||
x.append(self.time)
|
|
||||||
#print "2er duration", (self.time, psteps[1].temp)
|
|
||||||
else:
|
|
||||||
for sts, rate in self.rates.iteritems():
|
|
||||||
if sts[0] == pstep:
|
|
||||||
used_steps.add(sts[1])
|
|
||||||
duration = (sts[1].temp - pstep.temp) / rate
|
|
||||||
self.time += duration
|
|
||||||
x.append(self.time)
|
|
||||||
y.append(sts[1].temp)
|
|
||||||
#print "rate", (self.time, sts[1].temp)
|
|
||||||
|
|
||||||
|
|
||||||
return array(map(float, x)), array(map(float, y)), max(x), max(y)
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def unpack(filename):
|
|
||||||
xmltree = etree.parse(filename)
|
|
||||||
root = xmltree.getroot()
|
|
||||||
s = Solder()
|
|
||||||
s.name = root[0].attrib["name"]
|
|
||||||
for state in root[0].findall("state"):
|
|
||||||
s.add_state(state.attrib["name"], int(state.attrib["temperature"]))
|
|
||||||
for duration in root[0].findall("duration"):
|
|
||||||
states = list()
|
|
||||||
for state in duration:
|
|
||||||
states.append(s.get_state(state.attrib["name"]))
|
|
||||||
s.add_duration(tuple(states), int(duration.attrib["value"]))
|
|
||||||
for rate in root[0].findall("rate"):
|
|
||||||
#print rate
|
|
||||||
states = list()
|
|
||||||
for state in rate:
|
|
||||||
states.append(s.get_state(state.attrib["name"]))
|
|
||||||
s.add_rate(tuple(states), int(rate.attrib["value"]))
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
class SolderListModel(QtCore.QAbstractListModel):
|
|
||||||
def __init__(self, parent=None, *args):
|
|
||||||
""" datain: a list where each item is a row
|
|
||||||
"""
|
|
||||||
super(SolderListModel, self).__init__(parent, *args)
|
|
||||||
self.listdata = [Solder.unpack(os.path.join("solder_types", p)) for p in os.listdir("solder_types")]
|
|
||||||
|
|
||||||
def rowCount(self, parent=QtCore.QModelIndex()):
|
|
||||||
return len(self.listdata)
|
|
||||||
|
|
||||||
def data(self, index, role):
|
|
||||||
if index.isValid() and role == QtCore.Qt.DisplayRole:
|
|
||||||
return QtCore.QVariant(self.listdata[index.row()].name)
|
|
||||||
else:
|
|
||||||
return QtCore.QVariant()
|
|
||||||
|
|
||||||
|
|
||||||
class PStepModel(QtCore.QAbstractTableModel):
|
|
||||||
def __init__(self, parent=None, *args):
|
|
||||||
super(PStepModel, self).__init__(parent, *args)
|
|
||||||
self.psteps = list()
|
|
||||||
|
|
||||||
def rowCount(self, parent):
|
|
||||||
return len(self.psteps)
|
|
||||||
|
|
||||||
def columnCount(self, parent):
|
|
||||||
return 2
|
|
||||||
|
|
||||||
def data(self, index, role):
|
|
||||||
if not index.isValid():
|
|
||||||
return QtCore.QVariant()
|
|
||||||
elif role != QtCore.Qt.DisplayRole:
|
|
||||||
return QtCore.QVariant()
|
|
||||||
|
|
||||||
col = index.column()
|
|
||||||
if col == 0:
|
|
||||||
return QtCore.QVariant(self.psteps[index.row()].name)
|
|
||||||
else:
|
|
||||||
return QtCore.QVariant(self.psteps[index.row()].temperature)
|
|
||||||
|
|
||||||
def removeRows(self, start, _count, _parent):
|
|
||||||
print type(start), type(_count)
|
|
||||||
self.beginRemoveRows(_parent, start, start + _count)
|
|
||||||
self.psteps[:start].extend(self.psteps[start + _count:])
|
|
||||||
self.endRemoveRows()
|
|
||||||
|
|
||||||
|
|
||||||
class MyDynamicMplCanvas(FigureCanvas):
|
|
||||||
"""A canvas that updates itself every second with a new plot."""
|
|
||||||
def __init__(self, parent=None, width=5, height=4, dpi=100):
|
|
||||||
self.fig = Figure(figsize=(width, height), dpi=dpi)
|
|
||||||
self.axes = self.fig.add_subplot(111)
|
|
||||||
# We want the axes cleared every time plot() is called
|
|
||||||
self.axes.set_axis_bgcolor('black')
|
|
||||||
self.axes.set_title(u'reflow profile', size=12)
|
|
||||||
self.axes.set_xlabel(u'time (seconds)', size=12)
|
|
||||||
self.axes.set_ylabel(u'temperature (°C)', size=12)
|
|
||||||
|
|
||||||
pylab.setp(self.axes.get_xticklabels(), fontsize=8)
|
|
||||||
pylab.setp(self.axes.get_yticklabels(), fontsize=8)
|
|
||||||
|
|
||||||
super(MyDynamicMplCanvas, self).__init__(self.fig)
|
|
||||||
self.setParent(parent)
|
|
||||||
|
|
||||||
self.solder = None
|
|
||||||
|
|
||||||
self.compute_initial_figure()
|
|
||||||
FigureCanvas.setSizePolicy(self,
|
|
||||||
QtGui.QSizePolicy.Expanding,
|
|
||||||
QtGui.QSizePolicy.Expanding)
|
|
||||||
FigureCanvas.updateGeometry(self)
|
|
||||||
|
|
||||||
timer = QtCore.QTimer(self)
|
|
||||||
|
|
||||||
self.counter = list()
|
|
||||||
QtCore.QObject.connect(timer, QtCore.SIGNAL("timeout()"), self.update_figure)
|
|
||||||
timer.start(1000)
|
|
||||||
|
|
||||||
|
|
||||||
def compute_initial_figure(self):
|
|
||||||
|
|
||||||
"""test foo bar"""
|
|
||||||
|
|
||||||
#start_rate = 1
|
|
||||||
#start_temp = 25
|
|
||||||
#start_period = None
|
|
||||||
|
|
||||||
## warmup
|
|
||||||
#warmup_rate = 1
|
|
||||||
#warmup_temp = 155
|
|
||||||
#preheat_period = None
|
|
||||||
|
|
||||||
## preheat start
|
|
||||||
#preheat_start_rate = 1
|
|
||||||
#preheat_start_temp = 155
|
|
||||||
#preheat_start_period = 100
|
|
||||||
|
|
||||||
## preheat end
|
|
||||||
#preheat_end_rate = 1
|
|
||||||
#preheat_end_temp = 185
|
|
||||||
#preheat_end_period = None
|
|
||||||
|
|
||||||
#tal_rate = 1
|
|
||||||
#tal_temp = 220
|
|
||||||
#tal_duration = 60
|
|
||||||
|
|
||||||
#peak_temp = 250
|
|
||||||
#peak_rate = 1
|
|
||||||
|
|
||||||
#x, y = self.solder.calc_profile()
|
|
||||||
|
|
||||||
#print "x", repr(x)
|
|
||||||
#print "y", repr(y)
|
|
||||||
|
|
||||||
#dtp_min = 99999.
|
|
||||||
#dtp_max = 0.
|
|
||||||
#dtpi = -1
|
|
||||||
|
|
||||||
#dtn_min = -99999.
|
|
||||||
#dtn_max = 0.
|
|
||||||
#dtni = -1
|
|
||||||
#for i in xrange(1, len(y)):
|
|
||||||
#tmp = (y[i] - y[i-1]) / (x[i] - x[i-1])
|
|
||||||
#if tmp > 0:
|
|
||||||
#if tmp < dtp_min:
|
|
||||||
#dtp_min = tmp
|
|
||||||
#dtpi = i
|
|
||||||
#elif tmp > dtp_max:
|
|
||||||
#dtp_max = tmp
|
|
||||||
#dtpi = i
|
|
||||||
#elif tmp < 0:
|
|
||||||
#if tmp > dtn_min:
|
|
||||||
#dtn_min = tmp
|
|
||||||
#dtni = i
|
|
||||||
#elif tmp < dtn_max:
|
|
||||||
#dtn_max = tmp
|
|
||||||
#dtni = i
|
|
||||||
#print "max negative", dtn_min, dtn_max, dtni
|
|
||||||
#print "max positive", dtp_min, dtp_max, dtpi
|
|
||||||
|
|
||||||
self.plot_data, = self.axes.plot([], linewidth=1.0, color=(0,0,1))
|
|
||||||
#self.axes.plot(p1x, p1y, 'r-o')
|
|
||||||
|
|
||||||
def update_figure(self):
|
|
||||||
# Build a list of 4 random integers between 0 and 10 (both inclusive)
|
|
||||||
x, y, xmax, ymax = self.solder.calc_profile()
|
|
||||||
|
|
||||||
lines = list()
|
|
||||||
legend = list()
|
|
||||||
|
|
||||||
cols = ("lightgreen", "yellow", "orange", "red")
|
|
||||||
for ix, i in enumerate(self.solder.psteps[1:-1]):
|
|
||||||
line = Line2D([0, xmax + 20], [i.temp, i.temp],
|
|
||||||
transform=self.axes.transData, figure=self.fig, color=cols[ix], label="name")
|
|
||||||
lines.append(line)
|
|
||||||
|
|
||||||
self.fig.lines = lines
|
|
||||||
|
|
||||||
self.axes.set_xbound(lower=0, upper=xmax + 20)
|
|
||||||
self.axes.set_ybound(lower=0, upper=ymax + 20)
|
|
||||||
|
|
||||||
#self.axes.grid(True, color='gray')
|
|
||||||
|
|
||||||
pylab.setp(self.axes.get_xticklabels(), visible=True)
|
|
||||||
|
|
||||||
self.plot_data.set_xdata(x)
|
|
||||||
self.plot_data.set_ydata(y)
|
|
||||||
self.axes.legend(("Estimated profile",))
|
|
||||||
self.draw()
|
|
||||||
|
|
||||||
|
|
||||||
class ApplicationWindow(QtGui.QMainWindow):
|
|
||||||
def __init__(self):
|
|
||||||
QtGui.QMainWindow.__init__(self)
|
|
||||||
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
|
||||||
self.setWindowTitle("application main window")
|
|
||||||
|
|
||||||
self.file_menu = QtGui.QMenu('&File', self)
|
|
||||||
self.file_menu.addAction('&Quit', self.fileQuit,
|
|
||||||
QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
|
|
||||||
self.file_menu.addAction('&Save plot', self.save_plot,
|
|
||||||
QtCore.Qt.CTRL + QtCore.Qt.Key_S)
|
|
||||||
self.menuBar().addMenu(self.file_menu)
|
|
||||||
|
|
||||||
self.help_menu = QtGui.QMenu('&Help', self)
|
|
||||||
self.menuBar().addSeparator()
|
|
||||||
self.menuBar().addMenu(self.help_menu)
|
|
||||||
|
|
||||||
self.help_menu.addAction('&About', self.about)
|
|
||||||
|
|
||||||
self.main_widget = QtGui.QWidget(self)
|
|
||||||
self.profile_widget = QtGui.QWidget(self)
|
|
||||||
self.steps_box = QtGui.QGroupBox(self)
|
|
||||||
|
|
||||||
self.dpi = 100
|
|
||||||
|
|
||||||
pl = QtGui.QHBoxLayout(self.profile_widget)
|
|
||||||
sl = QtGui.QVBoxLayout(self.steps_box)
|
|
||||||
|
|
||||||
self.solder_model = SolderListModel(self)
|
|
||||||
self.pstep_model = PStepModel(self)
|
|
||||||
self.solder_view = QtGui.QListView()
|
|
||||||
self.pstep_view = QtGui.QTableView()
|
|
||||||
self.solder_view.setModel(self.solder_model)
|
|
||||||
self.pstep_view.setModel(self.pstep_model)
|
|
||||||
|
|
||||||
self.connect(self.solder_view, QtCore.SIGNAL("clicked(QModelIndex)"), self.solder_selected)
|
|
||||||
pl.addWidget(self.solder_view)
|
|
||||||
pl.addWidget(self.pstep_view)
|
|
||||||
|
|
||||||
l = QtGui.QVBoxLayout(self.main_widget)
|
|
||||||
self.dc = MyDynamicMplCanvas(self.main_widget, width=5, height=4, dpi=self.dpi)
|
|
||||||
self.dc.solder = self.solder_model.listdata[0]
|
|
||||||
l.addWidget(self.profile_widget, 1)
|
|
||||||
l.addWidget(self.dc, 10)
|
|
||||||
|
|
||||||
self.main_widget.setFocus()
|
|
||||||
self.setCentralWidget(self.main_widget)
|
|
||||||
|
|
||||||
self.statusBar().showMessage("I'm in reflow heaven", 2000)
|
|
||||||
|
|
||||||
def solder_selected(self, index):
|
|
||||||
if index.isValid():
|
|
||||||
self.dc.solder = self.solder_model.listdata[index.row()]
|
|
||||||
self.pstep_model.removeRows(0, self.pstep_model.rowCount(QtCore.QModelIndex()))
|
|
||||||
self.pstep_model.insertRows()
|
|
||||||
|
|
||||||
def save_plot(self):
|
|
||||||
file_choices = "PNG (*.png)|*.png"
|
|
||||||
|
|
||||||
filename = QtGui.QFileDialog.getSaveFileName(self, 'Save File', 'qtplot.png')
|
|
||||||
print type(filename), dir(filename)
|
|
||||||
self.dc.print_figure(str(filename), dpi=self.dpi)
|
|
||||||
|
|
||||||
def fileQuit(self):
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def closeEvent(self, ce):
|
|
||||||
self.fileQuit()
|
|
||||||
|
|
||||||
def about(self):
|
|
||||||
QtGui.QMessageBox.about(self, "About %s" % progname,
|
|
||||||
u"""%(prog)s version %(version)s
|
|
||||||
Copyright \N{COPYRIGHT SIGN} 2012 Stefan Kögl
|
|
||||||
|
|
||||||
reflowctl frontend"""
|
|
||||||
% {"prog": progname, "version": progversion})
|
|
||||||
|
|
||||||
|
|
||||||
qApp = QtGui.QApplication(sys.argv)
|
|
||||||
|
|
||||||
aw = ApplicationWindow()
|
|
||||||
aw.setWindowTitle("%s" % progname)
|
|
||||||
aw.show()
|
|
||||||
sys.exit(qApp.exec_())
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from distribute_setup import use_setuptools
|
||||||
|
use_setuptools()
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
|
if sys.version_info >= (3,):
|
||||||
|
extras['use_2to3'] = True
|
||||||
|
extras['convert_2to3_doctests'] = ['src/your/module/README.txt']
|
||||||
|
#extra['use_2to3_fixers'] = ['your.fixers']
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='reflowctl_gui',
|
||||||
|
version='0.1',
|
||||||
|
packages=find_packages(),
|
||||||
|
|
||||||
|
include_package_data = True,
|
||||||
|
|
||||||
|
install_requires=["numpy", "matplotlib"],
|
||||||
|
|
||||||
|
# installing unzipped
|
||||||
|
zip_safe = False,
|
||||||
|
|
||||||
|
# predefined extension points, e.g. for plugins
|
||||||
|
entry_points = """
|
||||||
|
[console_scripts]
|
||||||
|
reflowctl_gui = reflowctl.reflowctl_gui:main
|
||||||
|
""",
|
||||||
|
# pypi metadata
|
||||||
|
author = "Stefan Kögl",
|
||||||
|
|
||||||
|
# FIXME: add author email
|
||||||
|
author_email = "",
|
||||||
|
description = "paludis useflag management",
|
||||||
|
|
||||||
|
# FIXME: add long_description
|
||||||
|
long_description = """
|
||||||
|
""",
|
||||||
|
|
||||||
|
# FIXME: add license
|
||||||
|
license = "GPL",
|
||||||
|
|
||||||
|
# FIXME: add keywords
|
||||||
|
keywords = "",
|
||||||
|
|
||||||
|
# FIXME: add download url
|
||||||
|
url = "",
|
||||||
|
)
|
Loading…
Reference in New Issue