Compare commits

..
3 Commits
Author SHA1 Message Date
saturn afd4eec6e1 Добавлена картинка с шефом 2024-10-22 17:57:51 +03:00
saturn 5e3c94f348 test 2024-10-22 17:55:25 +03:00
saturn 474f8d38ce test 2024-10-22 12:03:50 +03:00
20 changed files with 16336 additions and 473 deletions
-3
View File
@@ -1,3 +0,0 @@
__pycache__/
build/
dist/
Submodule
+1
Submodule 1C_Bases added at 0aa3007c5e
+203 -467
View File
@@ -1,12 +1,10 @@
import os
import re
import tkinter as tk
from tkinter import messagebox, filedialog
from tkinter import messagebox
import pyodbc
import uuid
import sys
_BANNER = ("""
print("""
....:::::::::
@@ -58,524 +56,262 @@ _BANNER = ("""
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%@@@@%%%%%%%#%%%%%%%##%%%%%%%%%%%%%%%%%@@@@@@%%%%##**
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%@@@@%%@@@@@@@%%%%%%##%%%%%%%###%%%%%%%%%%%%%%%%%@@%%%%%%%%##*+
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%@@@@@@@@%%%%@@@@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%###%%*#
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%@@@@@@%@@@%@@@@@@@%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%@@@@@@%@@@%@@@@@@@%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%/
""")
# В оконном режиме (сборка без консоли) sys.stdout может быть None — не роняем старт
if getattr(sys, "stdout", None):
try:
print(_BANNER)
except Exception:
pass
class RemoteFolderSelector(tk.Tk):
def __init__(self):
super().__init__()
self.title("Добавление баз 1С пользователям")
self.geometry("760x780")
self.minsize(700, 640)
# --- Состояние ---
self.ip_address = None # None/"" => локальный ПК, иначе IP удалённого ПК
self.active_user = None # пользователь, чьи базы показаны в панели "Подключённые базы"
self.user_vars = {} # имя пользователя -> BooleanVar (галочка)
self.db_vars = {} # имя базы из SQL -> BooleanVar (галочка)
self.conn_vars = {} # имя подключённой базы активного пользователя -> BooleanVar
# Компоновка окна: две колонки сверху, широкая кнопка "Добавить" снизу
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(1, weight=1)
self.grid_rowconfigure(0, weight=1)
self.title("Remote Folder and SQL Database Selector")
self.geometry("500x600")
# Создадим фреймы для лучшей компоновки элементов
self.frame_left = tk.Frame(self)
self.frame_left.grid(row=0, column=0, padx=10, pady=10, sticky="nsew")
self.frame_right = tk.Frame(self)
self.frame_right.grid(row=0, column=1, padx=10, pady=10, sticky="nsew")
self._build_left_panel()
self._build_right_panel()
# Сделаем окна масштабируемыми
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(1, weight=1)
self.grid_rowconfigure(0, weight=1)
# Большая кнопка добавления снизу, на всю ширину окна
self.add_button = tk.Button(
self, text="Добавить отмеченные базы отмеченным пользователям",
font=("Segoe UI", 11, "bold"), command=self.add_database_to_ibases
)
self.add_button.grid(row=1, column=0, columnspan=2, padx=10, pady=(0, 12), sticky="ew")
# Переменные для выбора пользователя и базы данных
self.selected_user = None
self.base_name = None
self.server_name = None
self.ip_address = None
# По умолчанию грузим пользователей локального ПК
self.load_users()
# Поле ввода IP-адреса
self.ip_label = tk.Label(self.frame_left, text="Enter IP (optional):")
self.ip_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")
# ------------------------------------------------------------------ UI
self.ip_entry = tk.Entry(self.frame_left, width=30)
self.ip_entry.grid(row=1, column=0, padx=5, pady=5, sticky="w")
def _build_left_panel(self):
f = self.frame_left
f.grid_columnconfigure(0, weight=1)
tk.Label(f, text="IP-адрес (необязательно):").grid(row=0, column=0, padx=5, pady=(5, 0), sticky="w")
self.ip_entry = tk.Entry(f)
self.ip_entry.grid(row=1, column=0, padx=5, pady=(0, 5), sticky="ew")
tk.Button(f, text="Загрузить пользователей", command=self.load_users)\
.grid(row=2, column=0, padx=5, pady=5, sticky="ew")
# Поиск по пользователям
tk.Label(f, text="Поиск пользователей:").grid(row=3, column=0, padx=5, pady=(5, 0), sticky="w")
self.user_search_var = tk.StringVar()
self.user_search_var.trace_add("write", lambda *a: self._render_checklist(
self.user_inner, self.user_vars, self.user_search_var.get(), self.on_user_click))
tk.Entry(f, textvariable=self.user_search_var)\
.grid(row=4, column=0, padx=5, pady=(0, 5), sticky="ew")
# Отметить все / снять все (с учётом фильтра)
bar = tk.Frame(f)
bar.grid(row=5, column=0, padx=5, pady=(0, 3), sticky="w")
tk.Button(bar, text="Отметить все",
command=lambda: self._set_all(self.user_vars, self.user_search_var.get(), True))\
.pack(side="left", padx=(0, 4))
tk.Button(bar, text="Снять все",
command=lambda: self._set_all(self.user_vars, self.user_search_var.get(), False))\
.pack(side="left")
self.connect_button = tk.Button(self.frame_left, text="Load Users", command=self.load_users)
self.connect_button.grid(row=2, column=0, padx=5, pady=5)
# Список пользователей
self.user_container, self.user_inner = self._create_scrollable_checklist(f, height=150)
self.user_container.grid(row=6, column=0, padx=5, pady=5, sticky="nsew")
f.grid_rowconfigure(6, weight=1)
self.folder_listbox = tk.Listbox(self.frame_left, width=30, height=10)
self.folder_listbox.grid(row=3, column=0, padx=5, pady=5)
self.folder_listbox.bind("<Double-Button-1>", self.select_user)
# Панель подключённых баз активного пользователя
self.conn_label = tk.Label(f, text="Подключённые базы: (выберите пользователя)")
self.conn_label.grid(row=7, column=0, padx=5, pady=(8, 0), sticky="w")
# Поля для ввода данных SQL
self.server_label = tk.Label(self.frame_right, text="SQL Server:")
self.server_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")
bar2 = tk.Frame(f)
bar2.grid(row=8, column=0, padx=5, pady=(0, 3), sticky="w")
tk.Button(bar2, text="Отметить все",
command=lambda: self._set_all(self.conn_vars, "", True)).pack(side="left", padx=(0, 4))
tk.Button(bar2, text="Снять все",
command=lambda: self._set_all(self.conn_vars, "", False)).pack(side="left")
self.conn_container, self.conn_inner = self._create_scrollable_checklist(f, height=150)
self.conn_container.grid(row=9, column=0, padx=5, pady=5, sticky="nsew")
f.grid_rowconfigure(9, weight=1)
tk.Button(f, text="Удалить отмеченные базы у пользователя", command=self.delete_connected_bases)\
.grid(row=10, column=0, padx=5, pady=5, sticky="ew")
# Опция дублирования в ZIP (roaming) профиль
self.zip_enabled = tk.BooleanVar(value=False)
tk.Checkbutton(f, text="Дублировать изменения в ZIP-профиль пользователя",
variable=self.zip_enabled, command=self._toggle_zip)\
.grid(row=11, column=0, padx=5, pady=(8, 0), sticky="w")
zf = tk.Frame(f)
zf.grid(row=12, column=0, padx=5, pady=(0, 5), sticky="ew")
zf.grid_columnconfigure(0, weight=1)
self.zip_path_var = tk.StringVar(value=r"Z:\ZIP_User_Profiles")
self.zip_path_entry = tk.Entry(zf, textvariable=self.zip_path_var, state="disabled")
self.zip_path_entry.grid(row=0, column=0, sticky="ew", padx=(0, 4))
self.zip_browse_btn = tk.Button(zf, text="Обзор...", state="disabled", command=self._browse_zip)
self.zip_browse_btn.grid(row=0, column=1)
def _build_right_panel(self):
f = self.frame_right
f.grid_columnconfigure(0, weight=1)
tk.Label(f, text="SQL-сервер:").grid(row=0, column=0, padx=5, pady=(5, 0), sticky="w")
self.server_entry = tk.Entry(f)
self.server_entry.grid(row=1, column=0, padx=5, pady=(0, 5), sticky="ew")
self.server_entry = tk.Entry(self.frame_right, width=30)
self.server_entry.grid(row=1, column=0, padx=5, pady=5, sticky="w")
self.server_entry.insert(0, "SERVERSQL")
tk.Label(f, text="Логин SQL:").grid(row=2, column=0, padx=5, pady=(5, 0), sticky="w")
self.login_entry = tk.Entry(f)
self.login_entry.grid(row=3, column=0, padx=5, pady=(0, 5), sticky="ew")
self.login_label = tk.Label(self.frame_right, text="SQL Login:")
self.login_label.grid(row=2, column=0, padx=5, pady=5, sticky="w")
self.login_entry = tk.Entry(self.frame_right, width=30)
self.login_entry.grid(row=3, column=0, padx=5, pady=5, sticky="w")
self.login_entry.insert(0, "sa")
tk.Label(f, text="Пароль SQL:").grid(row=4, column=0, padx=5, pady=(5, 0), sticky="w")
self.password_entry = tk.Entry(f, show="*")
self.password_entry.grid(row=5, column=0, padx=5, pady=(0, 5), sticky="ew")
self.password_label = tk.Label(self.frame_right, text="SQL Password:")
self.password_label.grid(row=4, column=0, padx=5, pady=5, sticky="w")
tk.Button(f, text="Загрузить базы", command=self.load_databases)\
.grid(row=6, column=0, padx=5, pady=5, sticky="ew")
self.password_entry = tk.Entry(self.frame_right, show="*", width=30)
self.password_entry.grid(row=5, column=0, padx=5, pady=5, sticky="w")
# Поиск по базам
tk.Label(f, text="Поиск баз:").grid(row=7, column=0, padx=5, pady=(5, 0), sticky="w")
self.db_search_var = tk.StringVar()
self.db_search_var.trace_add("write", lambda *a: self._render_checklist(
self.db_inner, self.db_vars, self.db_search_var.get()))
tk.Entry(f, textvariable=self.db_search_var)\
.grid(row=8, column=0, padx=5, pady=(0, 5), sticky="ew")
self.sql_button = tk.Button(self.frame_right, text="Load Databases", command=self.load_databases)
self.sql_button.grid(row=6, column=0, padx=5, pady=5)
bar = tk.Frame(f)
bar.grid(row=9, column=0, padx=5, pady=(0, 3), sticky="w")
tk.Button(bar, text="Отметить все",
command=lambda: self._set_all(self.db_vars, self.db_search_var.get(), True))\
.pack(side="left", padx=(0, 4))
tk.Button(bar, text="Снять все",
command=lambda: self._set_all(self.db_vars, self.db_search_var.get(), False))\
.pack(side="left")
# Список баз данных
self.db_listbox = tk.Listbox(self.frame_right, width=30, height=10)
self.db_listbox.grid(row=7, column=0, padx=5, pady=5)
self.db_listbox.bind("<Double-Button-1>", self.select_database)
self.db_container, self.db_inner = self._create_scrollable_checklist(f, height=380)
self.db_container.grid(row=10, column=0, padx=5, pady=5, sticky="nsew")
f.grid_rowconfigure(10, weight=1)
# Кнопка добавления базы
self.add_button = tk.Button(self.frame_left, text="Add to ibases.v8i", command=self.add_database_to_ibases)
self.add_button.grid(row=4, column=0, padx=5, pady=5)
def _create_scrollable_checklist(self, parent, width=220, height=180):
"""Прокручиваемая область для чекбоксов. Возвращает (container, inner)."""
container = tk.Frame(parent, borderwidth=1, relief="sunken")
canvas = tk.Canvas(container, width=width, height=height, highlightthickness=0)
scrollbar = tk.Scrollbar(container, orient="vertical", command=canvas.yview)
inner = tk.Frame(canvas)
inner.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
canvas.create_window((0, 0), window=inner, anchor="nw")
canvas.configure(yscrollcommand=scrollbar.set)
canvas.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")
# Список уже подключенных баз данных
self.connected_bases_label = tk.Label(self.frame_left, text="Connected Bases:")
self.connected_bases_label.grid(row=5, column=0, padx=5, pady=5, sticky="w")
def _on_mousewheel(event):
canvas.yview_scroll(int(-event.delta / 120), "units")
self.connected_bases_listbox = tk.Listbox(self.frame_left, width=30, height=10)
self.connected_bases_listbox.grid(row=6, column=0, padx=5, pady=5)
canvas.bind("<Enter>", lambda e: canvas.bind_all("<MouseWheel>", _on_mousewheel))
canvas.bind("<Leave>", lambda e: canvas.unbind_all("<MouseWheel>"))
return container, inner
def _load_items(self, vars_dict, items):
"""Создаём свежий набор BooleanVar по списку items (галочки сбрасываются)."""
vars_dict.clear()
for item in items:
vars_dict[item] = tk.BooleanVar(value=False)
def _render_checklist(self, inner, vars_dict, filter_text="", on_click=None):
"""Рисуем чекбоксы, показывая только элементы, подходящие под фильтр.
Переменные (галочки) сохраняются между перерисовками — состояние не теряется."""
for child in inner.winfo_children():
child.destroy()
ft = (filter_text or "").lower()
for name, var in vars_dict.items():
if ft and ft not in name.lower():
continue
cmd = (lambda n=name: on_click(n)) if on_click else None
tk.Checkbutton(inner, text=name, variable=var, anchor="w", command=cmd)\
.pack(fill="x", anchor="w")
# После перерисовки (например, при вводе в поиск) возвращаем прокрутку наверх,
# иначе список остаётся проскроллен вниз и результат поиска не виден.
inner.master.yview_moveto(0)
def _set_all(self, vars_dict, filter_text, value):
"""Отмечаем/снимаем все чекбоксы, попадающие под текущий фильтр."""
ft = (filter_text or "").lower()
for name, var in vars_dict.items():
if ft and ft not in name.lower():
continue
var.set(value)
def _get_checked(self, vars_dict):
return [name for name, var in vars_dict.items() if var.get()]
def _toggle_zip(self):
state = "normal" if self.zip_enabled.get() else "disabled"
self.zip_path_entry.config(state=state)
self.zip_browse_btn.config(state=state)
def _browse_zip(self):
path = filedialog.askdirectory(title="Каталог с ZIP-профилями пользователей")
if path:
self.zip_path_var.set(os.path.normpath(path))
# -------------------------------------------------------------- Загрузка
# Загрузка пользователей с локального компьютера по умолчанию
self.load_users()
def load_users(self):
"""Загружаем список пользователей с локального ПК или с удалённого по IP."""
self.ip_address = self.ip_entry.get().strip()
if not self.ip_address:
base = r"C:\Users"
"""Загружаем пользователей с указанного IP-адреса или локального ПК."""
self.ip_address = self.ip_entry.get()
if not self.ip_address: # Если IP не указан, используем локальный ПК
local_path = r"C:\Users"
self.load_local_users(local_path)
else:
base = f"\\\\{self.ip_address}\\C$\\Users"
try:
# Используем указанный IP для подключения к удалённому ПК
remote_path = f"\\\\{self.ip_address}\\C$\\Users"
self.load_remote_users(remote_path)
except Exception as e:
messagebox.showerror("Error", f"Could not load users: {str(e)}")
def load_local_users(self, path):
"""Загружаем список пользователей с локального ПК."""
try:
folders = [f for f in os.listdir(base) if os.path.isdir(os.path.join(base, f))]
folders = os.listdir(path)
self.folder_listbox.delete(0, tk.END)
for folder in folders:
if os.path.isdir(os.path.join(path, folder)):
self.folder_listbox.insert(tk.END, folder)
except Exception as e:
messagebox.showerror("Ошибка", f"Не удалось загрузить пользователей:\n{e}")
messagebox.showerror("Error", f"Could not load local users: {str(e)}")
def load_remote_users(self, remote_path):
"""Загружаем список пользователей с удалённого ПК."""
try:
folders = os.listdir(remote_path)
self.folder_listbox.delete(0, tk.END)
for folder in folders:
if os.path.isdir(os.path.join(remote_path, folder)):
self.folder_listbox.insert(tk.END, folder)
except Exception as e:
messagebox.showerror("Error", f"Could not load remote users: {str(e)}")
def select_user(self, event):
"""Обработчик двойного клика для выбора пользователя."""
selected_index = self.folder_listbox.curselection()
if selected_index:
self.selected_user = self.folder_listbox.get(selected_index)
messagebox.showinfo("User Selected", f"Selected User: {self.selected_user}")
self.load_connected_bases() # Загружаем базы для выбранного пользователя
def load_connected_bases(self):
"""Загружаем базы данных из файла ibases.v8i для выбранного пользователя."""
if not self.selected_user:
return
self._load_items(self.user_vars, folders)
self._render_checklist(self.user_inner, self.user_vars, self.user_search_var.get(), self.on_user_click)
try:
# Определяем путь к файлу ibases.v8i
if not self.ip_address:
base_path = f"C:\\Users\\{self.selected_user}\\AppData\\Roaming\\1C\\1CEStart"
else:
base_path = f"\\\\{self.ip_address}\\C$\\Users\\{self.selected_user}\\AppData\\Roaming\\1C\\1CEStart"
# Сбрасываем панель подключённых баз — она относилась к прежнему источнику
self.active_user = None
self.conn_vars.clear()
self._render_checklist(self.conn_inner, self.conn_vars, "")
self.conn_label.config(text="Подключённые базы: (выберите пользователя)")
ibases_path = os.path.join(base_path, "ibases.v8i")
# Проверяем, существует ли файл
if os.path.exists(ibases_path):
with open(ibases_path, "r", encoding="utf-8") as f:
lines = f.readlines()
bases = []
current_base = None
for line in lines:
line = line.strip()
if line.startswith("[") and line.endswith("]"):
if current_base is not None:
bases.append(current_base)
current_base = line[1:-1] # Убираем квадратные скобки
elif current_base is not None and line.startswith("Connect="):
# Здесь можно добавлять другие параметры, если нужно
pass
# Добавляем последнюю базу
if current_base is not None:
bases.append(current_base)
# Сортируем базы в алфавитном порядке
bases.sort()
self.connected_bases_listbox.delete(0, tk.END)
for base in bases:
self.connected_bases_listbox.insert(tk.END, base)
else:
messagebox.showinfo("Info", f"No ibases.v8i file found for user: {self.selected_user}")
except Exception as e:
messagebox.showerror("Error", f"Could not load connected bases: {str(e)}")
def load_databases(self):
"""Подключаемся к SQL-серверу и загружаем список баз."""
server = self.server_entry.get().strip()
login = self.login_entry.get()
password = self.password_entry.get()
"""Подключаемся к SQL серверу и загружаем список баз данных."""
self.server_name = self.server_entry.get()
self.login = self.login_entry.get()
self.password = self.password_entry.get()
try:
connection_string = f"DRIVER={{SQL Server}};SERVER={server};UID={login};PWD={password};"
connection = pyodbc.connect(connection_string)
cursor = connection.cursor()
conn_str = f'DRIVER={{SQL Server}};SERVER={self.server_name};UID={self.login};PWD={self.password};'
conn = pyodbc.connect(conn_str)
cursor = conn.cursor()
cursor.execute("SELECT name FROM sys.databases")
databases = cursor.fetchall()
cursor.close()
connection.close()
self.db_listbox.delete(0, tk.END)
for db in databases:
self.db_listbox.insert(tk.END, db[0]) # db[0] содержит имя базы данных
conn.close()
except Exception as e:
messagebox.showerror("Ошибка", f"Не удалось подключиться к SQL-серверу:\n{e}")
return
messagebox.showerror("Error", f"Could not load databases: {str(e)}")
# Служебные базы SQL Server скрываем — это не базы 1С
system_dbs = {"master", "tempdb", "model", "msdb"}
names = [db[0] for db in databases if db[0].lower() not in system_dbs]
self._load_items(self.db_vars, names)
self._render_checklist(self.db_inner, self.db_vars, self.db_search_var.get())
def on_user_click(self, user):
"""Клик по пользователю — делаем его активным и показываем его подключённые базы."""
self.load_connected_bases(user)
def load_connected_bases(self, user):
"""Читаем ibases.v8i пользователя и показываем список его баз в панели."""
self.active_user = user
self.ip_address = self.ip_entry.get().strip()
path = self.get_ibases_path(user)
text = self._read_ibases(path)
_, sections = self._parse_ibases(text)
names = [name for name, _ in sections]
self._load_items(self.conn_vars, names)
self._render_checklist(self.conn_inner, self.conn_vars, "")
suffix = "" if names else " (баз нет)"
self.conn_label.config(text=f"Подключённые базы: {user}{suffix}")
# --------------------------------------------------------------- Пути
def get_ibases_path(self, user):
"""Путь к ibases.v8i пользователя (локально либо по IP)."""
if not self.ip_address:
base_path = f"C:\\Users\\{user}\\AppData\\Roaming\\1C\\1CEStart"
else:
base_path = f"\\\\{self.ip_address}\\C$\\Users\\{user}\\AppData\\Roaming\\1C\\1CEStart"
return os.path.join(base_path, "ibases.v8i")
def get_zip_ibases_path(self, user):
"""Путь к ibases.v8i внутри ZIP-профиля пользователя.
Папку профиля ищем автопоиском: <user> либо <user>.* (например <user>.V6).
Возвращаем None, если корень недоступен или профиль не найден."""
root = self.zip_path_var.get().strip()
if not root or not os.path.isdir(root):
return None
u = user.lower()
candidates = []
try:
for name in os.listdir(root):
if not os.path.isdir(os.path.join(root, name)):
continue
low = name.lower()
if low == u or low.startswith(u + "."):
candidates.append(name)
except Exception:
return None
if not candidates:
return None
# Приоритет: точное <user>.V6, затем любой суффикс .*, затем совпадение без суффикса
def score(n):
low = n.lower()
if low == u + ".v6":
return 0
if "." in low:
return 1
return 2
candidates.sort(key=score)
chosen = candidates[0]
return os.path.join(root, chosen, "AppData", "Roaming", "1C", "1CEStart", "ibases.v8i")
# ------------------------------------------------------- Чтение/запись v8i
def _read_ibases(self, path):
"""Читаем ibases.v8i, устойчиво к кодировке (UTF-8 с BOM / без / cp1251)."""
if not os.path.exists(path):
return ""
for enc in ("utf-8-sig", "cp1251"):
try:
with open(path, "r", encoding=enc) as f:
return f.read()
except UnicodeDecodeError:
continue
with open(path, "r", encoding="utf-8", errors="ignore") as f:
return f.read()
def _parse_ibases(self, text):
"""Разбираем содержимое на (преамбула, [(имя_базы, блок_текста), ...]).
Секция начинается со строки вида [ИмяБазы]."""
header_re = re.compile(r"^\s*\[(.+?)\]\s*$")
preamble = []
sections = [] # список [имя, [строки]]
current = None
for line in text.splitlines(keepends=True):
m = header_re.match(line)
if m:
current = [m.group(1), [line]]
sections.append(current)
elif current is None:
preamble.append(line)
else:
current[1].append(line)
return "".join(preamble), [(name, "".join(ls)) for name, ls in sections]
def build_base_entry(self, base, server):
"""Формируем запись одной базы для ibases.v8i."""
return (
f"\n[{base}]\n"
f'Connect=Srvr="{server}";Ref="{base}";\n'
f"ID={uuid.uuid4()}\n"
"OrderInList=255\n"
"Folder=/\n"
"OrderInTree=16640\n"
"External=0\n"
"ClientConnectionSpeed=Normal\n"
"App=Auto\n"
"WA=1\n"
"Version=8.3\n"
"DefaultApp=ThickClient\n"
"DisableLocalSpeechToText=0\n"
)
def _add_entries_to_file(self, ibases_path, bases, server):
"""Добавляем базы в один файл ibases.v8i (с фильтром дублей).
Возвращаем (добавлено, пропущено)."""
base_dir = os.path.dirname(ibases_path)
if not os.path.exists(base_dir):
os.makedirs(base_dir)
existing = self._read_ibases(ibases_path)
entries = []
added = skipped = 0
for base in bases:
connect_line = f'Connect=Srvr="{server}";Ref="{base}";'
if connect_line in existing or any(connect_line in e for e in entries):
skipped += 1
continue
entries.append(self.build_base_entry(base, server))
added += 1
if entries:
with open(ibases_path, "a", encoding="utf-8") as f:
f.write("".join(entries))
return added, skipped
def _delete_entries_from_file(self, ibases_path, base_names):
"""Удаляем указанные базы из одного файла ibases.v8i. Возвращаем число удалённых."""
if not os.path.exists(ibases_path):
return 0
text = self._read_ibases(ibases_path)
preamble, sections = self._parse_ibases(text)
target = {b.lower() for b in base_names}
kept = [blk for (name, blk) in sections if name.lower() not in target]
removed = len(sections) - len(kept)
if removed:
with open(ibases_path, "w", encoding="utf-8") as f:
f.write(preamble + "".join(kept))
return removed
# ----------------------------------------------------------- Действия
def select_database(self, event):
"""Обработчик двойного клика для выбора базы данных."""
selected_index = self.db_listbox.curselection()
if selected_index:
self.base_name = self.db_listbox.get(selected_index)
messagebox.showinfo("Database Selected", f"Selected Database: {self.base_name}")
def add_database_to_ibases(self):
"""Добавляем отмеченные базы всем отмеченным пользователям (+ ZIP по галочке)."""
self.ip_address = self.ip_entry.get().strip()
users = self._get_checked(self.user_vars)
bases = self._get_checked(self.db_vars)
server = self.server_entry.get().strip()
if not users:
messagebox.showerror("Ошибка", "Не отмечен ни один пользователь!")
"""Добавляем выбранную базу в файл ibases.v8i."""
if not self.selected_user or not self.base_name or not self.server_name:
messagebox.showwarning("Warning", "Please select a user, database, and SQL server first.")
return
if not bases:
messagebox.showerror("Ошибка", "Не отмечена ни одна база!")
return
if not server:
messagebox.showerror("Ошибка", "Не указан SQL-сервер!")
return
use_zip = self.zip_enabled.get()
added = skipped = zadded = zskipped = 0
errors = []
for user in users:
try:
a, s = self._add_entries_to_file(self.get_ibases_path(user), bases, server)
added += a
skipped += s
except Exception as e:
errors.append(f"{user}: {e}")
if use_zip:
zp = self.get_zip_ibases_path(user)
if zp is None:
errors.append(f"{user}: ZIP-профиль не найден")
else:
try:
a, s = self._add_entries_to_file(zp, bases, server)
zadded += a
zskipped += s
except Exception as e:
errors.append(f"{user} (ZIP): {e}")
# Обновим панель подключённых баз, если активный пользователь среди затронутых
if self.active_user in users:
self.load_connected_bases(self.active_user)
summary = (
f"Пользователей: {len(users)}, баз отмечено: {len(bases)}\n"
f"Локально — добавлено: {added}, пропущено (уже есть): {skipped}"
)
if use_zip:
summary += f"\nZIP-профили — добавлено: {zadded}, пропущено: {zskipped}"
self._report(summary, errors)
def delete_connected_bases(self):
"""Удаляем отмеченные подключённые базы у активного пользователя (+ ZIP по галочке)."""
user = self.active_user
if not user:
messagebox.showerror("Ошибка", "Сначала выберите пользователя слева.")
return
bases = self._get_checked(self.conn_vars)
if not bases:
messagebox.showerror("Ошибка", "Не отмечена ни одна база для удаления!")
return
if not messagebox.askyesno(
"Подтверждение",
f"Удалить {len(bases)} баз(ы) у пользователя «{user}»?\n\n" + "\n".join(bases)
):
return
self.ip_address = self.ip_entry.get().strip()
use_zip = self.zip_enabled.get()
removed_local = removed_zip = 0
errors = []
try:
removed_local = self._delete_entries_from_file(self.get_ibases_path(user), bases)
except Exception as e:
errors.append(f"{user}: {e}")
if use_zip:
zp = self.get_zip_ibases_path(user)
if zp is None:
errors.append(f"{user}: ZIP-профиль не найден")
if not self.ip_address:
base_path = f"C:\\Users\\{self.selected_user}\\AppData\\Roaming\\1C\\1CEStart"
else:
try:
removed_zip = self._delete_entries_from_file(zp, bases)
except Exception as e:
errors.append(f"{user} (ZIP): {e}")
base_path = f"\\\\{self.ip_address}\\C$\\Users\\{self.selected_user}\\AppData\\Roaming\\1C\\1CEStart"
self.load_connected_bases(user)
ibases_path = os.path.join(base_path, "ibases.v8i")
summary = f"Пользователь: {user}\nУдалено локально: {removed_local}"
if use_zip:
summary += f"\nУдалено в ZIP-профиле: {removed_zip}"
self._report(summary, errors)
# Сначала читаем текущее содержимое файла
lines = []
if os.path.exists(ibases_path):
with open(ibases_path, "r", encoding="utf-8") as f:
lines = f.readlines()
def _report(self, summary, errors):
if errors:
messagebox.showwarning("Готово с ошибками", summary + "\n\nОшибки:\n" + "\n".join(errors))
else:
messagebox.showinfo("Готово", summary)
# Создаём новый GUID для базы данных
base_id = str(uuid.uuid4())
# Создаем новую запись для базы данных без лишних пробелов в начале
new_entry = (
f"[{self.base_name}]\n"
f"Connect=Srvr=\"{self.server_name}\";Ref=\"{self.base_name}\";\n"
f"ID={base_id}\n"
f"OrderInList=511\n"
f"Folder=/\n"
f"OrderInTree=33024\n"
f"External=0\n"
f"ClientConnectionSpeed=Normal\n"
f"App=Auto\n"
f"WA=1\n"
f"Version=8.3\n"
)
# Добавляем новую базу данных
lines.append(new_entry)
# Записываем обратно в файл
with open(ibases_path, "w", encoding="utf-8") as f:
f.writelines(lines)
messagebox.showinfo("Success",
f"Database '{self.base_name}' added to ibases.v8i for user '{self.selected_user}'.")
except Exception as e:
messagebox.showerror("Error", f"Could not add database to ibases.v8i: {str(e)}")
if __name__ == "__main__":
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.
+289
View File
@@ -0,0 +1,289 @@
('C:\\Project\\build\\Main_v3\\PYZ-00.pyz',
[('_compat_pickle',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\_compat_pickle.py',
'PYMODULE'),
('_compression',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\_compression.py',
'PYMODULE'),
('_py_abc',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\_py_abc.py',
'PYMODULE'),
('_pydecimal',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\_pydecimal.py',
'PYMODULE'),
('_strptime',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\_strptime.py',
'PYMODULE'),
('_threading_local',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\_threading_local.py',
'PYMODULE'),
('argparse',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\argparse.py',
'PYMODULE'),
('ast',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\ast.py',
'PYMODULE'),
('base64',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\base64.py',
'PYMODULE'),
('bisect',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\bisect.py',
'PYMODULE'),
('bz2',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\bz2.py',
'PYMODULE'),
('calendar',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\calendar.py',
'PYMODULE'),
('contextlib',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\contextlib.py',
'PYMODULE'),
('contextvars',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\contextvars.py',
'PYMODULE'),
('copy',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\copy.py',
'PYMODULE'),
('csv',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\csv.py',
'PYMODULE'),
('dataclasses',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\dataclasses.py',
'PYMODULE'),
('datetime',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\datetime.py',
'PYMODULE'),
('decimal',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\decimal.py',
'PYMODULE'),
('dis',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\dis.py',
'PYMODULE'),
('email',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\__init__.py',
'PYMODULE'),
('email._encoded_words',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\_encoded_words.py',
'PYMODULE'),
('email._header_value_parser',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\_header_value_parser.py',
'PYMODULE'),
('email._parseaddr',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\_parseaddr.py',
'PYMODULE'),
('email._policybase',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\_policybase.py',
'PYMODULE'),
('email.base64mime',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\base64mime.py',
'PYMODULE'),
('email.charset',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\charset.py',
'PYMODULE'),
('email.contentmanager',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\contentmanager.py',
'PYMODULE'),
('email.encoders',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\encoders.py',
'PYMODULE'),
('email.errors',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\errors.py',
'PYMODULE'),
('email.feedparser',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\feedparser.py',
'PYMODULE'),
('email.generator',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\generator.py',
'PYMODULE'),
('email.header',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\header.py',
'PYMODULE'),
('email.headerregistry',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\headerregistry.py',
'PYMODULE'),
('email.iterators',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\iterators.py',
'PYMODULE'),
('email.message',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\message.py',
'PYMODULE'),
('email.parser',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\parser.py',
'PYMODULE'),
('email.policy',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\policy.py',
'PYMODULE'),
('email.quoprimime',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\quoprimime.py',
'PYMODULE'),
('email.utils',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\email\\utils.py',
'PYMODULE'),
('fnmatch',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\fnmatch.py',
'PYMODULE'),
('fractions',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\fractions.py',
'PYMODULE'),
('getopt',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\getopt.py',
'PYMODULE'),
('gettext',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\gettext.py',
'PYMODULE'),
('gzip',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\gzip.py',
'PYMODULE'),
('hashlib',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\hashlib.py',
'PYMODULE'),
('importlib',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\importlib\\__init__.py',
'PYMODULE'),
('importlib._abc',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\importlib\\_abc.py',
'PYMODULE'),
('importlib._bootstrap',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\importlib\\_bootstrap.py',
'PYMODULE'),
('importlib._bootstrap_external',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\importlib\\_bootstrap_external.py',
'PYMODULE'),
('importlib.abc',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\importlib\\abc.py',
'PYMODULE'),
('importlib.machinery',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\importlib\\machinery.py',
'PYMODULE'),
('importlib.metadata',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\importlib\\metadata\\__init__.py',
'PYMODULE'),
('importlib.metadata._adapters',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\importlib\\metadata\\_adapters.py',
'PYMODULE'),
('importlib.metadata._collections',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\importlib\\metadata\\_collections.py',
'PYMODULE'),
('importlib.metadata._functools',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\importlib\\metadata\\_functools.py',
'PYMODULE'),
('importlib.metadata._itertools',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\importlib\\metadata\\_itertools.py',
'PYMODULE'),
('importlib.metadata._meta',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\importlib\\metadata\\_meta.py',
'PYMODULE'),
('importlib.metadata._text',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\importlib\\metadata\\_text.py',
'PYMODULE'),
('importlib.readers',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\importlib\\readers.py',
'PYMODULE'),
('importlib.util',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\importlib\\util.py',
'PYMODULE'),
('inspect',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\inspect.py',
'PYMODULE'),
('logging',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\logging\\__init__.py',
'PYMODULE'),
('lzma',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\lzma.py',
'PYMODULE'),
('numbers',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\numbers.py',
'PYMODULE'),
('opcode',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\opcode.py',
'PYMODULE'),
('optparse',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\optparse.py',
'PYMODULE'),
('pathlib',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\pathlib.py',
'PYMODULE'),
('pickle',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\pickle.py',
'PYMODULE'),
('pprint',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\pprint.py',
'PYMODULE'),
('py_compile',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\py_compile.py',
'PYMODULE'),
('quopri',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\quopri.py',
'PYMODULE'),
('random',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\random.py',
'PYMODULE'),
('selectors',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\selectors.py',
'PYMODULE'),
('shutil',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\shutil.py',
'PYMODULE'),
('signal',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\signal.py',
'PYMODULE'),
('socket',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\socket.py',
'PYMODULE'),
('statistics',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\statistics.py',
'PYMODULE'),
('string',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\string.py',
'PYMODULE'),
('stringprep',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\stringprep.py',
'PYMODULE'),
('subprocess',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\subprocess.py',
'PYMODULE'),
('tarfile',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\tarfile.py',
'PYMODULE'),
('textwrap',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\textwrap.py',
'PYMODULE'),
('threading',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\threading.py',
'PYMODULE'),
('tkinter',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\tkinter\\__init__.py',
'PYMODULE'),
('tkinter.commondialog',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\tkinter\\commondialog.py',
'PYMODULE'),
('tkinter.constants',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\tkinter\\constants.py',
'PYMODULE'),
('tkinter.messagebox',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\tkinter\\messagebox.py',
'PYMODULE'),
('token',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\token.py',
'PYMODULE'),
('tokenize',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\tokenize.py',
'PYMODULE'),
('tracemalloc',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\tracemalloc.py',
'PYMODULE'),
('typing',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\typing.py',
'PYMODULE'),
('urllib',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\urllib\\__init__.py',
'PYMODULE'),
('urllib.parse',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\urllib\\parse.py',
'PYMODULE'),
('uu',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\uu.py',
'PYMODULE'),
('zipfile',
'C:\\Users\\Saturn\\AppData\\Local\\Programs\\Python\\Python310\\lib\\zipfile.py',
'PYMODULE')])
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+27
View File
@@ -0,0 +1,27 @@
This file lists modules PyInstaller was not able to find. This does not
necessarily mean this module is required for running your program. Python and
Python 3rd-party packages include a lot of conditional or optional modules. For
example the module 'ntpath' only exists on Windows, whereas the module
'posixpath' only exists on Posix systems.
Types if import:
* top-level: imported at the top-level - look at these first
* conditional: imported within an if-statement
* delayed: imported within a function
* optional: imported within a try-except-statement
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
tracking down the missing module yourself. Thanks!
missing module named pep517 - imported by importlib.metadata (delayed)
missing module named 'org.python' - imported by copy (optional)
missing module named org - imported by pickle (optional)
missing module named pwd - imported by posixpath (delayed, conditional), subprocess (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional)
missing module named grp - imported by subprocess (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional)
missing module named posix - imported by os (conditional, optional), shutil (conditional), importlib._bootstrap_external (conditional)
missing module named resource - imported by posix (top-level)
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional)
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional)
missing module named _posixsubprocess - imported by subprocess (optional)
missing module named fcntl - imported by subprocess (optional)
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 KiB

+2 -3
View File
@@ -22,18 +22,17 @@ exe = EXE(
a.binaries,
a.datas,
[],
name='1C_Base_Adder',
name='Main_v3',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['download.ico'],
)