tina4-python 3.13.83__tar.gz → 3.13.85__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tina4_python-3.13.83 → tina4_python-3.13.85}/PKG-INFO +1 -1
- {tina4_python-3.13.83 → tina4_python-3.13.85}/pyproject.toml +1 -1
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/cli/__init__.py +75 -13
- tina4_python-3.13.83/tina4_python/public/js/tina4-dev-admin.js +0 -1124
- {tina4_python-3.13.83 → tina4_python-3.13.85}/.gitignore +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/README.md +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/CLAUDE.md +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/Testing.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/auth/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/context/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/context/chunker.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/core/events.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/core/rate_limiter.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/core/request.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/core/response.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/core/router.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/core/server.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/database/connection.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/database/mongodb.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/dev_admin/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/dev_admin/plan.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/dev_admin/project_index.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/docs.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/docstore/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/env.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/mqtt/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/mqtt/message.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/orm/model.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/public/__feedback/widget.js +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/public/js/frond.js +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/queue/job.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/queue/kafka_backend.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/queue/lite_backend.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/queue/mongo_backend.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/queue/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/realtime/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/realtime/models/Attachment.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/realtime/models/Channel.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/realtime/models/ChannelMember.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/realtime/models/Message.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/realtime/models/Workspace.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/realtime/models/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/realtime/storage.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/_pagination.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/test/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.13.83 → tina4_python-3.13.85}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -170,24 +170,85 @@ def _parse_every(every: str) -> int:
|
|
|
170
170
|
return 60
|
|
171
171
|
|
|
172
172
|
|
|
173
|
+
def _in_container() -> bool:
|
|
174
|
+
"""True when this process is running inside a container.
|
|
175
|
+
|
|
176
|
+
Reclaiming a port makes sense on a dev machine, where a previous
|
|
177
|
+
``tina4 serve`` may still hold it. Inside a container the server IS the
|
|
178
|
+
container, so there is never a stale sibling to reclaim from -- and trying
|
|
179
|
+
is actively dangerous (see ``_kill_process_on_port``).
|
|
180
|
+
"""
|
|
181
|
+
if os.path.exists("/.dockerenv") or os.path.exists("/run/.containerenv"):
|
|
182
|
+
return True
|
|
183
|
+
try:
|
|
184
|
+
with open("/proc/1/cgroup", "r", encoding="utf-8", errors="replace") as fh:
|
|
185
|
+
blob = fh.read()
|
|
186
|
+
return "docker" in blob or "containerd" in blob or "kubepods" in blob
|
|
187
|
+
except OSError:
|
|
188
|
+
return False
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def selectable_pids(lsof_output: str, me: int, my_group: int | None = None) -> list[int]:
|
|
192
|
+
"""The PIDs from ``lsof -ti`` output that are safe to signal.
|
|
193
|
+
|
|
194
|
+
Pure so the safety rule can be tested directly. An unvalidated parse is a
|
|
195
|
+
footgun with real teeth: when ``lsof`` is present but prints a different
|
|
196
|
+
shape than ``-ti`` implies, a non-numeric field coerces to 0, and
|
|
197
|
+
signalling PID 0 sends the signal to EVERY process in the caller's own
|
|
198
|
+
process group -- the server kills itself. That is exactly what happened in
|
|
199
|
+
a container, where the log read "Killed existing process on port 7148
|
|
200
|
+
(PID: 1 ...)" and the container exited 143.
|
|
201
|
+
|
|
202
|
+
So: accept only all-digit tokens, and never PID 0 (our process group),
|
|
203
|
+
PID 1 (init), ourselves, or our own process group.
|
|
204
|
+
"""
|
|
205
|
+
pids = []
|
|
206
|
+
for token in lsof_output.split():
|
|
207
|
+
if not token.isdigit():
|
|
208
|
+
continue # never coerce junk into a PID
|
|
209
|
+
pid = int(token)
|
|
210
|
+
if pid <= 1 or pid == me:
|
|
211
|
+
continue # 0 = our process group, 1 = init, me = suicide
|
|
212
|
+
if my_group is not None and pid == my_group:
|
|
213
|
+
continue
|
|
214
|
+
if pid not in pids:
|
|
215
|
+
pids.append(pid)
|
|
216
|
+
return pids
|
|
217
|
+
|
|
218
|
+
|
|
173
219
|
def _kill_process_on_port(port: int) -> bool:
|
|
174
|
-
"""Kill any process listening on the given port. Returns True if killed.
|
|
220
|
+
"""Kill any process listening on the given port. Returns True if killed.
|
|
221
|
+
|
|
222
|
+
Skipped entirely in a container, where the server IS the container and
|
|
223
|
+
there is no stale sibling to reclaim from. The PID safety rule lives in
|
|
224
|
+
:func:`selectable_pids`.
|
|
225
|
+
"""
|
|
226
|
+
if _in_container():
|
|
227
|
+
return False
|
|
175
228
|
try:
|
|
176
229
|
result = subprocess.run(
|
|
177
230
|
["lsof", "-ti", f":{port}"],
|
|
178
231
|
capture_output=True, text=True, timeout=5,
|
|
179
232
|
)
|
|
180
|
-
if result.returncode
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
233
|
+
if result.returncode != 0 or not result.stdout.strip():
|
|
234
|
+
return False
|
|
235
|
+
|
|
236
|
+
me = os.getpid()
|
|
237
|
+
my_group = os.getpgrp() if hasattr(os, "getpgrp") else None
|
|
238
|
+
killed = []
|
|
239
|
+
for pid in selectable_pids(result.stdout, me, my_group):
|
|
240
|
+
try:
|
|
241
|
+
os.kill(pid, signal.SIGTERM)
|
|
242
|
+
killed.append(str(pid))
|
|
243
|
+
except (ProcessLookupError, PermissionError):
|
|
244
|
+
pass
|
|
245
|
+
|
|
246
|
+
if not killed:
|
|
247
|
+
return False
|
|
248
|
+
import time
|
|
249
|
+
time.sleep(0.5)
|
|
250
|
+
print(f" ⚠ Killed existing process on port {port} (PID: {', '.join(killed)})")
|
|
251
|
+
return True
|
|
191
252
|
except (FileNotFoundError, subprocess.TimeoutExpired):
|
|
192
253
|
pass
|
|
193
254
|
return False
|
|
@@ -663,7 +724,8 @@ def _init(args):
|
|
|
663
724
|
'FROM python:3.13-slim\nWORKDIR /app\n'
|
|
664
725
|
'COPY --from=build /app .\nCOPY --from=build /usr/local/bin/uv /usr/local/bin/uv\n'
|
|
665
726
|
'ENV PATH="/app/.venv/bin:$PATH"\nENV HOST=0.0.0.0\nENV PORT=7146\n'
|
|
666
|
-
'
|
|
727
|
+
'ENV TINA4_OVERRIDE_CLIENT=true\nENV TINA4_DEBUG=false\n'
|
|
728
|
+
'EXPOSE 7146\nCMD ["tina4python", "serve", "--production"]\n',
|
|
667
729
|
encoding="utf-8",
|
|
668
730
|
)
|
|
669
731
|
|