Compare commits
3
Commits
c3345a94e8
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afd4eec6e1 | ||
|
|
5e3c94f348 | ||
|
|
474f8d38ce |
@@ -1,3 +0,0 @@
|
|||||||
__pycache__/
|
|
||||||
build/
|
|
||||||
dist/
|
|
||||||
Submodule
+1
Submodule 1C_Bases added at 0aa3007c5e
+198
-462
@@ -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.
@@ -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.
@@ -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
Vendored
BIN
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 264 KiB |
@@ -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'],
|
|
||||||
)
|
)
|
||||||
Reference in New Issue
Block a user