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
+198 -462
View File
@@ -1,12 +1,10 @@
import os import os
import re
import tkinter as tk import tkinter as tk
from tkinter import messagebox, filedialog from tkinter import messagebox
import pyodbc import pyodbc
import uuid 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): class RemoteFolderSelector(tk.Tk):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.title("Добавление баз 1С пользователям") self.title("Remote Folder and SQL Database Selector")
self.geometry("760x780") self.geometry("500x600")
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.frame_left = tk.Frame(self) self.frame_left = tk.Frame(self)
self.frame_left.grid(row=0, column=0, padx=10, pady=10, sticky="nsew") self.frame_left.grid(row=0, column=0, padx=10, pady=10, sticky="nsew")
self.frame_right = tk.Frame(self) self.frame_right = tk.Frame(self)
self.frame_right.grid(row=0, column=1, padx=10, pady=10, sticky="nsew") 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.selected_user = None
self, text="Добавить отмеченные базы отмеченным пользователям", self.base_name = None
font=("Segoe UI", 11, "bold"), command=self.add_database_to_ibases self.server_name = None
) self.ip_address = None
self.add_button.grid(row=1, column=0, columnspan=2, padx=10, pady=(0, 12), sticky="ew")
# По умолчанию грузим пользователей локального ПК # Поле ввода IP-адреса
self.load_users() 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): self.connect_button = tk.Button(self.frame_left, text="Load Users", command=self.load_users)
f = self.frame_left self.connect_button.grid(row=2, column=0, padx=5, pady=5)
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.user_container, self.user_inner = self._create_scrollable_checklist(f, height=150) self.folder_listbox = tk.Listbox(self.frame_left, width=30, height=10)
self.user_container.grid(row=6, column=0, padx=5, pady=5, sticky="nsew") self.folder_listbox.grid(row=3, column=0, padx=5, pady=5)
f.grid_rowconfigure(6, weight=1) self.folder_listbox.bind("<Double-Button-1>", self.select_user)
# Панель подключённых баз активного пользователя # Поля для ввода данных SQL
self.conn_label = tk.Label(f, text="Подключённые базы: (выберите пользователя)") self.server_label = tk.Label(self.frame_right, text="SQL Server:")
self.conn_label.grid(row=7, column=0, padx=5, pady=(8, 0), sticky="w") self.server_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")
bar2 = tk.Frame(f) self.server_entry = tk.Entry(self.frame_right, width=30)
bar2.grid(row=8, column=0, padx=5, pady=(0, 3), sticky="w") self.server_entry.grid(row=1, column=0, padx=5, pady=5, 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.insert(0, "SERVERSQL") 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_label = tk.Label(self.frame_right, text="SQL Login:")
self.login_entry = tk.Entry(f) self.login_label.grid(row=2, column=0, padx=5, pady=5, sticky="w")
self.login_entry.grid(row=3, column=0, padx=5, pady=(0, 5), sticky="ew")
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") 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_label = tk.Label(self.frame_right, text="SQL Password:")
self.password_entry = tk.Entry(f, show="*") self.password_label.grid(row=4, column=0, padx=5, pady=5, sticky="w")
self.password_entry.grid(row=5, column=0, padx=5, pady=(0, 5), sticky="ew")
tk.Button(f, text="Загрузить базы", command=self.load_databases)\ self.password_entry = tk.Entry(self.frame_right, show="*", width=30)
.grid(row=6, column=0, padx=5, pady=5, sticky="ew") self.password_entry.grid(row=5, column=0, padx=5, pady=5, sticky="w")
# Поиск по базам self.sql_button = tk.Button(self.frame_right, text="Load Databases", command=self.load_databases)
tk.Label(f, text="Поиск баз:").grid(row=7, column=0, padx=5, pady=(5, 0), sticky="w") self.sql_button.grid(row=6, column=0, padx=5, pady=5)
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")
bar = tk.Frame(f) # Список баз данных
bar.grid(row=9, column=0, padx=5, pady=(0, 3), sticky="w") self.db_listbox = tk.Listbox(self.frame_right, width=30, height=10)
tk.Button(bar, text="Отметить все", self.db_listbox.grid(row=7, column=0, padx=5, pady=5)
command=lambda: self._set_all(self.db_vars, self.db_search_var.get(), True))\ self.db_listbox.bind("<Double-Button-1>", self.select_database)
.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_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") self.add_button = tk.Button(self.frame_left, text="Add to ibases.v8i", command=self.add_database_to_ibases)
f.grid_rowconfigure(10, weight=1) self.add_button.grid(row=4, column=0, padx=5, pady=5)
def _create_scrollable_checklist(self, parent, width=220, height=180): # Список уже подключенных баз данных
"""Прокручиваемая область для чекбоксов. Возвращает (container, inner).""" self.connected_bases_label = tk.Label(self.frame_left, text="Connected Bases:")
container = tk.Frame(parent, borderwidth=1, relief="sunken") self.connected_bases_label.grid(row=5, column=0, padx=5, pady=5, sticky="w")
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")
def _on_mousewheel(event): self.connected_bases_listbox = tk.Listbox(self.frame_left, width=30, height=10)
canvas.yview_scroll(int(-event.delta / 120), "units") 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>")) self.load_users()
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))
# -------------------------------------------------------------- Загрузка
def load_users(self): def load_users(self):
"""Загружаем список пользователей с локального ПК или с удалённого по IP.""" """Загружаем пользователей с указанного IP-адреса или локального ПК."""
self.ip_address = self.ip_entry.get().strip() self.ip_address = self.ip_entry.get()
if not self.ip_address:
base = r"C:\Users" if not self.ip_address: # Если IP не указан, используем локальный ПК
local_path = r"C:\Users"
self.load_local_users(local_path)
else: else:
base = f"\\\\{self.ip_address}\\C$\\Users"
try: try:
folders = [f for f in os.listdir(base) if os.path.isdir(os.path.join(base, f))] # Используем указанный IP для подключения к удалённому ПК
remote_path = f"\\\\{self.ip_address}\\C$\\Users"
self.load_remote_users(remote_path)
except Exception as e: except Exception as e:
messagebox.showerror("Ошибка", f"Не удалось загрузить пользователей:\n{e}") messagebox.showerror("Error", f"Could not load users: {str(e)}")
def load_local_users(self, path):
"""Загружаем список пользователей с локального ПК."""
try:
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("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 return
self._load_items(self.user_vars, folders) try:
self._render_checklist(self.user_inner, self.user_vars, self.user_search_var.get(), self.on_user_click) # Определяем путь к файлу 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"
# Сбрасываем панель подключённых баз — она относилась к прежнему источнику ibases_path = os.path.join(base_path, "ibases.v8i")
self.active_user = None
self.conn_vars.clear() # Проверяем, существует ли файл
self._render_checklist(self.conn_inner, self.conn_vars, "") if os.path.exists(ibases_path):
self.conn_label.config(text="Подключённые базы: (выберите пользователя)") 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): def load_databases(self):
"""Подключаемся к SQL-серверу и загружаем список баз.""" """Подключаемся к SQL серверу и загружаем список баз данных."""
server = self.server_entry.get().strip() self.server_name = self.server_entry.get()
login = self.login_entry.get() self.login = self.login_entry.get()
password = self.password_entry.get() self.password = self.password_entry.get()
try: try:
connection_string = f"DRIVER={{SQL Server}};SERVER={server};UID={login};PWD={password};" conn_str = f'DRIVER={{SQL Server}};SERVER={self.server_name};UID={self.login};PWD={self.password};'
connection = pyodbc.connect(connection_string) conn = pyodbc.connect(conn_str)
cursor = connection.cursor() cursor = conn.cursor()
cursor.execute("SELECT name FROM sys.databases") cursor.execute("SELECT name FROM sys.databases")
databases = cursor.fetchall() 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: except Exception as e:
messagebox.showerror("Ошибка", f"Не удалось подключиться к SQL-серверу:\n{e}") messagebox.showerror("Error", f"Could not load databases: {str(e)}")
return
# Служебные базы SQL Server скрываем — это не базы 1С def select_database(self, event):
system_dbs = {"master", "tempdb", "model", "msdb"} """Обработчик двойного клика для выбора базы данных."""
names = [db[0] for db in databases if db[0].lower() not in system_dbs] selected_index = self.db_listbox.curselection()
self._load_items(self.db_vars, names) if selected_index:
self._render_checklist(self.db_inner, self.db_vars, self.db_search_var.get()) self.base_name = self.db_listbox.get(selected_index)
messagebox.showinfo("Database Selected", f"Selected Database: {self.base_name}")
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 add_database_to_ibases(self): def add_database_to_ibases(self):
"""Добавляем отмеченные базы всем отмеченным пользователям (+ ZIP по галочке).""" """Добавляем выбранную базу в файл ibases.v8i."""
self.ip_address = self.ip_entry.get().strip() if not self.selected_user or not self.base_name or not self.server_name:
users = self._get_checked(self.user_vars) messagebox.showwarning("Warning", "Please select a user, database, and SQL server first.")
bases = self._get_checked(self.db_vars)
server = self.server_entry.get().strip()
if not users:
messagebox.showerror("Ошибка", "Не отмечен ни один пользователь!")
return
if not bases:
messagebox.showerror("Ошибка", "Не отмечена ни одна база!")
return
if not server:
messagebox.showerror("Ошибка", "Не указан SQL-сервер!")
return return
use_zip = self.zip_enabled.get()
added = skipped = zadded = zskipped = 0
errors = []
for user in users:
try: try:
a, s = self._add_entries_to_file(self.get_ibases_path(user), bases, server) if not self.ip_address:
added += a base_path = f"C:\\Users\\{self.selected_user}\\AppData\\Roaming\\1C\\1CEStart"
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: else:
try: base_path = f"\\\\{self.ip_address}\\C$\\Users\\{self.selected_user}\\AppData\\Roaming\\1C\\1CEStart"
a, s = self._add_entries_to_file(zp, bases, server)
zadded += a
zskipped += s
except Exception as e:
errors.append(f"{user} (ZIP): {e}")
# Обновим панель подключённых баз, если активный пользователь среди затронутых ibases_path = os.path.join(base_path, "ibases.v8i")
if self.active_user in users:
self.load_connected_bases(self.active_user)
summary = ( # Сначала читаем текущее содержимое файла
f"Пользователей: {len(users)}, баз отмечено: {len(bases)}\n" lines = []
f"Локально — добавлено: {added}, пропущено (уже есть): {skipped}" if os.path.exists(ibases_path):
with open(ibases_path, "r", encoding="utf-8") as f:
lines = f.readlines()
# Создаём новый 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"
) )
if use_zip:
summary += f"\nZIP-профили — добавлено: {zadded}, пропущено: {zskipped}"
self._report(summary, errors)
def delete_connected_bases(self): # Добавляем новую базу данных
"""Удаляем отмеченные подключённые базы у активного пользователя (+ ZIP по галочке).""" lines.append(new_entry)
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( # Записываем обратно в файл
"Подтверждение", with open(ibases_path, "w", encoding="utf-8") as f:
f"Удалить {len(bases)} баз(ы) у пользователя «{user}»?\n\n" + "\n".join(bases) f.writelines(lines)
):
return
self.ip_address = self.ip_entry.get().strip() messagebox.showinfo("Success",
use_zip = self.zip_enabled.get() f"Database '{self.base_name}' added to ibases.v8i for user '{self.selected_user}'.")
removed_local = removed_zip = 0
errors = []
try:
removed_local = self._delete_entries_from_file(self.get_ibases_path(user), bases)
except Exception as e: except Exception as e:
errors.append(f"{user}: {e}") messagebox.showerror("Error", f"Could not add database to ibases.v8i: {str(e)}")
if use_zip:
zp = self.get_zip_ibases_path(user)
if zp is None:
errors.append(f"{user}: ZIP-профиль не найден")
else:
try:
removed_zip = self._delete_entries_from_file(zp, bases)
except Exception as e:
errors.append(f"{user} (ZIP): {e}")
self.load_connected_bases(user)
summary = f"Пользователь: {user}\nУдалено локально: {removed_local}"
if use_zip:
summary += f"\nУдалено в ZIP-профиле: {removed_zip}"
self._report(summary, errors)
def _report(self, summary, errors):
if errors:
messagebox.showwarning("Готово с ошибками", summary + "\n\nОшибки:\n" + "\n".join(errors))
else:
messagebox.showinfo("Готово", summary)
if __name__ == "__main__": 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.binaries,
a.datas, a.datas,
[], [],
name='1C_Base_Adder', name='Main_v3',
debug=False, debug=False,
bootloader_ignore_signals=False, bootloader_ignore_signals=False,
strip=False, strip=False,
upx=True, upx=True,
upx_exclude=[], upx_exclude=[],
runtime_tmpdir=None, runtime_tmpdir=None,
console=False, console=True,
disable_windowed_traceback=False, disable_windowed_traceback=False,
argv_emulation=False, argv_emulation=False,
target_arch=None, target_arch=None,
codesign_identity=None, codesign_identity=None,
entitlements_file=None, entitlements_file=None,
icon=['download.ico'],
) )