Compare commits
25 Commits
5e1cdfb9e5
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 58082ed171 | |||
| f09c365384 | |||
| b204ce38fc | |||
| 1cf4482914 | |||
| b9025fcabe | |||
|
|
fa5c846ebb | ||
| 6bcfc3102b | |||
| 92714bcb51 | |||
|
|
396bf19214 | ||
|
|
37c7a5bd7a | ||
|
|
69e0f7f8b1 | ||
|
|
44771dcd11 | ||
|
|
ca42c8e3c7 | ||
|
|
9f45a02f13 | ||
|
|
6f07bb9cba | ||
|
|
1536f26fee | ||
|
|
e838d25c44 | ||
|
|
8e3893e85c | ||
|
|
f2a2ca7d97 | ||
|
|
8301fc8ef4 | ||
|
|
82949fb9bf | ||
|
|
9bfc40d733 | ||
|
|
e7aac91d51 | ||
|
|
795dd5cac2 | ||
|
|
ba54bbfa75 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1 +1,4 @@
|
||||
label/
|
||||
build/
|
||||
logs/
|
||||
pdf_backup/
|
||||
|
||||
178
BUILD_ON_WINDOWS.md
Normal file
178
BUILD_ON_WINDOWS.md
Normal file
@@ -0,0 +1,178 @@
|
||||
# Building LabelPrinter.exe on Windows
|
||||
|
||||
This guide explains how to build a standalone `LabelPrinter.exe` single-file executable on a Windows machine.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. **Python 3.10, 3.11, 3.12, or 3.13** - Download from https://www.python.org/
|
||||
- ⚠️ **IMPORTANT**: Check "Add Python to PATH" during installation
|
||||
- ⚠️ **Note**: Python 3.14+ may have compatibility issues with Kivy 2.2.1
|
||||
- Verify: Open Command Prompt and type `python --version`
|
||||
|
||||
2. **Git** (optional, for cloning the repository)
|
||||
|
||||
3. **Internet connection** - To download dependencies
|
||||
|
||||
## Quick Start (Using Provided Scripts)
|
||||
|
||||
### Option 1: Batch Script (Recommended for CMD users)
|
||||
|
||||
1. Open **Command Prompt** (cmd.exe)
|
||||
2. Navigate to the project folder:
|
||||
```
|
||||
cd C:\path\to\label_print
|
||||
```
|
||||
3. Run the build script:
|
||||
```
|
||||
build_windows.bat
|
||||
```
|
||||
4. Wait 5-15 minutes for the build to complete
|
||||
5. The executable will be in: `dist\LabelPrinter.exe`
|
||||
|
||||
### Option 2: PowerShell Script
|
||||
|
||||
1. Open **PowerShell** (as Administrator recommended)
|
||||
2. Navigate to the project folder:
|
||||
```
|
||||
cd C:\path\to\label_print
|
||||
```
|
||||
3. Allow script execution (if needed):
|
||||
```
|
||||
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
```
|
||||
4. Run the build script:
|
||||
```
|
||||
.\build_windows.ps1
|
||||
```
|
||||
5. Wait 5-15 minutes for the build to complete
|
||||
6. The executable will be in: `dist\LabelPrinter.exe`
|
||||
|
||||
## Manual Build Steps
|
||||
|
||||
If you prefer to run commands manually:
|
||||
|
||||
### Step 1: Prepare Python Environment
|
||||
|
||||
```bash
|
||||
# Upgrade pip, setuptools, and wheel
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
```
|
||||
|
||||
### Step 2: Install Dependencies
|
||||
|
||||
```bash
|
||||
# Install required Python packages
|
||||
pip install python-barcode pillow reportlab kivy==2.2.1 pyinstaller==6.1.0
|
||||
```
|
||||
|
||||
### Step 3: Build the Executable
|
||||
|
||||
```bash
|
||||
# Create single-file executable
|
||||
pyinstaller label_printer_gui.py ^
|
||||
--onefile ^
|
||||
--windowed ^
|
||||
--name=LabelPrinter ^
|
||||
--distpath=./dist ^
|
||||
--workpath=./build ^
|
||||
--hidden-import=kivy ^
|
||||
--hidden-import=PIL ^
|
||||
--hidden-import=barcode ^
|
||||
--hidden-import=reportlab ^
|
||||
--hidden-import=print_label ^
|
||||
--hidden-import=print_label_pdf ^
|
||||
-y
|
||||
```
|
||||
|
||||
The build process will take 5-15 minutes depending on your PC speed.
|
||||
|
||||
### Step 4: Test the Executable
|
||||
|
||||
```bash
|
||||
# Run the built executable
|
||||
dist\LabelPrinter.exe
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
After successful build, you'll have:
|
||||
|
||||
```
|
||||
dist/
|
||||
└── LabelPrinter.exe ← Single executable file
|
||||
```
|
||||
|
||||
## Distributing the Executable
|
||||
|
||||
You can:
|
||||
1. **Copy `LabelPrinter.exe`** to any Windows PC (no Python needed!)
|
||||
2. **Share via USB** or file transfer
|
||||
3. **Create an installer** using NSIS or InnoSetup (optional)
|
||||
4. **Upload to GitHub Releases** for public distribution
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Error: "Python is not recognized"
|
||||
- Reinstall Python and check "Add Python to PATH"
|
||||
- Restart Command Prompt after reinstalling Python
|
||||
|
||||
### Error: "pip command not found"
|
||||
- Use `python -m pip` instead of `pip`
|
||||
|
||||
### Build takes too long (>30 minutes)
|
||||
- **Normal for first build** - Kivy framework is large
|
||||
- Subsequent builds will be faster due to caching
|
||||
- Close other applications to free up RAM
|
||||
|
||||
### Error: "No module named 'kivy'"
|
||||
- Make sure dependencies installed correctly: `pip install kivy==2.2.1`
|
||||
- Check internet connection
|
||||
|
||||
### Python 3.14 Compatibility Issues
|
||||
If you have Python 3.14 installed and get errors like:
|
||||
- `ModuleNotFoundError: No module named 'kivy'`
|
||||
- `ImportError: DLL load failed`
|
||||
- PyInstaller compatibility errors
|
||||
|
||||
**Solution:**
|
||||
- Install Python 3.11, 3.12, or 3.13 instead
|
||||
- Download from: https://www.python.org/downloads/
|
||||
- Uninstall Python 3.14 first
|
||||
- Then use one of the recommended versions
|
||||
- Make sure all files are in the project folder:
|
||||
- `label_printer_gui.py`
|
||||
- `print_label.py`
|
||||
- `print_label_pdf.py`
|
||||
- Antivirus might be blocking it - check security software
|
||||
|
||||
## Build Time Reference
|
||||
|
||||
- **First build**: 10-15 minutes (downloading dependencies)
|
||||
- **Subsequent builds**: 5-10 minutes (cached dependencies)
|
||||
|
||||
## Advanced Options
|
||||
|
||||
### Reduce Build Time
|
||||
```bash
|
||||
pyinstaller label_printer_gui.py --onefile --windowed --name=LabelPrinter -y
|
||||
```
|
||||
|
||||
### Add Icon to Executable
|
||||
```bash
|
||||
pyinstaller label_printer_gui.py --onefile --windowed --name=LabelPrinter --icon=path\to\icon.ico -y
|
||||
```
|
||||
|
||||
### Faster: Use --onedir (Directory) instead of --onefile
|
||||
```bash
|
||||
pyinstaller label_printer_gui.py --onedir --windowed --name=LabelPrinter -y
|
||||
# Builds in ~3-5 minutes, but creates a folder instead of single file
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
If you encounter issues:
|
||||
1. Check the error message carefully
|
||||
2. Make sure Python 3.10+ is installed
|
||||
3. Verify all dependencies: `pip list`
|
||||
4. Check internet connection
|
||||
5. Try again with a fresh Command Prompt window
|
||||
88
DEPLOYMENT.md
Normal file
88
DEPLOYMENT.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Label Printer - Portable Deployment Guide
|
||||
|
||||
## Deployment Structure
|
||||
|
||||
The app is now **fully self-contained** with SumatraPDF embedded inside:
|
||||
|
||||
```
|
||||
LabelPrinter/
|
||||
├── LabelPrinter.exe # Main application (includes SumatraPDF inside)
|
||||
├── pdf_backup/ # Auto-created: PDF backups
|
||||
└── logs/ # Auto-created: Print logs
|
||||
```
|
||||
|
||||
**No visible folders!** SumatraPDF is bundled inside LabelPrinter.exe and extracted to a temporary location at runtime.
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
### 1. Download SumatraPDF (For Building Only)
|
||||
|
||||
**This step is only needed when building the app.** SumatraPDF will be embedded inside the executable.
|
||||
|
||||
```powershell
|
||||
# PowerShell command to download SumatraPDF
|
||||
powershell -ExecutionPolicy Bypass -File setup_sumatra.ps1
|
||||
```
|
||||
|
||||
This downloads SumatraPDF portable (~5 MB) to the `SumatraPDF` folder.
|
||||
|
||||
### 2. Build the Application
|
||||
|
||||
```powershell
|
||||
.\build_windows.ps1
|
||||
```
|
||||
|
||||
The build script will:
|
||||
- Check for SumatraPDF
|
||||
- Bundle it inside the executable
|
||||
- Create `dist\LabelPrinter.exe` (~80 MB including all dependencies)
|
||||
|
||||
### 3. Deploy
|
||||
|
||||
**Simply copy `LabelPrinter.exe` to any Windows machine!**
|
||||
|
||||
```
|
||||
📁 Deployment (any folder)
|
||||
└── LabelPrinter.exe ← Just this one file!
|
||||
```
|
||||
|
||||
- No installation needed
|
||||
- No additional files or folders
|
||||
- Double-click to run
|
||||
- Works on any Windows 10/11 machine
|
||||
|
||||
## Features
|
||||
|
||||
- ✅ **Single Executable** - Everything bundled in one .exe file (~80 MB)
|
||||
- ✅ **Fully Portable** - No installation needed, no external dependencies
|
||||
- ✅ **Silent Printing** - No PDF viewer windows pop up
|
||||
- ✅ **Network Printers** - Supports printers from print servers (e.g. `\\server\printer`)
|
||||
- ✅ **PDF Backup** - All labels saved to `pdf_backup/` folder
|
||||
- ✅ **Print Logging** - CSV logs in `logs/` folder
|
||||
- ✅ **SumatraPDF Hidden** - Embedded inside, not visible to users
|
||||
|
||||
## Printer Name Display
|
||||
|
||||
Network printer names (e.g. `\\filesibiusb05\ZDesigner_ZQ630`) are automatically shortened to 20 characters in the dropdown for better display. The full printer name is used for actual printing.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Printing Not Working
|
||||
|
||||
1. **Check Printer Connection**: Verify printer is online and accessible
|
||||
2. **Check PDF Backup**: Labels are always saved to `pdf_backup/` folder even if printing fails
|
||||
3. **Check Logs**: View print logs in `logs/` folder for error messages
|
||||
4. **Rebuild App**: If you built the app yourself, ensure `setup_sumatra.ps1` was run first to download SumatraPDF before building
|
||||
|
||||
### Network Printers Not Showing
|
||||
|
||||
- Network printers must be installed/connected on the machine before running the app
|
||||
- For print server printers like `\\filesibiusb05\printer`, ensure the share is accessible
|
||||
- Run as administrator if printer enumeration fails
|
||||
|
||||
## Notes
|
||||
|
||||
- First run may be slower (Kivy initialization)
|
||||
- PDF backups are auto-deleted after 5 days
|
||||
- Log files are auto-deleted after 5 days
|
||||
- Supports Python 3.10-3.13 (Python 3.14+ may have issues with Kivy)
|
||||
@@ -4,9 +4,9 @@
|
||||
a = Analysis(
|
||||
['label_printer_gui.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
binaries=[('SumatraPDF\\SumatraPDF.exe', '.')],
|
||||
datas=[],
|
||||
hiddenimports=['kivy', 'kivy.core.window', 'kivy.core.text', 'kivy.core.image', 'kivy.uix.boxlayout', 'kivy.uix.gridlayout', 'kivy.uix.label', 'kivy.uix.textinput', 'kivy.uix.button', 'kivy.uix.spinner', 'kivy.uix.scrollview', 'kivy.uix.popup', 'kivy.clock', 'kivy.graphics', 'PIL', 'barcode', 'reportlab', 'print_label', 'print_label_pdf'],
|
||||
hiddenimports=['kivy', 'PIL', 'barcode', 'reportlab', 'print_label', 'print_label_pdf'],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
|
||||
BIN
SumatraPDF/SumatraPDF.exe
Normal file
BIN
SumatraPDF/SumatraPDF.exe
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,306 +0,0 @@
|
||||
|
||||
This file lists modules PyInstaller was not able to find. This does not
|
||||
necessarily mean these modules are required for running your program. Both
|
||||
Python's standard library and 3rd-party Python packages often conditionally
|
||||
import optional modules, some of which may be available only on certain
|
||||
platforms.
|
||||
|
||||
Types of 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 'collections.abc' - imported by traceback (top-level), typing (top-level), inspect (top-level), logging (top-level), importlib.resources.readers (top-level), selectors (top-level), tracemalloc (top-level), configparser (top-level), http.client (top-level), _pyrepl.types (top-level), _pyrepl.readline (top-level), asyncio.base_events (top-level), asyncio.coroutines (top-level), PIL.Image (top-level), PIL._typing (top-level), numpy._typing._array_like (top-level), numpy._typing._nested_sequence (conditional), numpy._typing._shape (top-level), numpy._typing._dtype_like (top-level), numpy.lib._function_base_impl (top-level), numpy.lib._npyio_impl (top-level), numpy.random._common (top-level), numpy.random._generator (top-level), numpy.random.bit_generator (top-level), numpy.random.mtrand (top-level), numpy.polynomial._polybase (top-level), xml.etree.ElementTree (top-level), PIL.TiffImagePlugin (top-level), PIL.ImageOps (top-level), PIL.ImagePalette (top-level), PIL.GimpGradientFile (conditional), PIL.ImageFilter (top-level), PIL.ImageQt (conditional), PIL.ImageMath (conditional), PIL.ImageSequence (conditional), PIL.PngImagePlugin (conditional), kivy.uix.filechooser (top-level), PIL.ImageDraw (top-level), PIL._imagingft (top-level), PIL.Jpeg2KImagePlugin (conditional), docutils (conditional), docutils.nodes (conditional), docutils.utils (conditional), docutils.utils._typing (conditional), docutils.frontend (conditional), docutils.parsers.rst.directives (conditional)
|
||||
missing module named _winapi - imported by encodings (delayed, conditional, optional), shutil (conditional), ntpath (optional), subprocess (conditional), sysconfig (delayed), mimetypes (optional), multiprocessing.connection (optional), multiprocessing.spawn (delayed, conditional), multiprocessing.reduction (conditional), multiprocessing.shared_memory (conditional), multiprocessing.heap (conditional), multiprocessing.popen_spawn_win32 (top-level), asyncio.windows_events (top-level), asyncio.windows_utils (top-level)
|
||||
missing module named msvcrt - imported by subprocess (optional), _pyrepl.windows_console (top-level), multiprocessing.spawn (delayed, conditional), multiprocessing.popen_spawn_win32 (top-level), asyncio.windows_events (top-level), asyncio.windows_utils (top-level), getpass (optional)
|
||||
missing module named urllib.pathname2url - imported by urllib (conditional), kivy.core.audio.audio_gstplayer (conditional), kivy.core.video.video_gstplayer (conditional)
|
||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
missing module named winreg - imported by importlib._bootstrap_external (conditional), platform (delayed, optional), mimetypes (optional), urllib.request (delayed, conditional, optional), pygments.formatters.img (optional)
|
||||
missing module named nt - imported by shutil (conditional), importlib._bootstrap_external (conditional), ntpath (optional), _colorize (delayed, conditional, optional), os (delayed, conditional, optional), ctypes (delayed, conditional), _pyrepl.windows_console (delayed, optional)
|
||||
missing module named _scproxy - imported by urllib.request (conditional)
|
||||
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
|
||||
missing module named 'ctypes.macholib' - imported by ctypes.util (conditional)
|
||||
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
|
||||
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named pyimod02_importers - imported by /srv/Label-design/venv/lib/python3.13/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py (delayed)
|
||||
missing module named olefile - imported by PIL.FpxImagePlugin (top-level), PIL.MicImagePlugin (top-level)
|
||||
missing module named _dummy_thread - imported by numpy._core.arrayprint (optional)
|
||||
missing module named 'numpy_distutils.cpuinfo' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||
missing module named 'numpy_distutils.fcompiler' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||
missing module named 'numpy_distutils.command' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||
missing module named numpy_distutils - imported by numpy.f2py.diagnose (delayed, optional)
|
||||
missing module named typing_extensions - imported by numpy.random.bit_generator (top-level), charset_normalizer.legacy (conditional), docutils.utils._typing (conditional)
|
||||
missing module named psutil - imported by numpy.testing._private.utils (delayed, optional)
|
||||
missing module named usercustomize - imported by site (delayed, optional)
|
||||
missing module named apport_python_hook - imported by sitecustomize (optional)
|
||||
missing module named win32pdh - imported by numpy.testing._private.utils (delayed, conditional)
|
||||
missing module named _overlapped - imported by asyncio.windows_events (top-level)
|
||||
missing module named asyncio.DefaultEventLoopPolicy - imported by asyncio (delayed, conditional), asyncio.events (delayed, conditional)
|
||||
missing module named _typeshed - imported by numpy.random.bit_generator (top-level)
|
||||
missing module named numpy.random.RandomState - imported by numpy.random (top-level), numpy.random._generator (top-level)
|
||||
missing module named threadpoolctl - imported by numpy.lib._utils_impl (delayed, optional)
|
||||
missing module named numpy._core.zeros - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.vstack - imported by numpy._core (top-level), numpy.lib._shape_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.void - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.vecmat - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.vecdot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.ushort - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.unsignedinteger - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ulonglong - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ulong - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.uintp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.uintc - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.uint64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.uint32 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.uint16 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.uint - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ubyte - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.trunc - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.true_divide - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.transpose - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._function_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.trace - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.timedelta64 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.tensordot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.tanh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.tan - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.swapaxes - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.sum - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.subtract - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.str_ - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.square - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.sqrt - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.spacing - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.sort - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.sinh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.single - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.signedinteger - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.signbit - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.sign - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.short - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.rint - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.right_shift - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.result_type - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.remainder - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.reciprocal - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.radians - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.rad2deg - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.prod - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.power - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.positive - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.pi - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.outer - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.ones - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.object_ - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.number - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.not_equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.nextafter - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.newaxis - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.negative - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ndarray - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy.lib._utils_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.multiply - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.moveaxis - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.modf - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.mod - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.minimum - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.maximum - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.max - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.matvec - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.matrix_transpose - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.matmul - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.longlong - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.longdouble - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.long - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_xor - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_or - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_not - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_and - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logaddexp2 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logaddexp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.log10 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.log2 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.log1p - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.log - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.linspace - imported by numpy._core (top-level), numpy.lib._index_tricks_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.less_equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.less - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.left_shift - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ldexp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.lcm - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.isscalar - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.isnat - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional)
|
||||
missing module named numpy._core.isnan - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.isfinite - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.intp - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.integer - imported by numpy._core (conditional), numpy (conditional), numpy.fft._helper (top-level)
|
||||
missing module named numpy._core.intc - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.int64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.int32 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.int16 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.int8 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.inf - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.inexact - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.iinfo - imported by numpy._core (top-level), numpy.lib._twodim_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.hypot - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.hstack - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.heaviside - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.half - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.greater_equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.greater - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.gcd - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.frompyfunc - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.frexp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.fmod - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.fmin - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.fmax - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.floor_divide - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.floor - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.floating - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.float_power - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.float32 - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.float16 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.finfo - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.fabs - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.expm1 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.exp2 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.exp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.euler_gamma - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.errstate - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.empty_like - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.empty - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy.fft._helper (top-level)
|
||||
missing module named numpy._core.e - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.double - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.dot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.divmod - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.divide - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.diagonal - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.degrees - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.deg2rad - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.datetime64 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.csingle - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.cross - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.count_nonzero - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.cosh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.cos - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.copysign - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.conjugate - imported by numpy._core (conditional), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.conj - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.complexfloating - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.complex64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.clongdouble - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.character - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ceil - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.cdouble - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.cbrt - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bytes_ - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.byte - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bool_ - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_xor - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_or - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_count - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_and - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.atleast_3d - imported by numpy._core (top-level), numpy.lib._shape_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.atleast_2d - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.atleast_1d - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.asarray - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._array_utils_impl (top-level), numpy (conditional), numpy.fft._helper (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.asanyarray - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.array_repr - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional)
|
||||
missing module named numpy._core.array2string - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.array - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.argsort - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.arctanh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arctan2 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arctan - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arcsinh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arcsin - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arccosh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arccos - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arange - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy.fft._helper (top-level)
|
||||
missing module named numpy._core.amin - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.amax - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.all - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.add - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named yaml - imported by numpy.__config__ (delayed)
|
||||
missing module named numpy._distributor_init_local - imported by numpy (optional), numpy._distributor_init (optional)
|
||||
missing module named defusedxml - imported by PIL.Image (optional)
|
||||
missing module named 'rlextra.pageCatcher' - imported by reportlab.lib.pdfencrypt (delayed, optional)
|
||||
missing module named pyaes - imported by reportlab.lib.pdfencrypt (optional)
|
||||
missing module named pyphen - imported by reportlab.platypus.paragraph (optional)
|
||||
missing module named reportlab.platypus.cleanBlockQuotedText - imported by reportlab.platypus (conditional), reportlab.platypus.paraparser (conditional)
|
||||
missing module named sets - imported by reportlab.platypus.doctemplate (optional)
|
||||
missing module named 'tests.test_platypus_tables' - imported by reportlab.platypus.tables (conditional)
|
||||
missing module named renderPM - imported by reportlab.graphics.charts.utils (delayed, conditional)
|
||||
missing module named rlextra - imported by reportlab.graphics.charts.textlabels (optional)
|
||||
missing module named freetype - imported by reportlab.graphics.utils (delayed, conditional, optional)
|
||||
missing module named _rl_renderPM - imported by reportlab.graphics.utils (delayed, conditional, optional), reportlab.graphics.renderPM (delayed, conditional, optional)
|
||||
missing module named 'rlextra.graphics' - imported by reportlab.graphics.shapes (delayed, conditional, optional)
|
||||
missing module named Image - imported by reportlab.graphics.renderPM (delayed, optional), kivy.core.image.img_pil (optional), docutils.parsers.rst.directives.images (optional)
|
||||
missing module named rlPyCairo - imported by reportlab.graphics.renderPM (delayed, conditional, optional)
|
||||
missing module named macostools - imported by reportlab.lib.utils (conditional), reportlab.graphics.renderPDF (delayed, conditional, optional), reportlab.graphics.shapes (delayed, conditional)
|
||||
missing module named macfs - imported by reportlab.lib.utils (conditional), reportlab.graphics.renderPDF (delayed, conditional, optional), reportlab.graphics.shapes (delayed, conditional)
|
||||
missing module named new - imported by reportlab.lib.attrmap (delayed, conditional)
|
||||
missing module named reportlab.platypus.XPreformatted - imported by reportlab.platypus (top-level), reportlab.graphics.charts.textlabels (top-level)
|
||||
missing module named 'reportlab.lib.pyHnj' - imported by reportlab.lib.utils (delayed, optional)
|
||||
missing module named rlbidi - imported by reportlab.pdfgen.textobject (optional)
|
||||
missing module named uharfbuzz - imported by reportlab.pdfbase.ttfonts (optional)
|
||||
missing module named pyRXPU - imported by reportlab.lib.rparsexml (optional)
|
||||
missing module named reportlab_mods - imported by reportlab (optional)
|
||||
missing module named 'reportlab.local_rl_mods' - imported by reportlab (optional)
|
||||
missing module named Queue - imported by kivy.compat (optional)
|
||||
missing module named ConfigParser - imported by kivy.config (optional)
|
||||
missing module named 'kivy.core.text._text_pango' - imported by kivy.core.text.text_pango (top-level)
|
||||
missing module named pygame - imported by kivy.input.providers.androidjoystick (conditional), kivy.app (delayed, conditional), kivy.core.window.window_pygame (top-level), kivy.support (delayed), kivy.core.text.text_pygame (optional), kivy.core.clipboard.clipboard_pygame (optional), kivy.core.audio.audio_pygame (conditional, optional), kivy.core.image.img_pygame (optional)
|
||||
missing module named android - imported by kivy.metrics (delayed, conditional), kivy.core.window (delayed, conditional), kivy.base (delayed, optional), kivy.input.providers.androidjoystick (optional), kivy.app (delayed, conditional), kivy.core.window.window_pygame (conditional, optional), kivy.support (delayed, optional), kivy.core.clipboard.clipboard_android (top-level), kivy.core.window.window_sdl2 (delayed, conditional), kivy.core.audio.audio_android (top-level)
|
||||
missing module named jnius - imported by kivy.metrics (delayed, conditional), kivy.app (delayed, conditional), kivy.core.clipboard.clipboard_android (top-level), kivy.core.camera.camera_android (top-level), kivy.core.audio.audio_android (top-level)
|
||||
missing module named cv2 - imported by kivy.core.camera.camera_android (delayed), kivy.core.camera.camera_opencv (optional)
|
||||
missing module named 'opencv.highgui' - imported by kivy.core.camera.camera_opencv (optional)
|
||||
missing module named opencv - imported by kivy.core.camera.camera_opencv (optional)
|
||||
missing module named android_mixer - imported by kivy.core.audio.audio_pygame (conditional, optional)
|
||||
missing module named 'android.mixer' - imported by kivy.core.audio.audio_pygame (conditional, optional)
|
||||
missing module named 'kivy.lib.gstplayer._gstplayer' - imported by kivy.lib.gstplayer (conditional)
|
||||
missing module named ios - imported by kivy.metrics (delayed, conditional), kivy.core.window (delayed)
|
||||
missing module named chardet - imported by pygments.lexer (delayed, conditional, optional)
|
||||
missing module named pygments.formatters.BBCodeFormatter - imported by pygments.formatters (top-level), kivy.uix.codeinput (top-level)
|
||||
missing module named pygments.lexers.PrologLexer - imported by pygments.lexers (top-level), pygments.lexers.cplint (top-level)
|
||||
missing module named _winreg - imported by pygments.formatters.img (optional)
|
||||
missing module named ctags - imported by pygments.formatters.html (optional)
|
||||
missing module named smb - imported by kivy.loader (delayed, conditional, optional)
|
||||
missing module named Leap - imported by kivy.input.providers.leapfinger (delayed)
|
||||
missing module named oscpy - imported by kivy.input.providers.tuio (delayed, optional)
|
||||
missing module named win32file - imported by kivy.uix.filechooser (conditional, optional)
|
||||
missing module named 'ffpyplayer.tools' - imported by kivy.core.video.video_ffpyplayer (optional), kivy.core.audio.audio_ffpyplayer (optional), kivy.core.image.img_ffpyplayer (top-level)
|
||||
missing module named 'ffpyplayer.pic' - imported by kivy.core.image.img_ffpyplayer (top-level)
|
||||
missing module named ffpyplayer - imported by kivy.core.video.video_ffpyplayer (optional), kivy.core.audio.audio_ffpyplayer (optional), kivy.core.image.img_ffpyplayer (top-level)
|
||||
missing module named 'gi.repository' - imported by kivy.core.camera.camera_gi (top-level), kivy.core.clipboard.clipboard_gtk3 (top-level)
|
||||
missing module named gi - imported by kivy.support (delayed, optional), kivy.core.clipboard.clipboard_gtk3 (top-level)
|
||||
missing module named gobject - imported by kivy.support (delayed, optional)
|
||||
missing module named kivy.lib.vidcore_lite.egl - imported by kivy.lib.vidcore_lite (top-level), kivy.core.window.window_egl_rpi (top-level)
|
||||
missing module named kivy.lib.vidcore_lite.bcm - imported by kivy.lib.vidcore_lite (top-level), kivy.core.window.window_egl_rpi (top-level)
|
||||
missing module named win32con - imported by kivy.core.window.window_pygame (delayed), kivy.core.window.window_sdl2 (delayed, conditional)
|
||||
missing module named enchant - imported by kivy.core.spelling.spelling_enchant (top-level)
|
||||
missing module named 'ffpyplayer.player' - imported by kivy.core.video.video_ffpyplayer (optional), kivy.core.audio.audio_ffpyplayer (optional)
|
||||
missing module named 'pygame.scrap' - imported by kivy.core.clipboard.clipboard_pygame (optional)
|
||||
missing module named dbus - imported by kivy.core.clipboard.clipboard_dbusklipper (optional)
|
||||
missing module named 'pyobjus.dylib_manager' - imported by kivy.core.clipboard.clipboard_nspaste (optional), kivy.core.audio.audio_avplayer (top-level)
|
||||
missing module named pyobjus - imported by kivy.core.clipboard.clipboard_nspaste (optional), kivy.core.audio.audio_avplayer (top-level)
|
||||
missing module named picamera - imported by kivy.core.camera.camera_picamera (top-level)
|
||||
missing module named ffmpeg - imported by kivy.core.video.video_ffmpeg (optional)
|
||||
missing module named 'android.runnable' - imported by kivy.core.clipboard.clipboard_android (top-level)
|
||||
missing module named AppKit - imported by kivy.core.spelling.spelling_osxappkit (top-level)
|
||||
missing module named win32gui - imported by kivy.core.window.window_pygame (delayed)
|
||||
missing module named win32api - imported by print_label (delayed, conditional, optional), kivy.core.window.window_pygame (delayed)
|
||||
missing module named kivy_deps - imported by kivy (optional)
|
||||
missing module named trio - imported by kivy.clock (delayed, conditional)
|
||||
missing module named win32print - imported by print_label (delayed, conditional, optional)
|
||||
missing module named vms_lib - imported by platform (delayed, optional)
|
||||
missing module named 'java.lang' - imported by platform (delayed, optional)
|
||||
missing module named java - imported by platform (delayed)
|
||||
missing module named _wmi - imported by platform (optional)
|
||||
File diff suppressed because it is too large
Load Diff
48
build_exe.py
48
build_exe.py
@@ -1,11 +1,20 @@
|
||||
"""
|
||||
PyInstaller build script for Label Printer GUI
|
||||
Run this to create a standalone Windows executable
|
||||
|
||||
IMPORTANT: This script MUST be run on Windows to generate a Windows .exe file.
|
||||
If run on Linux/macOS, it will create a Linux/macOS binary that won't work on Windows.
|
||||
|
||||
To build for Windows:
|
||||
1. Copy this project to a Windows machine
|
||||
2. Install dependencies: pip install -r requirements_windows.txt
|
||||
3. Run this script: python build_exe.py
|
||||
4. The Windows .exe will be created in the dist/ folder
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from PyInstaller import __main__ as pyi_main
|
||||
import subprocess
|
||||
|
||||
# Get the current directory
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
@@ -17,7 +26,7 @@ args = [
|
||||
'--windowed', # Don't show console window
|
||||
'--name=LabelPrinter', # Executable name
|
||||
'--distpath=./dist', # Output directory
|
||||
'--buildpath=./build', # Build directory
|
||||
'--workpath=./build', # Work directory (was --buildpath)
|
||||
'--hidden-import=kivy',
|
||||
'--hidden-import=kivy.core.window',
|
||||
'--hidden-import=kivy.core.text',
|
||||
@@ -49,15 +58,26 @@ if __name__ == '__main__':
|
||||
# Change to script directory
|
||||
os.chdir(script_dir)
|
||||
|
||||
# Run PyInstaller
|
||||
pyi_main.run(args)
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("Build Complete!")
|
||||
print("=" * 60)
|
||||
print("\nExecutable location: ./dist/LabelPrinter.exe")
|
||||
print("\nYou can now:")
|
||||
print("1. Double-click LabelPrinter.exe to run")
|
||||
print("2. Share the exe with others")
|
||||
print("3. Create a shortcut on desktop")
|
||||
print("\nNote: First run may take a moment as Kivy initializes")
|
||||
# Run PyInstaller directly with subprocess for better error reporting
|
||||
try:
|
||||
result = subprocess.run(['pyinstaller'] + args, check=True)
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("Build Complete!")
|
||||
print("=" * 60)
|
||||
print("\nExecutable location: ./dist/LabelPrinter.exe")
|
||||
print("\nYou can now:")
|
||||
print("1. Double-click LabelPrinter.exe to run")
|
||||
print("2. Share the exe with others")
|
||||
print("3. Create a shortcut on desktop")
|
||||
print("\nNote: First run may take a moment as Kivy initializes")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print("\n" + "=" * 60)
|
||||
print("Build Failed!")
|
||||
print("=" * 60)
|
||||
print(f"\nError code: {e.returncode}")
|
||||
print("\nPlease check the error messages above for details.")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"\nFatal error: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
99
build_windows.bat
Normal file
99
build_windows.bat
Normal file
@@ -0,0 +1,99 @@
|
||||
@echo off
|
||||
REM Label Printer - Windows Build Script (Single File EXE)
|
||||
REM This script builds a standalone LabelPrinter.exe on Windows
|
||||
REM Requirements: Python 3.10-3.13 installed and in PATH
|
||||
REM Note: Python 3.14+ may have compatibility issues
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo.
|
||||
echo ========================================================
|
||||
echo Label Printer - Windows Build Script
|
||||
echo Creates: LabelPrinter.exe (Single File)
|
||||
echo ========================================================
|
||||
echo.
|
||||
|
||||
REM Check if Python is installed
|
||||
python --version >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Python is not installed or not in PATH
|
||||
echo Please install Python 3.10-3.13 from https://www.python.org/
|
||||
echo Make sure to check "Add Python to PATH" during installation
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [1/5] Checking Python installation...
|
||||
python --version
|
||||
echo.
|
||||
|
||||
REM Upgrade pip
|
||||
echo [2/5] Upgrading pip, setuptools, and wheel...
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to upgrade pip
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo.
|
||||
|
||||
REM Install dependencies
|
||||
echo [3/5] Installing dependencies...
|
||||
echo Installing: python-barcode, pillow, reportlab, kivy, pyinstaller, pywin32, wmi...
|
||||
pip install python-barcode pillow reportlab kivy==2.2.1 pyinstaller==6.1.0 pywin32 wmi
|
||||
if errorlevel 1 (
|
||||
echo ERROR: Failed to install dependencies
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo.
|
||||
|
||||
REM Clean old build
|
||||
echo [4/5] Cleaning old build artifacts...
|
||||
if exist "dist" rmdir /s /q dist
|
||||
if exist "build" rmdir /s /q build
|
||||
if exist "*.spec" del *.spec
|
||||
echo.
|
||||
|
||||
REM Build with PyInstaller
|
||||
echo [5/5] Building executable with PyInstaller...
|
||||
echo This may take 5-15 minutes, please wait...
|
||||
echo.
|
||||
|
||||
pyinstaller label_printer_gui.py ^
|
||||
--onefile ^
|
||||
--windowed ^
|
||||
--name=LabelPrinter ^
|
||||
--distpath=./dist ^
|
||||
--workpath=./build ^
|
||||
--hidden-import=kivy ^
|
||||
--hidden-import=PIL ^
|
||||
--hidden-import=barcode ^
|
||||
--hidden-import=reportlab ^
|
||||
--hidden-import=print_label ^
|
||||
--hidden-import=print_label_pdf ^
|
||||
-y
|
||||
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo ERROR: Build failed!
|
||||
echo Please check the error messages above.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo ========================================================
|
||||
echo BUILD SUCCESSFUL!
|
||||
echo ========================================================
|
||||
echo.
|
||||
echo Executable Location: dist\LabelPrinter.exe
|
||||
echo.
|
||||
echo Next steps:
|
||||
echo 1. Navigate to the dist folder
|
||||
echo 2. Double-click LabelPrinter.exe to run
|
||||
echo 3. You can copy LabelPrinter.exe to other machines
|
||||
echo.
|
||||
echo Note: First run may take a moment as Kivy initializes
|
||||
echo.
|
||||
pause
|
||||
130
build_windows.ps1
Normal file
130
build_windows.ps1
Normal file
@@ -0,0 +1,130 @@
|
||||
# Label Printer - Windows Build Script (Single File EXE)
|
||||
# This script builds a standalone LabelPrinter.exe on Windows
|
||||
# Requirements: Python 3.10-3.13 installed and in PATH
|
||||
# Note: Python 3.14+ may have compatibility issues
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "========================================================"
|
||||
Write-Host " Label Printer - Windows Build Script"
|
||||
Write-Host " Creates: LabelPrinter.exe (Single File)"
|
||||
Write-Host "========================================================"
|
||||
Write-Host ""
|
||||
|
||||
# Check if Python is installed
|
||||
try {
|
||||
$pythonVersion = python --version 2>&1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Python not found"
|
||||
}
|
||||
} catch {
|
||||
Write-Host "ERROR: Python is not installed or not in PATH" -ForegroundColor Red
|
||||
Write-Host "Please install Python 3.10-3.13 from https://www.python.org/"
|
||||
Write-Host "Make sure to check 'Add Python to PATH' during installation"
|
||||
Read-Host "Press Enter to exit"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "[1/5] Checking Python installation..." -ForegroundColor Cyan
|
||||
Write-Host $pythonVersion
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "[2/5] Upgrading pip, setuptools, and wheel..." -ForegroundColor Cyan
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "ERROR: Failed to upgrade pip" -ForegroundColor Red
|
||||
Read-Host "Press Enter to exit"
|
||||
exit 1
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "[3/5] Installing dependencies..." -ForegroundColor Cyan
|
||||
Write-Host "Installing: python-barcode, pillow, reportlab, kivy, pyinstaller, pywin32, wmi..."
|
||||
pip install python-barcode pillow reportlab kivy pyinstaller pywin32 wmi
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "ERROR: Failed to install dependencies" -ForegroundColor Red
|
||||
Read-Host "Press Enter to exit"
|
||||
exit 1
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "[4/6] Checking for SumatraPDF..." -ForegroundColor Cyan
|
||||
$sumatraPath = "SumatraPDF\SumatraPDF.exe"
|
||||
if (-not (Test-Path $sumatraPath)) {
|
||||
Write-Host ""
|
||||
Write-Host "WARNING: SumatraPDF not found!" -ForegroundColor Yellow
|
||||
Write-Host "SumatraPDF is required for silent PDF printing." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host "Run the setup script first:" -ForegroundColor Yellow
|
||||
Write-Host " powershell -ExecutionPolicy Bypass -File setup_sumatra.ps1" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
$response = Read-Host "Continue building without SumatraPDF? (y/n)"
|
||||
if ($response -ne "y") {
|
||||
Write-Host "Build cancelled."
|
||||
Read-Host "Press Enter to exit"
|
||||
exit 1
|
||||
}
|
||||
Write-Host ""
|
||||
Write-Host "Building without SumatraPDF (PDF printing will not work)..." -ForegroundColor Yellow
|
||||
$addBinaryArg = @()
|
||||
} else {
|
||||
Write-Host "Found: $sumatraPath" -ForegroundColor Green
|
||||
# Add SumatraPDF as bundled binary (will be embedded inside the exe)
|
||||
$addBinaryArg = @("--add-binary", "$sumatraPath;.")
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "[5/6] Cleaning old build artifacts..." -ForegroundColor Cyan
|
||||
if (Test-Path "dist") { Remove-Item -Recurse -Force "dist" }
|
||||
if (Test-Path "build") { Remove-Item -Recurse -Force "build" }
|
||||
Remove-Item -Force "*.spec" -ErrorAction SilentlyContinue
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "[6/6] Building executable with PyInstaller..." -ForegroundColor Cyan
|
||||
Write-Host "This may take 5-15 minutes, please wait..."
|
||||
Write-Host ""
|
||||
|
||||
$pyinstallerArgs = @(
|
||||
"label_printer_gui.py",
|
||||
"--onefile",
|
||||
"--windowed",
|
||||
"--name=LabelPrinter",
|
||||
"--distpath=./dist",
|
||||
"--workpath=./build",
|
||||
"--hidden-import=kivy",
|
||||
"--hidden-import=PIL",
|
||||
"--hidden-import=barcode",
|
||||
"--hidden-import=reportlab",
|
||||
"--hidden-import=print_label",
|
||||
"--hidden-import=print_label_pdf",
|
||||
"-y"
|
||||
)
|
||||
|
||||
# Add SumatraPDF binary if available (bundles inside the exe)
|
||||
if ($addBinaryArg) {
|
||||
$pyinstallerArgs += $addBinaryArg
|
||||
}
|
||||
|
||||
pyinstaller @pyinstallerArgs
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host ""
|
||||
Write-Host "ERROR: Build failed!" -ForegroundColor Red
|
||||
Write-Host "Please check the error messages above." -ForegroundColor Red
|
||||
Read-Host "Press Enter to exit"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "========================================================"
|
||||
Write-Host " BUILD SUCCESSFUL!" -ForegroundColor Green
|
||||
Write-Host "========================================================"
|
||||
Write-Host ""
|
||||
Write-Host "Executable Location: dist\LabelPrinter.exe" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "Next steps:"
|
||||
Write-Host " 1. Navigate to the dist folder"
|
||||
Write-Host " 2. Double-click LabelPrinter.exe to run"
|
||||
Write-Host " 3. You can copy LabelPrinter.exe to other machines"
|
||||
Write-Host ""
|
||||
Write-Host "Note: First run may take a moment as Kivy initializes"
|
||||
Write-Host ""
|
||||
Read-Host "Press Enter to exit"
|
||||
BIN
dist/LabelPrinter
vendored
BIN
dist/LabelPrinter
vendored
Binary file not shown.
Binary file not shown.
@@ -1,61 +0,0 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
"""
|
||||
PyInstaller spec file for Label Printer GUI
|
||||
This creates a standalone Windows executable
|
||||
"""
|
||||
|
||||
a = Analysis(
|
||||
['label_printer_gui.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[
|
||||
'kivy',
|
||||
'kivy.core.window',
|
||||
'kivy.core.text',
|
||||
'kivy.core.image',
|
||||
'kivy.uix.boxlayout',
|
||||
'kivy.uix.gridlayout',
|
||||
'kivy.uix.label',
|
||||
'kivy.uix.textinput',
|
||||
'kivy.uix.button',
|
||||
'kivy.uix.spinner',
|
||||
'kivy.uix.scrollview',
|
||||
'kivy.uix.popup',
|
||||
'kivy.clock',
|
||||
'kivy.graphics',
|
||||
'PIL',
|
||||
'barcode',
|
||||
'reportlab',
|
||||
],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludedimports=[],
|
||||
noarchive=False,
|
||||
)
|
||||
|
||||
pyz = PYZ(a.pure, a.zipped_data, cipher=None)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
name='LabelPrinter',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False, # No console window
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=None,
|
||||
)
|
||||
@@ -19,6 +19,9 @@ from kivy.graphics import Color, Rectangle
|
||||
import os
|
||||
import threading
|
||||
import platform
|
||||
import time
|
||||
import datetime
|
||||
import glob
|
||||
from print_label import print_label_standalone, get_available_printers
|
||||
from kivy.clock import Clock
|
||||
|
||||
@@ -35,11 +38,175 @@ class LabelPrinterApp(App):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.available_printers = self.get_available_printers()
|
||||
# Build printer display names and mapping to full names
|
||||
full_printers = get_available_printers()
|
||||
self.printer_display_map = {} # display_name -> full_name
|
||||
self.available_printers = []
|
||||
for full_name in full_printers:
|
||||
display_name = self._shorten_printer_name(full_name)
|
||||
# Ensure unique display names
|
||||
if display_name in self.printer_display_map:
|
||||
display_name = full_name[:20]
|
||||
self.printer_display_map[display_name] = full_name
|
||||
self.available_printers.append(display_name)
|
||||
# Clean old PDF backup files on startup
|
||||
self.cleanup_old_pdfs()
|
||||
# Clean old log files on startup
|
||||
self.cleanup_old_logs()
|
||||
|
||||
def get_available_printers(self):
|
||||
"""Get list of available printers (cross-platform)"""
|
||||
return get_available_printers()
|
||||
def _shorten_printer_name(self, name, max_len=20):
|
||||
"""Shorten printer name for display (max 20 chars).
|
||||
For network printers like \\\\server\\printer, show just the printer part."""
|
||||
if name.startswith('\\\\'):
|
||||
# Network printer: \\server\printer -> extract printer name
|
||||
parts = name.strip('\\').split('\\')
|
||||
if len(parts) >= 2:
|
||||
short = parts[-1] # Just the printer name
|
||||
else:
|
||||
short = name
|
||||
else:
|
||||
short = name
|
||||
# Truncate to max_len
|
||||
if len(short) > max_len:
|
||||
short = short[:max_len]
|
||||
return short
|
||||
|
||||
def _get_full_printer_name(self, display_name):
|
||||
"""Resolve display name back to full printer name for printing."""
|
||||
return self.printer_display_map.get(display_name, display_name)
|
||||
|
||||
def cleanup_old_pdfs(self, days=5):
|
||||
"""
|
||||
Delete PDF files older than specified days from pdf_backup folder.
|
||||
|
||||
Args:
|
||||
days (int): Delete files older than this many days (default: 5)
|
||||
"""
|
||||
pdf_backup_dir = 'pdf_backup'
|
||||
|
||||
# Create folder if it doesn't exist
|
||||
if not os.path.exists(pdf_backup_dir):
|
||||
os.makedirs(pdf_backup_dir, exist_ok=True)
|
||||
return
|
||||
|
||||
try:
|
||||
current_time = time.time()
|
||||
cutoff_time = current_time - (days * 24 * 3600) # Convert days to seconds
|
||||
|
||||
for filename in os.listdir(pdf_backup_dir):
|
||||
file_path = os.path.join(pdf_backup_dir, filename)
|
||||
|
||||
# Only process PDF files
|
||||
if not filename.endswith('.pdf'):
|
||||
continue
|
||||
|
||||
# Check if file is older than cutoff
|
||||
if os.path.isfile(file_path):
|
||||
file_mtime = os.path.getmtime(file_path)
|
||||
if file_mtime < cutoff_time:
|
||||
try:
|
||||
os.remove(file_path)
|
||||
print(f"Deleted old PDF: {filename}")
|
||||
except Exception as e:
|
||||
print(f"Failed to delete {filename}: {e}")
|
||||
except Exception as e:
|
||||
print(f"Error during PDF cleanup: {e}")
|
||||
|
||||
def cleanup_old_logs(self, days=5):
|
||||
"""
|
||||
Delete log files older than specified days from logs folder.
|
||||
|
||||
Args:
|
||||
days (int): Delete files older than this many days (default: 5)
|
||||
"""
|
||||
logs_dir = 'logs'
|
||||
|
||||
# Create folder if it doesn't exist
|
||||
if not os.path.exists(logs_dir):
|
||||
os.makedirs(logs_dir, exist_ok=True)
|
||||
return
|
||||
|
||||
try:
|
||||
current_time = time.time()
|
||||
cutoff_time = current_time - (days * 24 * 3600) # Convert days to seconds
|
||||
|
||||
for filename in os.listdir(logs_dir):
|
||||
file_path = os.path.join(logs_dir, filename)
|
||||
|
||||
# Process both .log and .csv files
|
||||
if not (filename.endswith('.log') or filename.endswith('.csv')):
|
||||
continue
|
||||
|
||||
# Check if file is older than cutoff
|
||||
if os.path.isfile(file_path):
|
||||
file_mtime = os.path.getmtime(file_path)
|
||||
if file_mtime < cutoff_time:
|
||||
try:
|
||||
os.remove(file_path)
|
||||
print(f"Deleted old log: {filename}")
|
||||
except Exception as e:
|
||||
print(f"Failed to delete {filename}: {e}")
|
||||
except Exception as e:
|
||||
print(f"Error during log cleanup: {e}")
|
||||
|
||||
def log_print_action(self, sap_nr, quantity, cable_id, printer, pdf_filename, success):
|
||||
"""
|
||||
Log the print action to a CSV log file (table format).
|
||||
|
||||
Args:
|
||||
sap_nr (str): SAP article number
|
||||
quantity (str): Quantity value
|
||||
cable_id (str): Cable ID
|
||||
printer (str): Printer name
|
||||
pdf_filename (str): Path to the generated PDF file
|
||||
success (bool): Whether the print was successful
|
||||
"""
|
||||
logs_dir = 'logs'
|
||||
|
||||
# Create logs folder if it doesn't exist
|
||||
os.makedirs(logs_dir, exist_ok=True)
|
||||
|
||||
try:
|
||||
# Create log filename with date
|
||||
log_date = datetime.datetime.now().strftime("%Y%m%d")
|
||||
log_filename = os.path.join(logs_dir, f"print_log_{log_date}.csv")
|
||||
|
||||
# Create log entry values
|
||||
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
status = "SUCCESS" if success else "FAILED"
|
||||
|
||||
# Escape CSV values (handle commas and quotes)
|
||||
def escape_csv(value):
|
||||
"""Escape CSV special characters"""
|
||||
value = str(value)
|
||||
if ',' in value or '"' in value or '\n' in value:
|
||||
value = '"' + value.replace('"', '""') + '"'
|
||||
return value
|
||||
|
||||
# Create CSV line
|
||||
log_line = (
|
||||
f"{timestamp},{status},"
|
||||
f"{escape_csv(sap_nr)},"
|
||||
f"{escape_csv(quantity)},"
|
||||
f"{escape_csv(cable_id)},"
|
||||
f"{escape_csv(printer)},"
|
||||
f"{escape_csv(pdf_filename)}\n"
|
||||
)
|
||||
|
||||
# Check if file exists to add header on first entry
|
||||
file_exists = os.path.isfile(log_filename)
|
||||
|
||||
# Write to log file
|
||||
with open(log_filename, 'a', encoding='utf-8') as f:
|
||||
# Add header if file is new
|
||||
if not file_exists:
|
||||
f.write("Timestamp,Status,SAP-Nr,Quantity,Cable ID,Printer,PDF File\n")
|
||||
# Append log entry
|
||||
f.write(log_line)
|
||||
|
||||
print(f"Log entry saved to: {log_filename}")
|
||||
except Exception as e:
|
||||
print(f"Error saving log entry: {e}")
|
||||
|
||||
def build(self):
|
||||
"""Build the simplified single-column UI"""
|
||||
@@ -138,7 +305,8 @@ class LabelPrinterApp(App):
|
||||
values=self.available_printers,
|
||||
size_hint_y=None,
|
||||
height=45,
|
||||
font_size='12sp'
|
||||
font_size='12sp',
|
||||
sync_height=True,
|
||||
)
|
||||
self.printer_spinner = printer_spinner
|
||||
form_layout.add_widget(printer_spinner)
|
||||
@@ -180,7 +348,8 @@ class LabelPrinterApp(App):
|
||||
sap_nr = self.sap_input.text.strip()
|
||||
quantity = self.qty_input.text.strip()
|
||||
cable_id = self.cable_id_input.text.strip()
|
||||
printer = self.printer_spinner.text
|
||||
# Resolve display name to full printer name
|
||||
printer = self._get_full_printer_name(self.printer_spinner.text)
|
||||
|
||||
# Validate input
|
||||
if not sap_nr and not quantity and not cable_id:
|
||||
@@ -206,18 +375,37 @@ class LabelPrinterApp(App):
|
||||
|
||||
# Print in background thread (using PDF by default)
|
||||
def print_thread():
|
||||
pdf_filename = None
|
||||
success = False
|
||||
try:
|
||||
success = print_label_standalone(label_text, printer, preview=0, use_pdf=True)
|
||||
|
||||
# Get the PDF filename that was created
|
||||
# Files are saved to pdf_backup/ with timestamp
|
||||
pdf_files = glob.glob('pdf_backup/final_label_*.pdf')
|
||||
if pdf_files:
|
||||
# Get the most recently created PDF file
|
||||
pdf_filename = max(pdf_files, key=os.path.getctime)
|
||||
|
||||
if success:
|
||||
# Log the successful print action
|
||||
self.log_print_action(sap_nr, quantity, cable_id, printer, pdf_filename or "unknown", True)
|
||||
|
||||
# Use Clock.schedule_once to update UI from main thread
|
||||
Clock.schedule_once(lambda dt: popup.dismiss(), 0)
|
||||
Clock.schedule_once(lambda dt: self.show_popup("Success", "Label printed successfully!"), 0.1)
|
||||
# Clear inputs after successful print
|
||||
Clock.schedule_once(lambda dt: self.show_popup("Success", "Label printed successfully!", auto_dismiss=True), 0.1)
|
||||
# Clear inputs after successful print (but keep printer selection)
|
||||
Clock.schedule_once(lambda dt: self.clear_inputs(), 0.2)
|
||||
else:
|
||||
# Log the failed print action
|
||||
self.log_print_action(sap_nr, quantity, cable_id, printer, pdf_filename or "unknown", False)
|
||||
|
||||
Clock.schedule_once(lambda dt: popup.dismiss(), 0)
|
||||
Clock.schedule_once(lambda dt: self.show_popup("Error", "Failed to print label"), 0.1)
|
||||
except Exception as e:
|
||||
# Log the error
|
||||
self.log_print_action(sap_nr, quantity, cable_id, printer, pdf_filename or "unknown", False)
|
||||
|
||||
Clock.schedule_once(lambda dt: popup.dismiss(), 0)
|
||||
Clock.schedule_once(lambda dt: self.show_popup("Error", f"Print error: {str(e)}"), 0.1)
|
||||
|
||||
@@ -226,13 +414,20 @@ class LabelPrinterApp(App):
|
||||
thread.start()
|
||||
|
||||
def clear_inputs(self):
|
||||
"""Clear all input fields"""
|
||||
"""Clear only the input fields, preserving printer selection"""
|
||||
self.sap_input.text = ''
|
||||
self.qty_input.text = ''
|
||||
self.cable_id_input.text = ''
|
||||
# Printer selection is NOT cleared - it persists until user changes it
|
||||
|
||||
def show_popup(self, title, message):
|
||||
"""Show a popup message"""
|
||||
def show_popup(self, title, message, auto_dismiss=False):
|
||||
"""Show a popup message
|
||||
|
||||
Args:
|
||||
title (str): Popup title
|
||||
message (str): Popup message
|
||||
auto_dismiss (bool): If True, popup will auto-dismiss after 3 seconds
|
||||
"""
|
||||
popup = Popup(
|
||||
title=title,
|
||||
content=BoxLayout(
|
||||
@@ -250,6 +445,10 @@ class LabelPrinterApp(App):
|
||||
popup.content.add_widget(close_button)
|
||||
|
||||
popup.open()
|
||||
|
||||
# Auto-dismiss after 3 seconds if requested
|
||||
if auto_dismiss:
|
||||
Clock.schedule_once(lambda dt: popup.dismiss(), 3)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
7
logs/print_log_20260206.log
Normal file
7
logs/print_log_20260206.log
Normal file
@@ -0,0 +1,7 @@
|
||||
[2026-02-06 08:30:44] SUCCESS
|
||||
SAP-Nr: jgvkdjrdkh
|
||||
Quantity: 300
|
||||
Cable ID: jdflhfgvkjdzhee6465758382
|
||||
Printer: PDF
|
||||
PDF File: pdf_backup/final_label_20260206_083044.pdf
|
||||
---
|
||||
103
pdf_backup/final_label_20260206_083044.pdf
Normal file
103
pdf_backup/final_label_20260206_083044.pdf
Normal file
File diff suppressed because one or more lines are too long
172
print_label.py
172
print_label.py
@@ -3,6 +3,7 @@ import barcode
|
||||
from barcode.writer import ImageWriter
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import datetime
|
||||
import platform
|
||||
import subprocess
|
||||
@@ -28,6 +29,7 @@ SYSTEM = platform.system() # 'Linux', 'Windows', 'Darwin'
|
||||
def get_available_printers():
|
||||
"""
|
||||
Get list of available printers (cross-platform).
|
||||
Includes both local and network printers on Windows.
|
||||
|
||||
Returns:
|
||||
list: List of available printer names, with "PDF" as fallback
|
||||
@@ -40,14 +42,29 @@ def get_available_printers():
|
||||
return list(printers.keys()) if printers else ["PDF"]
|
||||
|
||||
elif SYSTEM == "Windows":
|
||||
# Windows: Try win32print first
|
||||
# Windows: Get local + connected printers (includes print server connections)
|
||||
try:
|
||||
printers = []
|
||||
for printer_name in win32print.EnumPrinters(win32print.PRINTER_ENUM_LOCAL):
|
||||
printers.append(printer_name[2])
|
||||
|
||||
# PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS captures:
|
||||
# - Locally installed printers
|
||||
# - Printers connected from a print server (e.g. \\server\printer)
|
||||
try:
|
||||
flags = win32print.PRINTER_ENUM_LOCAL | win32print.PRINTER_ENUM_CONNECTIONS
|
||||
for printer_info in win32print.EnumPrinters(flags):
|
||||
printer_name = printer_info[2]
|
||||
if printer_name and printer_name not in printers:
|
||||
printers.append(printer_name)
|
||||
except Exception as e:
|
||||
print(f"Error enumerating printers: {e}")
|
||||
|
||||
# Add PDF as fallback option
|
||||
if "PDF" not in printers:
|
||||
printers.append("PDF")
|
||||
|
||||
return printers if printers else ["PDF"]
|
||||
except:
|
||||
# Fallback for Windows if win32print fails
|
||||
except Exception as e:
|
||||
print(f"Error getting Windows printers: {e}")
|
||||
return ["PDF"]
|
||||
|
||||
elif SYSTEM == "Darwin":
|
||||
@@ -233,23 +250,146 @@ def print_to_printer(printer_name, file_path):
|
||||
return True
|
||||
|
||||
elif SYSTEM == "Windows":
|
||||
# Windows: Use win32print or open with default printer
|
||||
# Windows: Print PDF silently without any viewer opening
|
||||
try:
|
||||
if WIN32_AVAILABLE:
|
||||
import win32print
|
||||
import win32api
|
||||
# Print using the Windows API
|
||||
win32api.ShellExecute(0, "print", file_path, f'/d:"{printer_name}"', ".", 0)
|
||||
print(f"Label sent to printer: {printer_name}")
|
||||
return True
|
||||
else:
|
||||
# Fallback: Open with default printer
|
||||
|
||||
if file_path.endswith('.pdf'):
|
||||
os.startfile(file_path, "print")
|
||||
# Try silent printing methods (no viewer opens)
|
||||
import os
|
||||
import winreg
|
||||
|
||||
printed = False
|
||||
|
||||
# Method 1: SumatraPDF (bundled inside exe or external)
|
||||
sumatra_paths = []
|
||||
|
||||
# Get the directory where this script/exe is running
|
||||
if getattr(sys, 'frozen', False):
|
||||
# Running as compiled executable
|
||||
# PyInstaller extracts bundled files to sys._MEIPASS temp folder
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
# Check bundled version first (inside the exe)
|
||||
bundled_sumatra = os.path.join(sys._MEIPASS, 'SumatraPDF.exe')
|
||||
sumatra_paths.append(bundled_sumatra)
|
||||
|
||||
# Also check app directory for external version
|
||||
app_dir = os.path.dirname(sys.executable)
|
||||
sumatra_paths.append(os.path.join(app_dir, "SumatraPDF", "SumatraPDF.exe"))
|
||||
sumatra_paths.append(os.path.join(app_dir, "SumatraPDF.exe"))
|
||||
else:
|
||||
# Running as script - check local folders
|
||||
app_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sumatra_paths.append(os.path.join(app_dir, "SumatraPDF", "SumatraPDF.exe"))
|
||||
sumatra_paths.append(os.path.join(app_dir, "SumatraPDF.exe"))
|
||||
|
||||
# Then check system installations
|
||||
sumatra_paths.extend([
|
||||
r"C:\Program Files\SumatraPDF\SumatraPDF.exe",
|
||||
r"C:\Program Files (x86)\SumatraPDF\SumatraPDF.exe",
|
||||
])
|
||||
|
||||
for sumatra_path in sumatra_paths:
|
||||
if os.path.exists(sumatra_path):
|
||||
try:
|
||||
subprocess.run([
|
||||
sumatra_path,
|
||||
"-print-to",
|
||||
printer_name,
|
||||
file_path,
|
||||
"-print-settings",
|
||||
"fit,landscape",
|
||||
"-silent",
|
||||
"-exit-when-done"
|
||||
], check=False, creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
print(f"Label sent to printer via SumatraPDF: {printer_name}")
|
||||
printed = True
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"SumatraPDF error: {e}")
|
||||
|
||||
# Method 2: Adobe Reader silent printing
|
||||
if not printed:
|
||||
adobe_path = None
|
||||
for key_path in [
|
||||
r"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe",
|
||||
r"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Acrobat.exe"
|
||||
]:
|
||||
try:
|
||||
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key_path)
|
||||
adobe_path, _ = winreg.QueryValueEx(key, "")
|
||||
winreg.CloseKey(key)
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
if adobe_path and os.path.exists(adobe_path):
|
||||
try:
|
||||
subprocess.run([
|
||||
adobe_path,
|
||||
"/t", # Print and close
|
||||
file_path,
|
||||
printer_name
|
||||
], check=False, creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
print(f"Label sent to printer via Adobe Reader: {printer_name}")
|
||||
printed = True
|
||||
except:
|
||||
pass
|
||||
|
||||
# Method 3: GhostScript (if installed)
|
||||
if not printed:
|
||||
gs_paths = [
|
||||
r"C:\Program Files\gs\gs10.02.1\bin\gswin64c.exe",
|
||||
r"C:\Program Files (x86)\gs\gs10.02.1\bin\gswin32c.exe",
|
||||
]
|
||||
# Try to find gswin in PATH
|
||||
try:
|
||||
gs_result = subprocess.run(['where', 'gswin64c'],
|
||||
capture_output=True, text=True, check=False)
|
||||
if gs_result.returncode == 0:
|
||||
gs_paths.insert(0, gs_result.stdout.strip().split('\n')[0])
|
||||
except:
|
||||
pass
|
||||
|
||||
for gs_path in gs_paths:
|
||||
if os.path.exists(gs_path):
|
||||
try:
|
||||
subprocess.run([
|
||||
gs_path,
|
||||
"-dNOPAUSE", "-dBATCH", "-dQUIET",
|
||||
f"-sDEVICE=mswinpr2",
|
||||
f"-sOutputFile=%printer%{printer_name}",
|
||||
file_path
|
||||
], check=False, creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
print(f"Label sent to printer via GhostScript: {printer_name}")
|
||||
printed = True
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
if not printed:
|
||||
# Fallback: Let user know and save PDF
|
||||
print("=" * 60)
|
||||
print("NOTICE: Silent PDF printing requires SumatraPDF")
|
||||
print("SumatraPDF not found (should be bundled inside the app)")
|
||||
print("If you built the app yourself, ensure SumatraPDF.exe is downloaded first.")
|
||||
print("Run: setup_sumatra.ps1 before building")
|
||||
print("=" * 60)
|
||||
print(f"PDF saved to: {file_path}")
|
||||
print("The PDF can be printed manually.")
|
||||
|
||||
return True
|
||||
else:
|
||||
# For images, use default print application
|
||||
subprocess.run([f'notepad', '/p', file_path], check=False)
|
||||
print(f"Label sent to default printer")
|
||||
# Non-PDF files
|
||||
subprocess.run(['notepad', '/p', file_path],
|
||||
check=False,
|
||||
creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
print(f"Label sent to printer: {printer_name}")
|
||||
return True
|
||||
else:
|
||||
print("win32print not available, PDF saved as backup only")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Windows print error: {e}")
|
||||
|
||||
7
requirements_windows.txt
Normal file
7
requirements_windows.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
python-barcode
|
||||
pillow
|
||||
kivy>=2.1.0
|
||||
reportlab
|
||||
pyinstaller>=6.0.0
|
||||
pywin32
|
||||
wmi
|
||||
95
setup_sumatra.ps1
Normal file
95
setup_sumatra.ps1
Normal file
@@ -0,0 +1,95 @@
|
||||
# Download and Setup SumatraPDF Portable for Label Printer
|
||||
# This script downloads SumatraPDF portable and sets up the deployment structure
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "========================================================"
|
||||
Write-Host " Label Printer - SumatraPDF Setup"
|
||||
Write-Host "========================================================"
|
||||
Write-Host ""
|
||||
|
||||
# Create SumatraPDF folder if it doesn't exist
|
||||
$sumatraFolder = "SumatraPDF"
|
||||
if (-not (Test-Path $sumatraFolder)) {
|
||||
New-Item -ItemType Directory -Path $sumatraFolder -Force | Out-Null
|
||||
}
|
||||
|
||||
# Check if SumatraPDF.exe already exists
|
||||
$sumatraExe = Join-Path $sumatraFolder "SumatraPDF.exe"
|
||||
if (Test-Path $sumatraExe) {
|
||||
Write-Host "[OK] SumatraPDF.exe already exists at: $sumatraExe" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Read-Host "Press Enter to exit"
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "[1/3] Downloading SumatraPDF portable (64-bit, ~5 MB)..." -ForegroundColor Cyan
|
||||
|
||||
# SumatraPDF download URL (latest stable version)
|
||||
$url = "https://www.sumatrapdfreader.org/dl/rel/3.5.2/SumatraPDF-3.5.2-64.zip"
|
||||
$zipFile = "SumatraPDF-temp.zip"
|
||||
|
||||
try {
|
||||
# Download with progress
|
||||
$progressPreference = 'SilentlyContinue'
|
||||
Invoke-WebRequest -Uri $url -OutFile $zipFile -ErrorAction Stop
|
||||
Write-Host "[OK] Download complete" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "[ERROR] Failed to download SumatraPDF" -ForegroundColor Red
|
||||
Write-Host "Error: $_" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "Please download manually from:" -ForegroundColor Yellow
|
||||
Write-Host " https://www.sumatrapdfreader.org/download-free-pdf-viewer" -ForegroundColor Yellow
|
||||
Write-Host " Extract SumatraPDF.exe to the 'SumatraPDF' folder" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Read-Host "Press Enter to exit"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[2/3] Extracting..." -ForegroundColor Cyan
|
||||
|
||||
try {
|
||||
# Extract ZIP file
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory($zipFile, $sumatraFolder)
|
||||
Write-Host "[OK] Extraction complete" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "[ERROR] Failed to extract ZIP file" -ForegroundColor Red
|
||||
Write-Host "Error: $_" -ForegroundColor Red
|
||||
Read-Host "Press Enter to exit"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[3/3] Cleaning up..." -ForegroundColor Cyan
|
||||
|
||||
# Remove temporary ZIP file
|
||||
if (Test-Path $zipFile) {
|
||||
Remove-Item $zipFile -Force
|
||||
}
|
||||
|
||||
Write-Host "[OK] Cleanup complete" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# Verify installation
|
||||
if (Test-Path $sumatraExe) {
|
||||
Write-Host "========================================================"
|
||||
Write-Host " SETUP SUCCESSFUL!" -ForegroundColor Green
|
||||
Write-Host "========================================================"
|
||||
Write-Host ""
|
||||
Write-Host "SumatraPDF portable is now installed at:" -ForegroundColor Green
|
||||
Write-Host " $sumatraExe" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "The Label Printer app will now be able to print PDFs silently." -ForegroundColor Green
|
||||
Write-Host ""
|
||||
} else {
|
||||
Write-Host "========================================================"
|
||||
Write-Host " SETUP INCOMPLETE" -ForegroundColor Yellow
|
||||
Write-Host "========================================================"
|
||||
Write-Host ""
|
||||
Write-Host "Could not find SumatraPDF.exe after extraction." -ForegroundColor Yellow
|
||||
Write-Host "Please check the SumatraPDF folder and ensure SumatraPDF.exe is present." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
Read-Host "Press Enter to exit"
|
||||
Reference in New Issue
Block a user