pax_global_header 0000666 0000000 0000000 00000000064 13625463046 0014523 g ustar 00root root 0000000 0000000 52 comment=8fa1dd2c38bd00c00acc9463744942e84a2c52f2
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/ 0000775 0000000 0000000 00000000000 13625463046 0021467 5 ustar 00root root 0000000 0000000 product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/.gitignore 0000664 0000000 0000000 00000000142 13625463046 0023454 0 ustar 00root root 0000000 0000000 **/__pycache__/**
test-gb2312-*
test-utf8-*
test/
input..csv
output/
missing-parts.csv
config.py
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/.vscode/ 0000775 0000000 0000000 00000000000 13625463046 0023030 5 ustar 00root root 0000000 0000000 product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/.vscode/settings.json 0000664 0000000 0000000 00000000124 13625463046 0025560 0 ustar 00root root 0000000 0000000 {
"python.pythonPath": "/usr/bin/python3",
"python.linting.enabled": false
} product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/LICENSE 0000664 0000000 0000000 00000000124 13625463046 0022471 0 ustar 00root root 0000000 0000000 The AUTHOR give up ALL rights about this project. This project is in PUBLIC DOMAIN.
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/README.md 0000664 0000000 0000000 00000000660 13625463046 0022750 0 ustar 00root root 0000000 0000000 # magic program
> I don't know what's this shitty program doing. I was forced to write it.
`./main.py` is named as PROGRAM ALPHA, and `summerize-part-list/main.py` is named as PROGRAM BETA. (Because the program sucks, and too difficult to name them)
Firstly, run PROGRAM BETA to generate one dir (with some pdf-s), one sheet (as the input of ALPHA), and another csv (containing errors).
Then run ALPHA to get the final result.
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/__init__.py 0000664 0000000 0000000 00000000000 13625463046 0023566 0 ustar 00root root 0000000 0000000 product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/csv_preprocess.py 0000664 0000000 0000000 00000004131 13625463046 0025100 0 ustar 00root root 0000000 0000000 import csv
import numpy as np
import functools, utils, re
def _rstrip_csv(csvText):
return '\n'.join([line.rstrip(',') for line in csvText.split('\n')])
def clean_csv(csvText, begin_keyword='__uniqer_begin__', end_keyword='__uniqer_end__'):
# Use begin_keyword to indicate a begin, end_keyword to indicate an end.
csvText = _rstrip_csv(csvText)
foundUniqerBegin = False
result = ''
for line in csvText.split('\n'):
if begin_keyword in line:
foundUniqerBegin = True
continue
if not foundUniqerBegin:
continue
if end_keyword in line:
result = result[:-1] if len(result) != 0 else result
return result
result += line + '\n'
print('Warning: clean_csv returns abnormally because of reaching EOF.')
return result
def clean_csv_2(csvText):
# Append ',' to end of line, to make len(everyLine.split(',')) == max(anyLine.split(',')).
def csv_bettercount_delim(line):
return re.sub(r'"[^"]*"', '', line).count(',')
max_count = functools.reduce(lambda a, b: max(a, b), [csv_bettercount_delim(line) for line in csvText.split('\n')])
return '\n'.join([line+utils.str_repeat(',', max_count-csv_bettercount_delim(line)) for line in csvText.split('\n')])
def np_loadcsv_pycsv(reader_handle):
return np.genfromtxt(("\t".join(i) for i in csv.reader(reader_handle)), delimiter="\t", dtype=str)
def trim_npArr(np_bi_arr):
def _trim_str(s):
goodstr = s.strip()
if s != goodstr:
print('Warning: trimming "{}", which is usually not expected.'.format(s))
return goodstr
assert(type(np_bi_arr) == np.ndarray)
res = []
for line in np_bi_arr:
if type(line) == str or type(line) == np.str_:
res.append(_trim_str(line))
else:
res.append([_trim_str(item) for item in line])
if len(res) == 0 or type(res[0]) != list:
return np.array([res])
else:
return np.array(res)
import pandas
def npmat2csv(npmat, outputFd):
pandas.DataFrame(npmat).to_csv(outputFd, header=False, index=False)
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/dir-file-compare/ 0000775 0000000 0000000 00000000000 13625463046 0024606 5 ustar 00root root 0000000 0000000 product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/dir-file-compare/config.py 0000664 0000000 0000000 00000000056 13625463046 0026426 0 ustar 00root root 0000000 0000000
library_path = 'test/lib/'
working_dir = ''
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/dir-file-compare/entry.py 0000775 0000000 0000000 00000000737 13625463046 0026333 0 ustar 00root root 0000000 0000000 #!/usr/bin/python3
# Unknown script
# Workaround for fucking Windows NT
import traceback
def show_exception_and_exit(exc_type, exc_value, tb):
traceback.print_exception(exc_type, exc_value, tb)
input("Press any key to exit.")
sys.exit(-1)
import sys
import os, shutil
if os.name == 'nt':
sys.excepthook = show_exception_and_exit
import main
def _main():
main.main(sys.argv)
try:
_main()
except Exception as e:
#alert(repr(e), 'Error')
raise
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/dir-file-compare/main.py 0000664 0000000 0000000 00000002657 13625463046 0026116 0 ustar 00root root 0000000 0000000 import os, filecmp, config
def get_flist(rootdir):
result = []
for (dirpath, dirnames, filenames) in os.walk(rootdir):
result += [dirpath + os.path.sep + fname for fname in filenames]
return set(result)
def fileEq(fileL, fileR):
return filecmp.cmp(fileL, fileR)
def fuck(fl):
return os.path.basename(os.path.splitext(fl)[0])
def main(argv):
if len(argv) != 2:
raise RuntimeError('Missing arg! Usage: ./this.py
')
inputPath = argv[1]
libFlist = get_flist(config.library_path)
out_csv = []
for fl in get_flist(inputPath):
libFile = list(filter(lambda f: os.path.basename(f) == os.path.basename(fl), libFlist))
if len(libFile) == 0:
print('NOT_FOUND: {}'.format(fl))
out_csv.append('未找到,{}'.format(fuck(fl)))
elif len(libFile) > 1:
print('DUPLICATE: Input `{}` has multiple candidate `{}` in library.'.format(fl, libFile))
out_csv.append('库文件重复,{},重名库文件,{}'.format(fuck(fl), libFile))
else:
if not fileEq(libFile[0], fl):
print('NOT_MATCH: {} != {}'.format(fl, libFile[0]))
out_csv.append('与库文件不匹配,{}'.format(fuck(fl)))
fname = config.working_dir + os.path.sep + os.path.basename(inputPath) + '.csv'
with open(fname, 'w+') as f:
f.write('\n'.join(out_csv)) # Windows M$ excel also not accepting \r\n
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/main.py 0000775 0000000 0000000 00000020104 13625463046 0022765 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# A script to deal with product sheet. (see test-*.csv)
import traceback
def show_exception_and_exit(exc_type, exc_value, tb):
traceback.print_exception(exc_type, exc_value, tb)
# input("Press any key to exit.")
# PROG BETA calls this program. do not block
sys.exit(-1)
import sys
import os
if os.name == 'nt':
sys.excepthook = show_exception_and_exit
from uniqer import *
from utils import *
import material
import csv_preprocess, xlsx_conv
import numpy as np
from io import StringIO
def _dirty_func_return_empty_sheet(fname):
materialFileName = fname[:-4] + '-(材料表).csv'
partFileName = fname[:-4] + '-(下料表).csv'
with open(materialFileName, 'w+') as f:
f.write('空表')
with open(partFileName, 'w+') as f:
f.write('空表')
exit(0)
def _main():
if len(sys.argv) < 2:
print('Usage: ./main.py ')
exit(1)
fname = sys.argv[1]
index_part_name = 5
index_material_name = 6
index_arg_begin = 7
index_addible = 10 # Ex: length is addible
index_amount = 13
index_comment = 12
max_args = 3 # EXCLUDE addible arg, which is always the last one
ignored_material_keywords = ['外购件'] # DO NOT contain junk_material_words, or it won't match.
junk_material_words = ['(厚)', '(宽)', '(单件重)']
junk_part_words = []
fcontent = xlsx_conv.read_as_csv(fname)
fcontent = csv_preprocess.clean_csv(fcontent)
if fcontent.strip() == '':
_dirty_func_return_empty_sheet(fname)
fcontent = csv_preprocess.clean_csv_2(fcontent)
#contArr = np.loadtxt(StringIO(fcontent), delimiter=',', dtype=str)
contArr = csv_preprocess.np_loadcsv_pycsv(StringIO(fcontent))
contArr = csv_preprocess.trim_npArr(contArr)
contMat = np.mat(contArr)
# Clean junk words
cleanedMat = np.matrix([[]], dtype=str)
for line in contArr:
for word in junk_material_words:
if word in line[index_material_name]:
line[index_material_name] = line[index_material_name].replace(word, '')
for word in junk_part_words:
if word in line[index_part_name]:
line[index_part_name] = line[index_part_name].replace(word, '')
cleanedMat = npmat_appendrow(cleanedMat, line)
contArr = np.array(cleanedMat)
contMat = cleanedMat
# Pick these ignored materials out
toSumMat = np.matrix([[]], dtype=str)
ignoredMat = np.matrix([[]], dtype=str)
for line in contArr:
ignored = False
for keyword in ignored_material_keywords:
if keyword in line[index_material_name]:
ignoredMat = npmat_appendrow(ignoredMat, line)
ignored = True
break
if not ignored:
toSumMat = npmat_appendrow(toSumMat, line)
# Make summation
keyIndexes = [index_material_name]
for i in range(max_args):
if index_arg_begin + i != index_addible:
keyIndexes.append(index_arg_begin + i)
sumedMaterialListMat = uniq(toSumMat, keyIndexes, [index_addible, index_amount])
keyIndexes.append(index_part_name)
keyIndexes.append(index_addible)
sumedPartListMat = uniq(toSumMat, keyIndexes, [index_amount])
sumedIgnoredMat = uniq(ignoredMat, keyIndexes, [index_amount])
# tidify material list
newMaterialList = [] # Tip: ignored materials are still ignored.
for line in np.array(sumedMaterialListMat).tolist():
newLine = [line[index_material_name]]
newLine.extend(line[index_arg_begin:index_arg_begin+max_args])
material_class = material.material_find_class_obj(line[index_material_name])
arg_list = [str_to_float(arg)/1000 for arg in line[index_arg_begin:index_arg_begin+max_args]]
m_length = float(line[index_addible])/1000
newLine.append(material_class.get_meter_per_unit()) # meter per unit
newLine.append(material_class.get_weight(arg_list, material_class.get_meter_per_unit())) # weight per unit
newLine.append(material_class.get_unit_amount(m_length)) # needed unit amount
newLine.append(material_class.get_weight(arg_list, m_length)) # needed weight
newLine = [str(i) for i in newLine]
newMaterialList.append(newLine)
# Add ignored materials before tidify part list
sumedPartListMat = npmat_appendrow(sumedPartListMat, sumedIgnoredMat)
# tidify part list
newPartList = []
for line in np.array(sumedPartListMat).tolist():
newLine = [line[index_part_name], line[index_material_name]]
newLine.extend(line[index_arg_begin:index_arg_begin+max_args])
newLine.append(line[index_addible])
newLine.append(line[index_amount])
newLine.append(line[index_comment])
newPartList.append(newLine)
# Add ignored materials to material list...
#for line in np.array(ignoredMat).tolist():
# newLine = [line[index_material_name] + ' 数量' + line[index_amount]]
# newLine.extend(line[index_arg_begin:index_arg_begin+max_args])
# newLine.extend(['','','','']) # Warning: if outputMaterialSheet is edited, you must edit this line.
# newMaterialList.append(newLine)
# Done.
outputMaterialMat = np.mat(newMaterialList, dtype=str)
outputPartMat = np.mat(newPartList, dtype=str)
# Make output sheet head
materialLine1 = ['材料表']
materialLine1.extend(['' for i in range(outputMaterialMat.shape[1]-1)])
materialLine2 = ['材料名称']
materialLine2.extend(['参数(mm)' for i in range(max_args)])
materialLine2.extend(['每根长度(m)','每根质量(kg)','理论需根数','理论需质量(kg)'])
materialLineEmpty = ['' for i in range(outputMaterialMat.shape[1])]
outputMaterialMat = npmat_appendrow(np.mat([materialLine1, materialLine2, materialLineEmpty, materialLineEmpty]), outputMaterialMat)
partLine1 = ['下料表']
partLine1.extend(['' for i in range(outputPartMat.shape[1]-1)])
partLine2 = ['零件名称','材料名称']
partLine2.extend(['参数(mm)' for i in range(max_args)])
partLine2.extend(['长度(mm)','数量','备注'])
partLine2.extend(['' for i in range(outputPartMat.shape[1]-len(partLine2))])
partLineEmpty = ['' for i in range(outputPartMat.shape[1])]
outputPartMat = npmat_appendrow(np.mat([partLine1, partLine2, partLineEmpty, partLineEmpty]), outputPartMat)
# Ok. Enjoy!
materialFileName = fname[:-4] + '-(材料表).csv'
partFileName = fname[:-4] + '-(下料表).csv'
np.savetxt(materialFileName, outputMaterialMat, fmt='%s', delimiter=',')
np.savetxt(partFileName, outputPartMat, fmt='%s', delimiter=',')
# Dirty func here.
cut_extra_info_for_2dmaterial(materialFileName)
def cut_extra_info_for_2dmaterial(csvName):
# This is a dirty function.
def _get_summed_weight(cont, niddle):
w = 0.0
for line in cont.split('\n'):
if line[:len(niddle)] == niddle:
w += str_to_float(line.split(',')[-1]) # Assume last element is weight
return str(w)
# No comma is allowed in 2dmaterial_name!
_2dmaterial_names = list(filter(lambda x: x != '', [mclass.name if mclass.is2d else '' for mclass in material.material_class_list]))
with open(csvName, 'r') as fd:
cont = fd.read()
result = ''
newLine_must_merge = []
for line in cont.split('\n'):
double_continue_flag = False
for name in _2dmaterial_names:
niddle = name + ','
if line[:len(niddle)] == niddle:
arg1 = line.split(',')[1]
newLine = niddle + arg1 + str_repeat(',', line.count(',')-1) + _get_summed_weight(cont, niddle+arg1+',')
if newLine in newLine_must_merge:
double_continue_flag = True
break
line = newLine
newLine_must_merge.append(newLine)
if double_continue_flag:
continue
result += line
result += '\n'
with open(csvName, 'w+') as fd:
fd.write(result)
try:
_main()
except Exception as e:
#alert(repr(e), 'Error')
raise
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/material.py 0000664 0000000 0000000 00000010166 13625463046 0023643 0 ustar 00root root 0000000 0000000 import math
class material_class():
def __init__(self, name, volume_calculator, density, meter_per_unit, is2d = False):
'''
Assume all arguments in SI.
mass = volume_calculator(arg_list, length) * density
Example: round_steel_pipe = material_class('圆管', 2,
(lambda args,len: math.pi*(args[0]^2-(args[0]-args[1])^2))*len, 7850, 6)
'''
self.name = name
#self.want_args = want_args
self.volume_calculator = volume_calculator
self.density = density
self.meter_per_unit = meter_per_unit
self.is2d = is2d
def get_weight(self, arg_list, length):
#if len(arg_list) < self.want_args:
# raise AssertionError('material {} must have {} arguments, but gave {}.'.format(self.name, self.want_args, len(arg_list)))
return self.volume_calculator(arg_list, length) * self.density
def get_meter_per_unit(self):
return self.meter_per_unit
def get_unit_amount(self, length):
return length / self.meter_per_unit
class material():
def __init__(self, m_class, arg_list):
'''
Give all arguments in SI please!
Example: pipe_r40_d8 = material(round_steel_pipe, (40*0.001, 8*0.001))
'''
self.m_class = m_class
self.arg_list = arg_list
def get_weight(self, length):
return self.m_class.get_weight(self.arg_list, length)
def get_meter_per_unit(self):
return self.m_class.get_meter_per_unit()
def get_unit_amount(self, length):
return self.m_class.get_unit_amount(length)
def _calc_triangle_pipe_area(arg0, arg1):
sqrt2 = math.sqrt(2)
p = arg1 - (2+sqrt2) * arg0
area1 = arg0 * (sqrt2 * arg1 - arg0)
area2 = arg0 * (arg0 + p)
return area1 + 2 * area2
material_class_list = [
material_class('扁钢', (lambda args, length: 1.00000 * args[0] * args[1] * length), 7850, 6),
material_class('扁钢--易折弯', (lambda args, length: 1.00000 * args[0] * args[1] * length), 7850, 6),
material_class('方钢', (lambda args, length: 1.00000 * args[0] * args[0] * length), 7850, 6),
material_class('板材', (lambda args, length: 1.00000 * args[0] * args[1] * length), 7850, 6, True),
material_class('板材--冷轧板', (lambda args, length: 1.00000 * args[0] * args[1] * length), 7850, 6, True),
material_class('花纹板', (lambda args, length: 1.00000 * args[0] * args[1] * length), 7850, 6, True),
material_class('圆钢', (lambda args, length: 1.00000*3.14159265*args[0]*args[0]*length/4), 7850, 9),
material_class('圆管', (lambda args, length: 1.00000*3.14159265*args[1]*(args[0]-args[1])*length), 7850, 6),
material_class('圆无缝管', (lambda args, length: 1.00000*3.14159265*args[1]*(args[0]-args[1])*length), 7850, 9),
material_class('矩形管', (lambda args, length: 1.00000*2*args[0]*(args[1]+args[2]-2*args[0])*length), 7850, 6),
material_class( '方管' , (lambda args, length: 1.00000*4*args[0]*(args[1]-args[0])*length), 7850, 6),
material_class('不等边角钢', (lambda args, length: 1.01493*args[0]*(args[1]+args[2]-args[0])*length), 7850, 6),
material_class('等边角钢', (lambda args, length: 1.01493*args[0]*(args[1]+args[1]-args[0])*length), 7850, 6),
material_class('三角管', (lambda args, length: 1.00000*_calc_triangle_pipe_area(args[0],args[1])*length), 7850, 6),
material_class('三棱钢', (lambda args, length: 1.00000*args[0]*1000*length), 1, 6), # Be caution to its density! lambda is giving weight rather than volume!
]
'''
material arguments:
All input length is mm. All input weight is kg.
name arg1 arg2 ...
扁钢 厚度 宽度
方钢 宽度
板材 厚度 宽度
花纹板 厚度 宽度
圆钢 直径
圆管 外直径 厚度
圆无缝管 外直径 厚度
矩形管 厚度 a b
方管 厚度 a
不等边角钢 厚度 a b
等边角钢 厚度 a
三角管 厚度 边长
三棱钢 每米质量
'''
def material_find_class_obj(class_name):
global material_class_list
for cls in material_class_list:
if cls.name == class_name:
return cls
raise KeyError('material class `{}` not found.'.format(class_name))
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/summerize-part-list/ 0000775 0000000 0000000 00000000000 13625463046 0025424 5 ustar 00root root 0000000 0000000 product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/summerize-part-list/__init__.py 0000664 0000000 0000000 00000000000 13625463046 0027523 0 ustar 00root root 0000000 0000000 product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/summerize-part-list/beta2alpha.py 0000664 0000000 0000000 00000002634 13625463046 0030006 0 ustar 00root root 0000000 0000000 def _stoi(s):
# string to int
return 0 if (s is None or s == '') else int(float(s))
# convert BETA output csv, to match the format of ALPHA input format.
def csv_beta2alpha(csvText):
lines = csvText.split('\n')
res = lines[0] + ',总数量(autogen), __uniqer_begin__\n' # Silly M$ office don't like \r\n.
for line in lines[1:]:
items = line.split(',')
if len(items) <= 1:
continue # empty line
if len(items) != 13:
raise RuntimeError('Invalid line while performing BETA => ALPHA: ' + line)
actual_quantity = str(_stoi(items[3]) * _stoi(items[4]))
res += '{},{}\n'.format(line.replace('"',''), actual_quantity)
res += '__uniqer_end__\n'
return res
import os, subprocess
def execute_program_alpha(mypath, parent_arg1):
if not mypath.endswith('main.py'):
raise RuntimeError('CurrPath should end with `main.py`, but it is: ' + mypath)
par = os.path.abspath(mypath[:-7] + '../main.py')
args = [par, parent_arg1]
if os.name == 'nt':
args = ['python'] + args
print('EXEC =======================>', args)
ret = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
print(ret.stdout)
if ret.returncode != 0:
raise RuntimeError('SubProcess returned in status ' + str(ret.returncode))
print('EXEC SUBPROC EXITED =======================>')
os.remove(parent_arg1)
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/summerize-part-list/config.py 0000664 0000000 0000000 00000000613 13625463046 0027243 0 ustar 00root root 0000000 0000000
library_path = 'test/libs'
working_dir = ''
allow_part_tree_reference = False
allow_part_recursive_reference = False # Supported but disabled.
tmp_prefix = '_python_tmp_prefix_'
file_encoding = 'gb2312'
search_only_top_level_directory = False
output_dirname = 'output'
# index of column in specific part-material list.
part_name_col_index = 5
part_quantity_col_index = 4 # in 1 parent part
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/summerize-part-list/main.py 0000775 0000000 0000000 00000020431 13625463046 0026725 0 ustar 00root root 0000000 0000000 #!/usr/bin/python3
# A script to deal with product sheet. (see test-*.xlsx)
# Workaround for fucking Windows NT
import traceback
def show_exception_and_exit(exc_type, exc_value, tb):
traceback.print_exception(exc_type, exc_value, tb)
input("Press any key to exit.")
sys.exit(-1)
import sys
import os, shutil
if os.name == 'nt':
sys.excepthook = show_exception_and_exit
# Allow import parent
import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir)
import config, xlsx_conv, io
import csv_preprocess
import numpy as np
from utils import *
import beta2alpha
csv_buf = io.StringIO()
import logging
############################ Change working directory. ################################
if config.working_dir != "":
os.chdir(config.working_dir)
def log_error(msg):
print('Error:', msg)
def log_warn(msg):
print('Warning:', msg)
missing_parts = []
def _main():
if len(sys.argv) < 2:
print('Usage: ./main.py ')
exit(1)
fname = sys.argv[1]
output_prefix = fname[:-4]
config.output_dirname = output_prefix + config.output_dirname
csvIO = io.StringIO()
xlsx_conv.xlsx2csv(fname, 0, csvIO)
fcontent = csvIO.getvalue()
fcontent = csv_preprocess.clean_csv(fcontent, begin_keyword='__summarize_begin__', end_keyword='__summarize_end__')
fcontent = csv_preprocess.clean_csv_2(fcontent)
contArr = csv_preprocess.np_loadcsv_pycsv(io.StringIO(fcontent))
contArr = csv_preprocess.trim_npArr(contArr)
contMat = np.mat(contArr)
os.mkdir(config.output_dirname)
for line in contMat:
line = line.tolist()[0]
serial, product_id, product_name, quantity = line[0], line[1], line[2], line[3]
print('[{}]Adding product {} {}({}) ...'.format(serial, quantity, product_name, product_id))
add_product(serial, product_id, product_name, quantity, must_have_xlsx=config.allow_part_tree_reference) # first-level recursive is enabled. Update: controlled by config, should never switched on.
_magic_merge_missing_parts()
with open(output_prefix + '.csv', 'w+') as f:
# Force windows NT use Linux LF. M$ office don't like CRLF csv.
msg = '序号,,,套数,单套数量,零件名称,材料规格,参数A,参数B,参数C,长度,单件重,备注\n' + csv_buf.getvalue().replace('\r\n', '\n')
f.write(beta2alpha.csv_beta2alpha(msg))
with open(output_prefix + '-(缺失图纸材料表).csv', 'w+') as f:
# Force windows NT use Linux LF. M$ office don't like CRLF csv.
f.write('\n'.join(missing_parts))
beta2alpha.execute_program_alpha(sys.argv[0], output_prefix + '.csv')
def get_part_metadata_from_csv_text(csvText):
# Part Unique ID, Part Name
try:
ar = csvText.split('\n')[3].split(',')
return ar[1], ar[2]
except:
log_error("Error: Invalid csvText while parsing part_metadata")
raise
def add_product(serial, _id, name, quantity, must_have_xlsx=False, allow_recursive_part_ref=True):
global csv_buf, missing_parts
_id = _id.replace(' ', '')
print('ADD_PRODUCT: serial={}, _id={}, name={}, quantity={}'.format(serial, _id, name, quantity))
# Search & read product/part file.
found_pdf, found_xlsx = None, None
is_xlsx = lambda fname: fname.endswith('.xlsm') or fname.endswith('.xlsx') or fname.endswith('.xls') or fname.endswith('.XLSM') or fname.endswith('.XLSX') or fname.endswith('.XLS')
is_pdf = lambda fname: fname.endswith('.pdf') or fname.endswith('.PDF')
for (dirpath, dirnames, filenames) in os.walk(config.library_path):
for fname in filenames:
if fname.startswith(_id):
if is_pdf(fname):
found_pdf = dirpath + os.path.sep + fname
elif is_xlsx(fname):
found_xlsx = dirpath + os.path.sep + fname
else:
log_error('Unknown file {} while looking for {}. Skipped.'.format(fname, _id))
if (found_pdf is not None) or config.search_only_top_level_directory:
break
if found_pdf is None:
name_and_id = '{}({})'.format(name, _id)
log_error('Unable to locate part `{}` in `{}`, with search_only_top_level_directory={}.'.format(name_and_id, config.library_path, config.search_only_top_level_directory))
missing_parts.insert(0, '{},{},{}'.format(_id, name, '少图')) # PDF should always appear in front of XLSx.
else:
# Found the product pdf.
try_copy(found_pdf, config.output_dirname)
if found_xlsx is not None:
#try_copy(found_xlsx, config.output_dirname)
# Write CSV
csvIO = io.StringIO()
xlsx_conv.xlsx2csv(found_xlsx, 0, csvIO)
fcontent = csvIO.getvalue()
part_id, part_name = get_part_metadata_from_csv_text(fcontent)
fcontent = csv_preprocess.clean_csv(fcontent, begin_keyword='_begin__', end_keyword='_end__')
fcontent = csv_preprocess.clean_csv_2(fcontent)
contArr = csv_preprocess.np_loadcsv_pycsv(io.StringIO(fcontent))
contArr = csv_preprocess.trim_npArr(contArr)
contMat = np.mat(contArr)
contMat[:,0] = serial
contMat[:,1] = part_id
contMat[:,2] = part_name
contMat[:,3] = quantity
contMat = npmat_truncate_cols(contMat, 13) # magic number: only keep the first 13 columns of material list.
############## dirty begin
### dirty part: append POSTFIX part_id to each part without PREFIX id. shitty, right?
##_dirty_subpart_name_counter = {} # 'name' -> 3
##def _get_subpart_name_count(name):
## if name in _dirty_subpart_name_counter:
## _dirty_subpart_name_counter[name] = 1 + _dirty_subpart_name_counter[name]
## else:
## _dirty_subpart_name_counter[name] = 1
## return str(_dirty_subpart_name_counter[name])
##_new_contMat = np.matrix([[]], dtype=str)
##for line in contMat:
## line = line.tolist()[0]
## subpart_name = line[config.part_name_col_index]
## if get_id_prefix_from_string(subpart_name) == '':
## line[config.part_name_col_index] = subpart_name + part_id + '-' + _get_subpart_name_count(subpart_name)
## _new_contMat = npmat_appendrow(_new_contMat, [line])
##contMat = _new_contMat
############## dirty end
## dirty part removed at 2020.02.17, unknown reason. backup it up, and do not remove this!
# moved down # csv_preprocess.npmat2csv(contMat, csv_buf)
for line in contMat:
# recursive part reference
if allow_recursive_part_ref:
line_ar = line.tolist()[0]
part_name = line_ar[config.part_name_col_index]
part_id = get_id_prefix_from_string(part_name)
if part_id != '':
if part_id.startswith(_id):
log_warn('Self-reference detected on part {}. Skipping recursive walking.'.format(_id))
else:
if add_product(serial, part_id, part_name, stoi(quantity)*stoi(line_ar[config.part_quantity_col_index]), allow_recursive_part_ref=config.allow_part_tree_reference): # If found sub-part xlsx:
continue # DO not put the parent material into csv_buf again!
# put line into csv_buf
csv_preprocess.npmat2csv(line, csv_buf)
else:
if must_have_xlsx:
name_and_id = '{}({})'.format(name, _id)
log_error('Error: Unable to find xls for {} (xls/xlsm/xlsx)'.format(name_and_id))
missing_parts.append('{},{},{}'.format(_id, name, '少材料'))
print('ADD_PRODUCT END. found_xlsx =', found_xlsx)
return found_xlsx
def _magic_merge_missing_parts():
global missing_parts
buf = {}
for line in missing_parts:
line = line.split(',')
k = (line[0], line[1])
v = line[2]
v_old = buf.get(k)
if v_old == None:
buf[k] = v
elif v in v_old:
continue
else:
buf[k] = v + v_old
missing_parts = []
for k in buf:
missing_parts.append('{},{},{}'.format(k[0], k[1], buf.get(k)))
try:
_main()
except Exception as e:
#alert(repr(e), 'Error')
raise
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/test-gb2312.csv 0000664 0000000 0000000 00000025202 13625463046 0024062 0 ustar 00root root 0000000 0000000 ˺Ŀᣨ0֣ ,,,,,õ,,,,,,,,,,,,
:2018-1-31 Ʊ:2018-1-27 ,,,,,,,,,,,,,,,,,
,ͼ,,,,,,,,,,,,,,,,
1,6420-6105CN,"̶,Q235,T2.75,",2748,,,,,,,,,,,,,,
2,6420-6006ACN,ת1Q23532-T2.5λ,5052,,,,,,,,,,,,,,
3,6420-6014CN,תܺӼλ,4573,,,,,,,,,,,,,,
4,6420-6023ACN,ѹܺӣλ,5052,,,,,,,,,,,,,,
5,FMCX0001ACN,תᣬ350 ,2952,,,,,,,,,,,,,,
6,FMHDDJ001CN,ڹ̶壬λ ,2526,,,,,,,,,,,,,,
7,FMHM001CN,"źӼ,ᶨλ",2526,,,,,,,,,,,,,,
8,FMYL0005CN,"Ӽ,Ҷλ",2526,,,,,,,,,,,,,,
9,FMZL0005CN,"Ӽ,λ",2526,,,,,,,,,,,,,,
10,FMZQM001CN,ᶨλǰ,1263,,,,,,,,,,,,,,
11,FMYQM001CN,ᶨλǰ,1263,,,,,,,,,,,,,,
12,FMZQMK006CN,ǰſ,1263,,,,,,,,,,,,,,
13,FMYQMK006CN,Ҳǰſ,1263,,,,,,,,,,,,,,
14,FMHMPVCLZ001CN, PVC ֧ ,2526,,,,,,,,,,,,,,
15,FMHMPVCLZ002CN, PVC ֧ ,2526,,,,,,,,,,,,,,
16,FMLZ0001CN,PVC֧ܣ506MM ,414,,,,,,,,,,,,,,
17,6420-0100CN,Ǹ֣35x35 2.75 ,444,,,,,,,,,,,,,,
18,FMLZ0004CN,PVC֧ܣ506MM ,207,,,,,,,,,,,,,,
19,FMLZ0005CN,PVC֧ܣ506MM ,207,,,,,,,,,,,,,,
20,FMLZ0006CN,PVC֧ܣ506MM ,2304,,,,,,,,,,,,,,
21,6420-6028ECN,"̶,Q235,T2.75,",4608,,,,,,,,,,,,,,
22,6420-6106CN,"ѹ,",4608,,,,,,,,,,,,,,
23,FMLZ0001ACN,PVC֧ܣ506MM ,15,,,,,,,,,,,,,,
24,FMLZ0001BCN,PVC֧ܣ506MM ,15,,,,,,,,,,,,,,
25,FMLZ0004CCN,PVC֧ܣ506MM ,15,,,,,,,,,,,,,,
26,FMLZ0005ACN,PVC֧ܣ506MM ,15,,,,,,,,,,,,,,
27,FMHMPVCLZ003CN,ᵲ֧,60,,,,,,,,,,,,,,
28,6420-6028GCN,"UͲ,Q235,T2.75,ſ",60,,,,,,,,,,,,,,
ȶпȡ80um,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,
,,,,,,Ϲ,A,B,C,,,,ע,,,213216,__uniqer_begin__
1,6420-6105CN,"̶,Q235,T2.75,",2748,1,̶ 6105CN,,2.75,40,,101.4,0.088,2748,,0.0875589,0.0875589,240.6,
2,6420-6006ACN,ת1Q23532-T2.5λ,5052,1,ת1 6006ACN,Բ,32.8,2.5,,1128,2.107,5052,,2.107226728,2.107226728,10645.7,
3,6420-6014CN,תܺӼλ,4573,1,Բ 6015CN,Բ,42,2.5,,40,0.097,4573,,0.097412934,1.698812934,7768.7,
,,,4573,1,Ӱ 6012CN,,6,40,,850,1.601,4573,,1.6014,,0.0,
4,6420-6023ACN,ѹܺӣλ,5052,1,ѹ 6008ACN,Բ,32.8,2.5,,1976.5,3.692,5052,,3.692317046,3.728569455,18836.7,
,,,5052,1,Բ 6043CN,Բ,14,,,30,0.036,5052,,0.036252408,,0.0,
5,FMCX0001ACN,תᣬ350 ,2952,1, 6046ACN,Բ,14,,,350,0.423,2952,,0.422944765,0.432944765,1278.1,
,,,2952,1,M14Ȧƣ,,,,,,0.010,2952,,0.01,,0.0,
6,FMHDDJ001CN,ڹ̶壬λ ,2526,1,ְ 6049ACN,,5,120,,245,1.154,2526,,1.15395,1.5543,3926.2,
,,,2526,1, 6182CN,,5,60,,170,0.400,2526,,0.40035,,0.0,
7,FMHM001CN,"źӼ,ᶨλ",2526,1, 6124CN,Բ,32.8,2.5,,1434.8,2.680,2526,,2.680362508,4.788726818,12096.3,
,,,2526,2,Ӱ 6126CN,,6,40,,170,0.320,5052,,0.64056,,0.0,
,,,2526,2,ֱ֧Ÿ 6127CN,Բ,14,,,408,0.493,5052,,0.986065509,,0.0,
,,,2526,1,ѹ 6147CN,,6,40,,255.7,0.482,2526,,0.4817388,,0.0,
8,FMYL0005CN,"Ӽ,Ҷλ",2526,1,֧ 6055BCN,Բ,32.8,2.5,,768.5,1.436,2526,,1.435641614,17.83521974,45051.8,
,,,2526,2, 6057ACN,Բ,32.8,2.5,,1850,3.456,5052,,6.912002566,,0.0,
,,,2526,1,֧ 6056ACN,Բ,32.8,2.5,,641.6,1.199,2526,,1.198578607,,0.0,
,,,2526,1, 6058ACN,Բ,32.8,2.5,,1338.7,2.501,2526,,2.500837253,,0.0,
,,,2526,1,4 6010ACN,Բ,32.8,2.5,,1293,2.415,2526,,2.41546468,,0.0,
,,,2526,2,ӹ 6007CN,Բ,42,2.5,,100,0.244,5052,,0.487064671,,0.0,
,,,2526,5, 6016CN,,8,30,,74,0.139,12630,,0.69708,,0.0,
,,,2526,1,Ӱ 6011CN,,3,15,,37.5,0.013,2526,,0.013246875,,0.0,
,,,2526,1,ѹ˺֧,,8,120,,108,0.542,2526,,0.542,,0.0,
,,,2526,1,ؽŰ 6181CN,,6,45,,115,0.232,2526,,0.232,,0.0,
,,,2526,1,Բ 6149CN ,Բ,16,,,90,0.142,2526,,0.142050253,,0.0,
,,,2526,1,Ӽ 6004BCN,,8,50,,342.4,1.075,2526,,1.075136,,0.0,
,,,2526,1,Բ 6044CN,Բ,14,,,90,0.109,2526,,0.108757225,,0.0,
,,,2526,1,λ 6189CN,,8,40,,30,0.075,2526,,0.07536,,0.0,
9,FMZL0005CN,"Ӽ,λ",2526,1,֧ 6055BCN,Բ,32.8,2.5,,768.5,1.436,2526,,1.435641614,17.83521974,45051.8,
,,,2526,2, 6057ACN,Բ,32.8,2.5,,1850,3.456,5052,,6.912002566,,0.0,
,,,2526,1,֧ 6056ACN,Բ,32.8,2.5,,641.6,1.199,2526,,1.198578607,,0.0,
,,,2526,1, 6058ACN,Բ,32.8,2.5,,1338.7,2.501,2526,,2.500837253,,0.0,
,,,2526,1,4 6010ACN,Բ,32.8,2.5,,1293,2.415,2526,,2.41546468,,0.0,
,,,2526,2,ӹ 6007CN,Բ,42,2.5,,100,0.244,5052,,0.487064671,,0.0,
,,,2526,5, 6016CN,,8,30,,74,0.139,12630,,0.69708,,0.0,
,,,2526,1,Ӱ 6011CN,,3,15,,37.5,0.013,2526,,0.013246875,,0.0,
,,,2526,1,ѹ˺֧,,8,120,,108,0.542,2526,,0.542,,0.0,
,,,2526,1,ؽŰ 6181CN,,6,45,,115,0.232,2526,,0.232,,0.0,
,,,2526,1,Բ 6149CN ,Բ,16,,,90,0.142,2526,,0.142050253,,0.0,
,,,2526,1,Ӽ 6004BCN,,8,50,,342.4,1.075,2526,,1.075136,,0.0,
,,,2526,1,Բ 6044CN,Բ,14,,,90,0.109,2526,,0.108757225,,0.0,
,,,2526,1,λ 6189CN,,8,40,,30,0.075,2526,,0.07536,,0.0,
10,FMZQM001CN,ᶨλǰ,1263,1,ſ 6031CN,,2.5,30,,2202,4.754,1263,,4.7535675,6.670223907,8424.5,
,,,1263,2, 6032CN,,2.75,40,,430,0.371,2526,,0.74261,,0.0,
,,,1263,1, 6036ACN,Բ,14,,,414,0.500,1263,,0.500283236,,0.0,
,,,1263,1,Բ 6152CN,Բ,12,,,124.8,0.111,1263,,0.110799198,,0.0,
,,,1263,2,Ӽ 6033ACN,,6,40,,56,0.071,2526,,0.142,,0.0,
,,,1263,2,Բ 6035CN,Բ,12,,,109.8,0.097,2526,,0.194963973,,0.0,
,,,1263,2,,,,,,,0.113,2526,,0.226,,0.0,
11,FMYQM001CN,ᶨλǰ,1263,1,ſ 6031CN,,2.5,30,,2202,4.754,1263,,4.7535675,6.670223907,8424.5,
,,,1263,2, 6032CN,,2.75,40,,430,0.371,2526,,0.74261,,0.0,
,,,1263,1, 6036ACN,Բ,14,,,414,0.500,1263,,0.500283236,,0.0,
,,,1263,1,Բ 6152CN,Բ,12,,,124.8,0.111,1263,,0.110799198,,0.0,
,,,1263,2,Ӽ 6033ACN,,6,40,,56,0.071,2526,,0.142,,0.0,
,,,1263,2,Բ 6035CN,Բ,12,,,109.8,0.097,2526,,0.194963973,,0.0,
,,,1263,2,,,,,,,0.113,2526,,0.226,,0.0,
12,FMZQMK006CN,ǰſ,1263,1,ſ 6024CN,,2.5,30,,2527,5.455,1263,,5.45516125,11.90423057,15035.0,
,,,1263,2,UͲ 6028CN,,2.75,122.4,,500,1.321,2526,,2.64231,,0.0,
,,,1263,2,ؽŰ 6025ACN,,6,80,,160,0.603,2526,,1.20576,,0.0,
,,,1263,4,Ӱ 6027CN,,8,70,,63,0.277,5052,,1.107792,,0.0,
,,,1263,2,Ҷ 5145CN,Բ,25,4,,60,0.124,2526,,0.248587943,,0.0,
,,,1263,1,ſ,,,,,,0.110,1263,,0.11,,0.0,
,,,1263,1,,,3,25,,199,0.117,1263,,0.11716125,,0.0,
,,,1263,1,ǿ 6026CN,,6,50,,425,1.001,1263,,1.000875,,0.0,
,,,1263,1,λ 6062CN,,2.5,65,,13,0.017,1263,,0.016583125,,0.0,
13,FMYQMK006CN,Ҳǰſ,1263,1,ſ 6024CN,,2.5,30,,2527,5.455,1263,,5.45516125,11.89942244,15029.0,
,,,1263,2,UͲ 6028CN,,2.75,122.4,,500,1.321,2526,,2.64231,,0.0,
,,,1263,2,ؽŰ 6025ACN,,6,80,,160,0.603,2526,,1.20576,,0.0,
,,,1263,4,Ӱ 6027CN,,8,70,,63,0.277,5052,,1.107792,,0.0,
,,,1263,2,Ҷ 5145CN,Բ,25,4,,60,0.124,2526,,0.248587943,,0.0,
,,,1263,1,ſ,,,,,,0.110,1263,,0.11,,0.0,
,,,1263,1,,,3,25,,199,0.117,1263,,0.11716125,,0.0,
,,,1263,1,ǿ 6026CN,,6,50,,425,1.001,1263,,1.000875,,0.0,
,,,1263,1,λ 6062CN,,2.5,65,,13,0.012,1263,,0.011775,,0.0,
14,FMHMPVCLZ001CN, PVC ֧ ,2526,1,UͲ 6028GCN,,2.75,117.3,,475,1.203,2526,,1.202801531,1.385158544,3498.9,
,,,2526,2,Բ 6035BCN,Բ,12,,,102.7,0.091,5052,,0.182357013,,0.0,
15,FMHMPVCLZ002CN, PVC ֧ ,2526,1,UͲ 6028GCN,,2.75,117.3,,475,1.203,2526,,1.202801531,1.385158544,3498.9,
,,,2526,2,Բ 6035BCN,Բ,12,,,102.7,0.091,5052,,0.182357013,,0.0,
16,FMLZ0001CN,PVC֧ܣ506MM ,414,1,Ǹ 6048CN,,2.75,141.2,,500,1.524,414,,1.5240775,2.0991685,869.1,
,,,414,1,ְ 6047CN,,6,110,,111,0.575,414,,0.575091,,0.0,
17,6420-0100CN,Ǹ֣35x35 2.75 ,444,1,Ǹ 0100CN,,2.75,65.2,,500,0.704,444,,0.7037525,0.7037525,312.5,
18,FMLZ0004CN,PVC֧ܣ506MM ,207,1,ѹ 6146CCN,,2.75,155.8,,500,1.682,207,,1.68166625,2.356776455,487.9,
,,,207,1,ְ 6047CN,,6,110,,111,0.575,207,,0.575091,,0.0,
,,,207,2,UͲ 6180ACN,,2.75,22,,105.3,0.050,414,,0.100019205,,0.0,
19,FMLZ0005CN,PVC֧ܣ506MM ,207,1,ѹ 6146BCN,,2.75,155.8,,500,1.682,207,,1.68166625,2.356776455,487.9,
,,,207,1,ְ 6047CN,,6,110,,111,0.575,207,,0.575091,,0.0,
,,,207,2,UͲ 6180ACN,,2.75,22,,105.3,0.050,414,,0.100019205,,0.0,
20,FMLZ0006CN,PVC֧ܣ506MM ,2304,1,װ 7003ACN,,6,100,,180,0.848,2304,,0.8478,3.199395455,7371.4,
,,,2304,1,ѹ 6146ACN,,2.75,208.6,,500,2.252,2304,,2.25157625,,0.0,
,,,2304,2,UͲ 6180ACN,,2.75,22,,105.3,0.050,4608,,0.100019205,,0.0,
21,6420-6028ECN,"̶,Q235,T2.75,",4608,1,̶ 6028ECN,,2.75,81.4,,500,0.879,4608,,0.87861125,0.87861125,4048.6,
22,6420-6106CN,"ѹ,",4608,1,ѹ 6106CN,,2.75,40,,125,0.108,4608,,0.1079375,0.1079375,497.4,
23,FMLZ0001ACN,PVC֧ܣ506MM ,15,1,Ǹ 6048CN,,2.75,141.2,,500,1.524,15,,1.5240775,2.6091685,39.1,
,,,15,1,ְ 6047CN,,6,110,,111,0.575,15,,0.575091,,0.0,
,,,15,2,Ƭת 5122ACN,,6,80,,86,0.255,30,,0.51,,0.0,
24,FMLZ0001BCN,PVC֧ܣ506MM ,15,1,Ǹ 6048CN,,2.75,141.2,,500,1.524,15,,1.5240775,2.6091685,39.1,
,,,15,1,ְ 6047CN,,6,110,,111,0.575,15,,0.575091,,0.0,
,,,15,2,Ƭת 5122ACN,,6,80,,86,0.255,30,,0.51,,0.0,
25,FMLZ0004CCN,PVC֧ܣ506MM ,15,1,ѹ 6146ECN,,2.75,176,,500,1.900,15,,1.8997,3.084810205,46.3,
,,,15,1,ְ 6047CN,,6,110,,111,0.575,15,,0.575091,,0.0,
,,,15,2,UͲ 6180ACN,,2.75,22,,105.3,0.050,30,,0.100019205,,0.0,
,,,15,2,Ƭת 5122ACN,,6,80,,86,0.255,30,,0.51,,0.0,
26,FMLZ0005ACN,PVC֧ܣ506MM ,15,1,ѹ 6146DCN,,2.75,176,,500,1.900,15,,1.8997,3.084810205,46.3,
,,,15,1,ְ 6047CN,,6,110,,111,0.575,15,,0.575091,,0.0,
,,,15,2,UͲ 6180ACN,,2.75,22,,105.3,0.050,30,,0.100019205,,0.0,
,,,15,2,Ƭת 5122ACN,,6,80,,86,0.255,30,,0.51,,0.0,
27,FMHMPVCLZ003CN,ᵲ֧,60,1,UͲ 6028GCN,,2.75,117.3,,500,1.266,60,,1.266106875,1.473346875,88.4,
,,,60,2,ת֧ 5303ACN,,8,30,,55,0.104,120,,0.20724,,0.0,
28,6420-6028GCN,"UͲ,Q235,T2.75,ſ",60,1,UͲ 6028GCN,,2.75,117.3,,500,1.266,60,,1.266106875,1.266106875,76.0,
յ__uniqer_end__,,,,,,,,,,,,,,,,,
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/test-utf8.csv 0000664 0000000 0000000 00000027771 13625463046 0024065 0 ustar 00root root 0000000 0000000 大牧人合阳泛海项目分娩舍(0吨) ,,,,,配置单,,,,,,,,,,,,
发货日期:2018-1-31 制表:2018-1-27 刘,,,,,,,,,,,,,,,,,
序,焊件图号,焊件名称,套数,,理论重量,,,,,,,,,,,,
1,6420-6105CN,"固定板,Q235,T2.75,分娩舍",2748,,,,,,,,,,,,,,
2,6420-6006ACN,旋转杆1,Q235,Φ32-T2.5,分娩舍左定位栏,5052,,,,,,,,,,,,,,
3,6420-6014CN,旋转管焊接件,分娩舍左定位栏,4573,,,,,,,,,,,,,,
4,6420-6023ACN,防压管焊接,分娩舍左定位栏,5052,,,,,,,,,,,,,,
5,FMCX0001ACN,插销转轴,长350 分娩舍,2952,,,,,,,,,,,,,,
6,FMHDDJ001CN,调节固定板,定位栏 分娩舍,2526,,,,,,,,,,,,,,
7,FMHM001CN,"后门焊接件,分娩舍定位栏",2526,,,,,,,,,,,,,,
8,FMYL0005CN,"焊接件,分娩舍右定位栏",2526,,,,,,,,,,,,,,
9,FMZL0005CN,"焊接件,分娩舍左定位栏",2526,,,,,,,,,,,,,,
10,FMZQM001CN,分娩舍定位栏左前门,1263,,,,,,,,,,,,,,
11,FMYQM001CN,分娩舍定位栏右前门,1263,,,,,,,,,,,,,,
12,FMZQMK006CN,分娩舍左侧前门框,1263,,,,,,,,,,,,,,
13,FMYQMK006CN,分娩舍右侧前门框,1263,,,,,,,,,,,,,,
14,FMHMPVCLZ001CN,分娩舍 PVC 后门支架 左,2526,,,,,,,,,,,,,,
15,FMHMPVCLZ002CN,分娩舍 PVC 后门支架 右,2526,,,,,,,,,,,,,,
16,FMLZ0001CN,PVC支架,506MM 分娩舍,414,,,,,,,,,,,,,,
17,6420-0100CN,角钢,35x35 2.75厚 分娩舍,444,,,,,,,,,,,,,,
18,FMLZ0004CN,PVC支架,506MM 分娩舍,207,,,,,,,,,,,,,,
19,FMLZ0005CN,PVC支架,506MM 分娩舍,207,,,,,,,,,,,,,,
20,FMLZ0006CN,PVC支架,506MM 分娩舍,2304,,,,,,,,,,,,,,
21,6420-6028ECN,"固定板,Q235,T2.75,分娩舍",4608,,,,,,,,,,,,,,
22,6420-6106CN,"压板,分娩舍",4608,,,,,,,,,,,,,,
23,FMLZ0001ACN,PVC支架,506MM 分娩舍,15,,,,,,,,,,,,,,
24,FMLZ0001BCN,PVC支架,506MM 分娩舍,15,,,,,,,,,,,,,,
25,FMLZ0004CCN,PVC支架,506MM 分娩舍,15,,,,,,,,,,,,,,
26,FMLZ0005ACN,PVC支架,506MM 分娩舍,15,,,,,,,,,,,,,,
27,FMHMPVCLZ003CN,分娩舍挡猪门支架,60,,,,,,,,,,,,,,
28,6420-6028GCN,"U型槽,Q235,T2.75,分娩舍后门框",60,,,,,,,,,,,,,,
整体热镀锌厚度≥80um,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,
序号,,,套数,单套数量,零件名称,材料规格,参数A,参数B,参数C,长度,单件重,总数量,备注,单件总重,单套重,213216,程序起点__uniqer_begin__
1,6420-6105CN,"固定板,Q235,T2.75,分娩舍",2748,1,固定板 6105CN,扁钢,2.75,40,,101.4,0.088,2748,HereIsComment,0.0875589,0.0875589,240.6,
2,6420-6006ACN,旋转杆1,Q235,Φ32-T2.5,分娩舍左定位栏,5052,1,旋转杆1 6006ACN,圆管,32.8,2.5,,1128,2.107,5052,,2.107226728,2.107226728,10645.7,
2,6420-6006ACN,旋转杆1,Q235,Φ32-T2.5,分娩舍左定位栏,5052,1,旋转杆1 6006ACN,圆无缝管,32.8,2.5,,1128,2.107,5052,,2.107226728,2.107226728,10645.7,
3,6420-6014CN,旋转管焊接件,分娩舍左定位栏,4573,1,圆管 6015CN,圆管,42,2.5,,40,0.097,4573,,0.097412934,1.698812934,7768.7,
,,,4573,1,连接板 6012CN,扁钢,6,40,,850,1.601,4573,,1.6014,,0.0,
4,6420-6023ACN,防压管焊接,分娩舍左定位栏,5052,1,防压管 6008ACN,圆管,32.8,2.5,,1976.5,3.692,5052,,3.692317046,3.728569455,18836.7,
,,,5052,1,圆棒 6043CN,圆钢,14,,,30,0.036,5052,,0.036252408,,0.0,
5,FMCX0001ACN,插销转轴,长350 分娩舍,2952,1,轴 6046ACN,圆钢,14,,,350,0.423,2952,,0.422944765,0.432944765,1278.1,
,,,2952,1,M14垫圈(国标无镀),外购件,,,,,0.010,2952,,0.01,,0.0,
6,FMHDDJ001CN,调节固定板,定位栏 分娩舍,2526,1,钢板 6049ACN,扁钢,5,120,,245,1.154,2526,,1.15395,1.5543,3926.2,
,,,2526,1,卡板 6182CN,扁钢,5,60,,170,0.400,2526,,0.40035,,0.0,
7,FMHM001CN,"后门焊接件,分娩舍定位栏",2526,1,后门 6124CN,圆管,32.8,2.5,,1434.8,2.680,2526,,2.680362508,4.788726818,12096.3,
,,,2526,2,连接板 6126CN,扁钢,6,40,,170,0.320,5052,,0.64056,,0.0,
,,,2526,2,竖直支撑杆 6127CN,圆钢,14,,,408,0.493,5052,,0.986065509,,0.0,
,,,2526,1,压板 6147CN,扁钢,6,40,,255.7,0.482,2526,,0.4817388,,0.0,
8,FMYL0005CN,"焊接件,分娩舍右定位栏",2526,1,支柱管 6055BCN,圆管,32.8,2.5,,768.5,1.436,2526,,1.435641614,17.83521974,45051.8,
,,,2526,2,横杆 6057ACN,圆管,32.8,2.5,,1850,3.456,5052,,6.912002566,,0.0,
,,,2526,1,支柱管 6056ACN,圆管,32.8,2.5,,641.6,1.199,2526,,1.198578607,,0.0,
,,,2526,1,横杆 6058ACN,圆管,32.8,2.5,,1338.7,2.501,2526,,2.500837253,,0.0,
,,,2526,1,横杆4 6010ACN,圆管,32.8,2.5,,1293,2.415,2526,,2.41546468,,0.0,
,,,2526,2,连接管 6007CN,圆管,42,2.5,,100,0.244,5052,,0.487064671,,0.0,
,,,2526,5,铰链板 6016CN,扁钢,8,30,,74,0.139,12630,,0.69708,,0.0,
,,,2526,1,连接板 6011CN,扁钢,3,15,,37.5,0.013,2526,,0.013246875,,0.0,
,,,2526,1,防压杆后支架右,扁钢,8,120,,108,0.542,2526,,0.542,,0.0,
,,,2526,1,地脚板 6181CN,扁钢,6,45,,115,0.232,2526,,0.232,,0.0,
,,,2526,1,圆棒 6149CN ,圆钢,16,,,90,0.142,2526,,0.142050253,,0.0,
,,,2526,1,连接件 6004BCN,扁钢,8,50,,342.4,1.075,2526,,1.075136,,0.0,
,,,2526,1,圆棒 6044CN,圆钢,14,,,90,0.109,2526,,0.108757225,,0.0,
,,,2526,1,定位板 6189CN,扁钢,8,40,,30,0.075,2526,,0.07536,,0.0,
9,FMZL0005CN,"焊接件,分娩舍左定位栏",2526,1,支柱管 6055BCN,圆管,32.8,2.5,,768.5,1.436,2526,,1.435641614,17.83521974,45051.8,
,,,2526,2,横杆 6057ACN,圆管,32.8,2.5,,1850,3.456,5052,,6.912002566,,0.0,
,,,2526,1,支柱管 6056ACN,圆管,32.8,2.5,,641.6,1.199,2526,,1.198578607,,0.0,
,,,2526,1,横杆 6058ACN,圆管,32.8,2.5,,1338.7,2.501,2526,,2.500837253,,0.0,
,,,2526,1,横杆4 6010ACN,圆管,32.8,2.5,,1293,2.415,2526,,2.41546468,,0.0,
,,,2526,2,连接管 6007CN,圆管,42,2.5,,100,0.244,5052,,0.487064671,,0.0,
,,,2526,5,铰链板 6016CN,扁钢,8,30,,74,0.139,12630,,0.69708,,0.0,
,,,2526,1,连接板 6011CN,扁钢,3,15,,37.5,0.013,2526,,0.013246875,,0.0,
,,,2526,1,防压杆后支架左,扁钢,8,120,,108,0.542,2526,,0.542,,0.0,
,,,2526,1,地脚板 6181CN,扁钢,6,45,,115,0.232,2526,,0.232,,0.0,
,,,2526,1,圆棒 6149CN ,圆钢,16,,,90,0.142,2526,,0.142050253,,0.0,
,,,2526,1,连接件 6004BCN,扁钢,8,50,,342.4,1.075,2526,,1.075136,,0.0,
,,,2526,1,圆棒 6044CN,圆钢,14,,,90,0.109,2526,,0.108757225,,0.0,
,,,2526,1,定位板 6189CN,扁钢,8,40,,30,0.075,2526,,0.07536,,0.0,
10,FMZQM001CN,分娩舍定位栏左前门,1263,1,门框 6031CN,方管,2.5,30,,2202,4.754,1263,,4.7535675,6.670223907,8424.5,
,,,1263,2,板 6032CN,扁钢,2.75,40,,430,0.371,2526,,0.74261,,0.0,
,,,1263,1,横杆 6036ACN,圆钢,14,,,414,0.500,1263,,0.500283236,,0.0,
,,,1263,1,圆棒 6152CN,圆钢,12,,,124.8,0.111,1263,,0.110799198,,0.0,
,,,1263,2,连接件 6033ACN,扁钢,6,40,,56,0.071,2526,,0.142,,0.0,
,,,1263,2,圆棒 6035CN,圆钢,12,,,109.8,0.097,2526,,0.194963973,,0.0,
,,,1263,2,碰锁,外购件,,,,,0.113,2526,,0.226,,0.0,
11,FMYQM001CN,分娩舍定位栏右前门,1263,1,门框 6031CN,方管,2.5,30,,2202,4.754,1263,,4.7535675,6.670223907,8424.5,
,,,1263,2,板 6032CN,扁钢,2.75,40,,430,0.371,2526,,0.74261,,0.0,
,,,1263,1,横杆 6036ACN,圆钢,14,,,414,0.500,1263,,0.500283236,,0.0,
,,,1263,1,圆棒 6152CN,圆钢,12,,,124.8,0.111,1263,,0.110799198,,0.0,
,,,1263,2,连接件 6033ACN,扁钢,6,40,,56,0.071,2526,,0.142,,0.0,
,,,1263,2,圆棒 6035CN,圆钢,12,,,109.8,0.097,2526,,0.194963973,,0.0,
,,,1263,2,碰锁,外购件,,,,,0.113,2526,,0.226,,0.0,
12,FMZQMK006CN,分娩舍左侧前门框,1263,1,门框 6024CN,方管,2.5,30,,2527,5.455,1263,,5.45516125,11.90423057,15035.0,
,,,1263,2,U型槽 6028CN,板材,2.75,122.4,,500,1.321,2526,,2.64231,,0.0,
,,,1263,2,U型槽 6028CN,花纹板,2.75,122.4,,500,1.321,2526,,2.64231,,0.0,
,,,1263,2,U型槽 6028CN,花纹板,2.75,122.4,,500,1.321,2526,,2.64231,,0.0,
,,,1263,2,地脚板 6025ACN,扁钢,6,80,,160,0.603,2526,,1.20576,,0.0,
,,,1263,4,连接板 6027CN,扁钢,8,70,,63,0.277,5052,,1.107792,,0.0,
,,,1263,2,门栏挂耳 5145CN,圆管,25,4,,60,0.124,2526,,0.248587943,,0.0,
,,,1263,1,门扣,外购件,,,,,0.110,1263,,0.11,,0.0,
,,,1263,1,挡板,扁钢,3,25,,199,0.117,1263,,0.11716125,,0.0,
,,,1263,1,加强板 6026CN,扁钢,6,50,,425,1.001,1263,,1.000875,,0.0,
,,,1263,1,限位板 6062CN,扁钢,2.5,65,,13,0.017,1263,,0.016583125,,0.0,
13,FMYQMK006CN,分娩舍右侧前门框,1263,1,门框 6024CN,方管,2.5,30,,2527,5.455,1263,,5.45516125,11.89942244,15029.0,
,,,1263,2,U型槽 6028CN,板材,2.75,122.4,,500,1.321,2526,,2.64231,,0.0,
,,,1263,2,地脚板 6025ACN,扁钢,6,80,,160,0.603,2526,,1.20576,,0.0,
,,,1263,4,连接板 6027CN,扁钢,8,70,,63,0.277,5052,,1.107792,,0.0,
,,,1263,2,门栏挂耳 5145CN,圆管,25,4,,60,0.124,2526,,0.248587943,,0.0,
,,,1263,1,门扣,外购件,,,,,0.110,1263,,0.11,,0.0,
,,,1263,1,挡板,扁钢,3,25,,199,0.117,1263,,0.11716125,,0.0,
,,,1263,1,加强板 6026CN,扁钢,6,50,,425,1.001,1263,,1.000875,,0.0,
,,,1263,1,限位板 6062CN,扁钢,2.5,65,,13,0.012,1263,,0.011775,,0.0,
14,FMHMPVCLZ001CN,分娩舍 PVC 后门支架 左,2526,1,U型槽 6028GCN,板材,2.75,117.3,,475,1.203,2526,,1.202801531,1.385158544,3498.9,
,,,2526,2,圆棒 6035BCN,圆钢,12,,,102.7,0.091,5052,,0.182357013,,0.0,
15,FMHMPVCLZ002CN,分娩舍 PVC 后门支架 右,2526,1,U型槽 6028GCN,板材,2.75,117.3,,475,1.203,2526,,1.202801531,1.385158544,3498.9,
,,,2526,2,圆棒 6035BCN,圆钢,12,,,102.7,0.091,5052,,0.182357013,,0.0,
16,FMLZ0001CN,PVC支架,506MM 分娩舍,414,1,角钢 6048CN,板材,2.75,141.2,,500,1.524,414,,1.5240775,2.0991685,869.1,
,,,414,1,钢板 6047CN,扁钢,6,110,,111,0.575,414,,0.575091,,0.0,
17,6420-0100CN,角钢,35x35 2.75厚 分娩舍,444,1,角钢 0100CN,板材,2.75,65.2,,500,0.704,444,,0.7037525,0.7037525,312.5,
18,FMLZ0004CN,PVC支架,506MM 分娩舍,207,1,压板 6146CCN,板材,2.75,155.8,,500,1.682,207,,1.68166625,2.356776455,487.9,
,,,207,1,钢板 6047CN,扁钢,6,110,,111,0.575,207,,0.575091,,0.0,
,,,207,2,U型槽 6180ACN,板材,2.75,22,,105.3,0.050,414,,0.100019205,,0.0,
19,FMLZ0005CN,PVC支架,506MM 分娩舍,207,1,压板 6146BCN,板材,2.75,155.8,,500,1.682,207,,1.68166625,2.356776455,487.9,
,,,207,1,钢板 6047CN,扁钢,6,110,,111,0.575,207,,0.575091,,0.0,
,,,207,2,U型槽 6180ACN,板材,2.75,22,,105.3,0.050,414,,0.100019205,,0.0,
20,FMLZ0006CN,PVC支架,506MM 分娩舍,2304,1,底板 7003ACN,扁钢,6,100,,180,0.848,2304,,0.8478,3.199395455,7371.4,
,,,2304,1,压板 6146ACN,板材,2.75,208.6,,500,2.252,2304,,2.25157625,,0.0,
,,,2304,2,U型槽 6180ACN,板材,2.75,22,,105.3,0.050,4608,,0.100019205,,0.0,
21,6420-6028ECN,"固定板,Q235,T2.75,分娩舍",4608,1,固定板 6028ECN,板材,2.75,81.4,,500,0.879,4608,,0.87861125,0.87861125,4048.6,
22,6420-6106CN,"压板,分娩舍",4608,1,压板 6106CN,扁钢,2.75,40,,125,0.108,4608,,0.1079375,0.1079375,497.4,
23,FMLZ0001ACN,PVC支架,506MM 分娩舍,15,1,角钢 6048CN,板材,2.75,141.2,,500,1.524,15,,1.5240775,2.6091685,39.1,
,,,15,1,钢板 6047CN,扁钢,6,110,,111,0.575,15,,0.575091,,0.0,
,,,15,2,栏片转耳 5122ACN,板材,6,80,,86,0.255,30,,0.51,,0.0,
24,FMLZ0001BCN,PVC支架,506MM 分娩舍,15,1,角钢 6048CN,板材,2.75,141.2,,500,1.524,15,,1.5240775,2.6091685,39.1,
,,,15,1,钢板 6047CN,扁钢,6,110,,111,0.575,15,,0.575091,,0.0,
,,,15,2,栏片转耳 5122ACN,板材,6,80,,86,0.255,30,,0.51,,0.0,
25,FMLZ0004CCN,PVC支架,506MM 分娩舍,15,1,压板 6146ECN,板材,2.75,176,,500,1.900,15,,1.8997,3.084810205,46.3,
,,,15,1,钢板 6047CN,扁钢,6,110,,111,0.575,15,,0.575091,,0.0,
,,,15,2,U型槽 6180ACN,板材,2.75,22,,105.3,0.050,30,,0.100019205,,0.0,
,,,15,2,栏片转耳 5122ACN,板材,6,80,,86,0.255,30,,0.51,,0.0,
26,FMLZ0005ACN,PVC支架,506MM 分娩舍,15,1,压板 6146DCN,板材,2.75,176,,500,1.900,15,,1.8997,3.084810205,46.3,
,,,15,1,钢板 6047CN,扁钢,6,110,,111,0.575,15,,0.575091,,0.0,
,,,15,2,U型槽 6180ACN,板材,2.75,22,,105.3,0.050,30,,0.100019205,,0.0,
,,,15,2,栏片转耳 5122ACN,板材,6,80,,86,0.255,30,,0.51,,0.0,
27,FMHMPVCLZ003CN,分娩舍挡猪门支架,60,1,U型槽 6028GCN,板材,2.75,117.3,,500,1.266,60,,1.266106875,1.473346875,88.4,
,,,60,2,转动支板 5303ACN,扁钢,8,30,,55,0.104,120,,0.20724,,0.0,
28,6420-6028GCN,"U型槽,Q235,T2.75,分娩舍后门框",60,1,U型槽 6028GCN,板材,2.75,117.3,,500,1.266,60,,1.266106875,1.266106875,76.0,
程序终点__uniqer_end__,,,,,,,,,,,,,,,,,
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/test.py 0000664 0000000 0000000 00000000351 13625463046 0023017 0 ustar 00root root 0000000 0000000 from uniqer import *
import numpy as np
m = np.matrix([
[1,2,3,1],
[6,2,8,2],
[876,3,35,1],
[12,5,23,0],
[-1,55,2,0],
[1,1,1,0],
[1,2,44,2],
[9,1,1,0]
],dtype=str)
print(m)
print(uniq(m,(0,1),(2,3))) product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/uniqer.py 0000664 0000000 0000000 00000004275 13625463046 0023354 0 ustar 00root root 0000000 0000000 import numpy as np
from utils import *
import hashlib
def __quick_sha2(text):
# This function is slow, as it may become performance bottleneck sometimes.
# Use intel cpu hash cmd instead!
return str(hashlib.sha224(text.encode()).hexdigest())
def __sorter(matToSort):
# first col must be hash value, which is checked.
return matToSort[np.lexsort(matToSort.T[::-1])][0]
# Fuck the shitting numpy!!!!!!!
#matToSort.sort(axis=0)
def __hasher(matToAppendHash, keyIndexes):
# append uniq hash to first col, to feed __sorter.
results = np.matrix([[]])
for line in matToAppendHash:
currhash = 'sha2-'
for keyIndex in keyIndexes:
currhash = currhash + __quick_sha2(line[0, keyIndex])
newLine = np.concatenate((np.mat([[currhash]]), line), axis=1)
results = npmat_appendrow(newLine, results)
return results
def __uniqer(matToUniq, sumedIndexes):
cachedLine = np.matrix([[]])
results = np.matrix([[]])
for line in matToUniq:
sumedIndex = -1 # set to first sumedIndexes. -1 if none.
for index in sumedIndexes:
if sumedIndex == -1:
sumedIndex = index
continue
line[0,sumedIndex] = str(str_to_float(line[0,sumedIndex]) * str_to_float(line[0,index]))
line[0,index] = '1'
if cachedLine.size == 0:
cachedLine = line
continue
if line[0,0] == cachedLine[0,0]:
# Merge
if sumedIndex != -1:
cachedLine[0,sumedIndex] = str(str_to_float(line[0,sumedIndex])+str_to_float(cachedLine[0,sumedIndex]))
else:
results = npmat_appendrow(results, cachedLine)
cachedLine = line
results = npmat_appendrow(results, cachedLine)
return results
def uniq(matToUniq, keyIndexes, sumedIndexes = []):
# If there're many sumedIndexes, I'll multiply them and put result in the first one.
assert(type(matToUniq) == np.matrix)
if matToUniq.size == 0:
return matToUniq
m = __hasher(matToUniq, keyIndexes)
m = __sorter(m)
m = __uniqer(m, [i+1 for i in sumedIndexes]) # plus one because of hash column
return np.delete(m, 0, 1)
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/utils.py 0000664 0000000 0000000 00000003213 13625463046 0023200 0 ustar 00root root 0000000 0000000 import numpy as np
import ctypes
import os, shutil
def npmat_appendrow(src, toAppend):
if src is None:
return toAppend
if type(src) != np.matrix:
src = np.matrix(src)
if type(toAppend) != np.matrix:
toAppend = np.matrix(toAppend)
if src.size == 0:
return toAppend
if toAppend.size == 0:
return src
return np.concatenate((src, toAppend), axis=0)
def str_to_float(text):
text = text.replace(' ', '')
return float(0) if len(text) == 0 else float(text)
def str_repeat(string_to_expand, length):
return (string_to_expand * (int(length/len(string_to_expand))+1))[:length]
def alert(text, head='Alert'):
if os.name == 'nt':
MessageBox = ctypes.windll.user32.MessageBoxW
MessageBox(None, text, head, 0)
else:
print('{}> {}'.format(head, text))
def npmat_truncate_cols(mat, max_cols):
result = None
for line in mat:
tmp = line.copy()
tmp.resize(1, max_cols)
result = npmat_appendrow(result, tmp)
return result
def get_id_prefix_from_string(s):
first_illegal_char_index = 0
for i, c in enumerate(s.replace(' ', '')):
if c not in 'QWERTYUIOPASDFGHJKLZXCVBNM1234567890qwertyuiopasdfghjklzxcvbnm.-':
break
else:
first_illegal_char_index = i + 1
return s[:first_illegal_char_index]
def stoi(s):
# string to int
return 0 if (s is None or s == '') else int(float(s))
def try_copy(file_path, out_dir, dst = None):
name = dst or os.path.basename(file_path)
if not os.path.exists(os.path.join(out_dir, name)):
shutil.copy(file_path, os.path.join(out_dir, name))
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/xls-copy-paste/ 0000775 0000000 0000000 00000000000 13625463046 0024357 5 ustar 00root root 0000000 0000000 product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/xls-copy-paste/config.py 0000664 0000000 0000000 00000000574 13625463046 0026204 0 ustar 00root root 0000000 0000000
# all index starts from 1 here, because of the fucking silly xlsx.
src_title_ULcorner = 2,1
src_ULcorner = 3,1
dst_title_ULcorner = 2,1
dst_ULcorner = 3,1
# src may have cols: [A,C,F,G,H], [C,E,F,G], ...
src_cols = 3
# dst may have cols: [A,B,C,D,E,F,G,H,I,J]
dst_cols = 8
src_dir_path = 'test/'
dst_filename = template_filename = 'test/output.xlsx'
daemon_loop_interval = 5
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/xls-copy-paste/entry.py 0000775 0000000 0000000 00000000736 13625463046 0026103 0 ustar 00root root 0000000 0000000 #!/usr/bin/python3
# Unknown script
# Workaround for fucking Windows NT
import traceback
def show_exception_and_exit(exc_type, exc_value, tb):
traceback.print_exception(exc_type, exc_value, tb)
input("Press any key to exit.")
sys.exit(-1)
import sys
import os, shutil
if os.name == 'nt':
sys.excepthook = show_exception_and_exit
import main
def _main():
main.main(sys.argv)
try:
_main()
except Exception as e:
#alert(repr(e), 'Error')
raise
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/xls-copy-paste/main.py 0000664 0000000 0000000 00000012323 13625463046 0025656 0 ustar 00root root 0000000 0000000
import openpyxl
import config
import os, time, logging
# https://yagisanatode.com/2017/11/18/copy-and-paste-ranges-in-excel-with-openpyxl-and-python-3/
#Copy range of cells as a nested list
#Takes: start cell, end cell, and sheet you want to copy from.
def copyRange(startRow, startCol, endRow, endCol, sheet):
rangeSelected = []
#Loops through selected Rows
for i in range(startRow,endRow,1):
#Appends the row to a RowSelected list
rowSelected = []
for j in range(startCol,endCol,1):
rowSelected.append(sheet.cell(row = i, column = j).value)
#Adds the RowSelected List and nests inside the rangeSelected
rangeSelected.append(rowSelected)
return rangeSelected
#Paste range
#Paste data from copyRange into template sheet
def pasteRange(startRow, startCol, endRow, endCol, sheetReceiving, copiedData):
countRow = 0
for i in range(startRow,endRow,1):
countCol = 0
for j in range(startCol,endCol,1):
sheetReceiving.cell(row = i, column = j).value = copiedData[countRow][countCol]
countCol += 1
countRow += 1
def delete_rows_below(sheet, rowIndex):
# including rowIndex
sheet.delete_rows(rowIndex, sheet.max_row - rowIndex + 1)
def enlarge_2darray_by_title(input_title, output_title, input_2darray):
output_2darray = []
def locate(t):
try:
index = output_title.index(t)
except ValueError:
raise RuntimeError('Unable to locate {} in output_titles {}'.format(t, output_title))
return index
# conv_list[index_in_input_arr] => index_in_output_arr
conv_list = [locate(t) for t in input_title]
def conv_1darr(arr):
out_arr = ['' for _ in output_title]
for cter, item in enumerate(arr):
out_arr[conv_list[cter]] = item
return out_arr
return [conv_1darr(arr) for arr in input_2darray]
def get_flist(rootdir):
result = []
for (dirpath, dirnames, filenames) in os.walk(rootdir):
result += [dirpath + os.path.sep + fname for fname in filenames]
# remove the output sheet
is_xlsx = lambda fname: fname.endswith('.xlsm') or fname.endswith('.xlsx') or fname.endswith('.xls') or fname.endswith('.XLSM') or fname.endswith('.XLSX') or fname.endswith('.XLS')
result = list(filter(lambda f: os.path.basename(config.dst_filename) not in f and is_xlsx(f), result))
return set(result)
import plugin_date, plugin_remove_space
# (x,y) means (rowIndex, colIndex)
all_copied_data = []
def process_all(flist):
global all_copied_data
all_copied_data = []
output_xls = openpyxl.load_workbook(config.template_filename)
output_xls_sheet = output_xls.worksheets[0]
output_title = copyRange(config.dst_title_ULcorner[0], config.dst_title_ULcorner[1], config.dst_title_ULcorner[0]+1, config.dst_title_ULcorner[1]+config.dst_cols, output_xls_sheet)[0]
def process_one_src(fname):
global all_copied_data, nt_err_msg
logging.info('Working on file ' + fname)
input_sheet = openpyxl.load_workbook(fname).worksheets[0]
x,y = init_x,init_y = config.src_ULcorner
while input_sheet.cell(x, y).value != None and input_sheet.cell(x, y).value != '':
x += 1
copied = copyRange(init_x, init_y, x, y+config.src_cols, input_sheet)
input_title = copyRange(config.src_title_ULcorner[0], config.src_title_ULcorner[1], config.src_title_ULcorner[0]+1, config.src_title_ULcorner[1]+config.src_cols, input_sheet)[0]
copied, input_title = plugin_date.add_date_col(input_sheet.cell(1,1).value, copied, input_title) # dirty: generate date col.
copied = plugin_remove_space.work(copied)
all_copied_data += enlarge_2darray_by_title(input_title, output_title, copied)
# silly error report
if list(filter(lambda ls: None in ls, copied)) != []:
# contains None
nt_err_msg += 'Found `None` in file ' + fname + '\r\n'
# iterate over files
sorted_flist = list(flist)
sorted_flist.sort()
for fname in sorted_flist:
process_one_src(fname)
logging.info(all_copied_data)
if len(all_copied_data) > 0:
output_x, output_y = config.dst_ULcorner # starts from 1
pasteRange(output_x, output_y, output_x + len(all_copied_data), output_y + len(all_copied_data[0]), output_xls_sheet, all_copied_data)
delete_rows_below(output_xls_sheet, config.dst_ULcorner[0] + len(all_copied_data))
output_xls.save(config.dst_filename)
logging.basicConfig(format='[%(asctime)s] %(message)s', level=logging.INFO)
nt_err_msg = ''
def daemon_main(argv):
logging.info('Daemon running...')
prev_flist = set()
while True:
flist = get_flist(config.src_dir_path)
if prev_flist != flist:
logging.info('Detected file change. Re-calculating...')
process_all(flist)
prev_flist = flist
time.sleep(config.daemon_loop_interval)
def main(argv):
process_all(get_flist(config.src_dir_path))
if os.name == 'nt':
os.startfile(config.dst_filename)
if nt_err_msg != '':
tmpName = '1.宝牧生产计划汇总缺项.txt'
with open(tmpName, 'w+') as tf:
tf.write(nt_err_msg)
os.startfile(tmpName)
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/xls-copy-paste/plugin_date.py 0000664 0000000 0000000 00000001346 13625463046 0027230 0 ustar 00root root 0000000 0000000 import datetime
OLE_TIME_ZERO = datetime.datetime(1899, 12, 30, 0, 0, 0)
def parse_ole(ole):
""" Input: ole - float. Gives ole time, the number of DAYS since midnight 12/30/1899
Output: float - epoch time
"""
return OLE_TIME_ZERO + datetime.timedelta(days=ole)
def add_date_col(date_cell_val, copied, input_title):
res = []
try:
curr_date = parse_ole(date_cell_val)
except:
print('[ERROR] Adding date column: `{}` is not a valid date stamp. Should be an int from epoch.'.format(date_cell_val))
return copied, input_title
for line in copied:
res.append([curr_date.year, curr_date.month, curr_date.day] + line)
return res, (['年','月','日'] + input_title)
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/xls-copy-paste/plugin_remove_space.py 0000664 0000000 0000000 00000000323 13625463046 0030755 0 ustar 00root root 0000000 0000000 def _conv(ele):
if type(ele) == str:
return ele.replace(' ', '')
return ele
def work(copied):
res = []
for line in copied:
res += [[_conv(ele) for ele in line]]
return res
product-uniqer-8fa1dd2c38bd00c00acc9463744942e84a2c52f2/xlsx_conv.py 0000664 0000000 0000000 00000001316 13625463046 0024065 0 ustar 00root root 0000000 0000000 import xlrd
import csv, io
def xlsx2csv(xlsxPath, sheetIndex, outputFd):
wb = xlrd.open_workbook(xlsxPath)
sh = wb.sheet_by_index(sheetIndex)
wr = csv.writer(outputFd, quoting=csv.QUOTE_NONNUMERIC)
for rownum in range(sh.nrows):
wr.writerow(sh.row_values(rownum))
def read_as_csv(fname):
is_xlsx = lambda fname: fname.endswith('.xlsm') or fname.endswith('.xlsx') or fname.endswith('.xls') or fname.endswith('.XLSM') or fname.endswith('.XLSX') or fname.endswith('.XLS')
# read xlsx or csv
if is_xlsx(fname):
buf = io.StringIO()
xlsx2csv(fname, 0, buf)
return buf.getvalue()
else:
with open(fname, mode='r') as fd:
return fd.read()