Skip to main content

sc92-public-define

Personal shared utilities extracted from everyday scripts:

  1. Single-instance file lock — check_running_lock(): if the script is already running elsewhere, exit (or return False) immediately.
  2. Rotating logging setup — init_logging_config(): one call to get *_debug.log + *_info.log (10 MB × 7 backups) + console output. If another library already configured the root logger it now warns on stderr instead of silently doing nothing (pass force=True to take over); with no console (pythonw.exe, PyInstaller --noconsole) the console handler is skipped.
  3. Global exception hooks — enable_exception_logging(): uncaught exceptions are written to the log instead of only printed to stderr — for the main thread and for worker threads (threading.excepthook, which sys.excepthook never covers).
  4. MQTT publisher — MqttPublisher.publish(): one-shot connect → publish → disconnect. Credentials are taken from explicit constructor args only (no hardcoded defaults, no environment variables) — keep them in your local YAML config file and pass the values in.
  5. YAML config helpers — read_yaml() / write_yaml(): first run writes a default template into configs/ next to the script and exits for review; Chinese keys and insertion order are preserved, and a file saved as ANSI/GBK or broken YAML now fails with a readable message instead of a raw UnicodeDecodeError.

All helpers are PyInstaller-frozen aware and default to paths derived from the entry script, so typical usage needs zero arguments.

The derived name is <script dir>/…/<script name>…, so one instance means "one running copy of this script in this directory": a renamed or copied script is a separate instance. python -m pkg[.mod] is handled as module pkg[.mod] with the current working directory as its base — it never writes into site-packages.

Install

pip install sc92-public-define

Requires Python >= 3.11 (filelock>=4.0, paho-mqtt>=2.0, PyYAML>=6.0).

Typical usage (top of any script)

import logging
from sc92_public_define import (
    check_running_lock,     # single-instance lock
    init_logging_config,    # rotating logs + console
    enable_exception_logging,     # uncaught exception -> log
)

init_logging_config()       # logs/<script name>_debug.log / _info.log
check_running_lock()        # <script name>.running.lock next to the script;
                            # exits with status 1 when another copy is running
enable_exception_logging()

logging.info("main started")

MQTT publishing (credentials live in your YAML config, never in code)

from sc92_public_define import MqttPublisher, read_yaml

server = read_yaml()["mqtt服务器"]          # nested dict in <script>.config.yaml
pub = MqttPublisher(host=server["地址"], port=server["端口"],
                    username=server["用户名"] or None,
                    password=server["密码"] or None,
                    topic=server["主题"])
pub.publish("hello")                       # uses instance topic/qos
pub.publish("hello", topic="other/t", qos=1)   # per-call override

YAML config

from sc92_public_define import read_yaml, write_yaml

cfg = read_yaml(default_config={"服务器": "127.0.0.1", "端口": 8080})
# first run: creates configs/<script>.config.yaml next to the script, logs a hint, exits
cfg["端口"] = 9090
write_yaml(config_dict=cfg)     # writes back to the same default file

API

Function Default Notes
check_running_lock(lock_file=None, on_conflict="exit") <script dir>/<script>.running.lock on_conflict="exit" → logs an error and exits with status 1; "return" → returns False; True when acquired
init_logging_config(log_file=None, max_bytes=10MB, backup_count=7, force=False) <script dir>/logs/<script> warns on stderr and does nothing if the root logger already has handlers (force=True takes over); console handler skipped when there is no console
enable_exception_logging() / handle_global_exception / handle_thread_exception — sets sys.excepthook and threading.excepthook, writes tracebacks via logging.error
MqttPublisher(host, port=1883, username=None, password=None, topic=None, qos=2, client_id=None, connect_timeout=5, publish_timeout=10) explicit args only raises ValueError if host/topic missing; connect_timeout caps DNS + TCP + the wait for CONNACK
MqttPublisher.publish(msg, topic=None, qos=None) instance defaults True only when the message really got through: QoS 1/2 require the broker acknowledgement, QoS 0 has none (written to the socket only). Wrong password, missing CONNACK, an unacknowledged publish or any network error → False plus a logging.error, never raises. bytes/bytearray payloads are sent as-is, anything else is str()-ed
read_yaml(config_file=None, default_config=None, on_missing="exit", merge_defaults=False) <script dir>/configs/<script>.config.yaml missing → write template + exit(1); empty file or {} → overwrite with the template + exit(1); non-UTF-8 / broken YAML / top level not a mapping → ValueError; merge_defaults=True fills keys that only exist in default_config into the returned dict (the file on disk is untouched); the returned template is a deep copy
write_yaml(config_file=None, config_dict=None) same default file config_dict is required (None or a non-dict raises ValueError); utf-8, Chinese keys & order preserved
script_dir() / script_name() — entry-script path/name; frozen exe → exe folder/stem; python -m pkg → cwd + pkg
default_lock_file() / default_log_file() / default_config_file() — expose the derived default paths

Notes

  • The lock is released automatically by the OS when the process exits; the lock file is left on disk (harmless, reuse next time).
  • The first read_yaml() run on a machine without a config file deliberately exits with status 1 after writing the template: edit it, then run again.
  • init_logging_config() must come before check_running_lock() / read_yaml(), otherwise their "抢锁结果 / 配置已加载" INFO lines are dropped (only the ERROR lines still reach stderr through logging's last-resort handler).
  • See the demo/ folder in the source tree for runnable examples (it is not shipped inside the wheel or sdist).

Metadata

Release files for sc92-public-define 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sc92-public-define 0.3.1
File Size Uploaded Provenance Actions
sc92_public_define-0.3.1.tar.gz 14.6 kB Without provenance Details for sc92_public_define-0.3.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for sc92-public-define 0.3.1
File Interpreter ABI Platform Actions
sc92_public_define-0.3.1-py3-none-any.whl Python 3 none any Details for sc92_public_define-0.3.1-py3-none-any.whl

Total release size: 28.9 kB

Release files / sc92_public_define-0.3.1.tar.gz

Download URL sc92_public_define-0.3.1.tar.gz
Size 14.6 kB
Tags Source
SHA-256 checksum
How to use checksums
e508301a47037858c636be21f746301ef0efcdcc5da2da608ef9248edd779715
BLAKE2b-256 checksum
How to use checksums
35198268dda4cd5b182f80b7b70113494c79f23879b967f016ba16b50aded22e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release files / sc92_public_define-0.3.1-py3-none-any.whl

Download URL sc92_public_define-0.3.1-py3-none-any.whl
Size 14.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dac1b8f51d6d963219d070d5453f38142be4a1ea01f603817b91ff8a0881980a
BLAKE2b-256 checksum
How to use checksums
e47a64806dbb88ac20d6a27eafa4b4af5f4b1543c9c84cc611487024fa5dc8f9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Security for sc92-public-define 0.3.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page