# windowsservice
`windowsservice` is a Python package for building Windows services.
The key features are:
- Easy to use
- Support for [PyInstaller](https://www.pyinstaller.org/)
- Support for [`multiprocessing`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.freeze_support)
## Getting ready
Create and activate a virtual environment:
```cli
python -m venv venv
```
```cli
.\venv\Scripts\activate
```
## Installation
Install the windowsservice package from PyPI:
```cli
pip install windowsservice
```
The windowsservice package depends on [pywin32](https://github.com/mhammond/pywin32) created by Mark Hammond. Installing the windowsservice package also installs the pywin32 dependency.
## Coding
1. Import the `BaseService` class:
```python
from windowsservice import BaseService
```
2. Create a new subclass that inherits from the `BaseService` class.
3. Define the following three class variables in the subclass:
- `_svc_name_`: A unique identifier for your service.
- `_svc_display_name_`: The name shown in the service control manager.
- `_svc_description_`: The description shown in the service control manager.
For example:
```python
_svc_name_ = "MyWindowsService"
_svc_display_name_ = "My Windows Service"
_svc_description_ = "This is my custom Windows service."
```
4. Override the following methods in the subclass:
- `start(self)`: This method is invoked when the service starts. Override
this to add setup code, such as initializing a running condition.
- `main(self)`: This method is invoked after `start`. Override this to
create a run loop, typically based on a running condition.
- `stop(self)`: This method is invoked when the service stops. Override
this to add cleanup code, such as releasing resources or to invalidate a
running condition.
For example:
```python
def start(self):
self.is_running = True
def main(self):
while self.is_running:
time.sleep(5)
def stop(self):
self.is_running = False
```
5. Call the `parse_command_line` class method from the module's entry point. This handles command-line arguments for installing, starting, stopping,
and debugging the service.
For example:
```python
if __name__ == "__main__":
ExampleService.parse_command_line()
```
### Examples
Basic example ([example_service.py](examples/example_service.py)):
```python
import time
from windowsservice import BaseService, utils
class ExampleService(BaseService):
"""Example Windows service in Python."""
_svc_name_ = "PythonExampleWindowsService"
_svc_display_name_ = "Python Example Windows Service"
_svc_description_ = "Example Windows service in Python"
def start(self):
self.is_running = True
def main(self):
while self.is_running:
utils.log(f"{self._svc_display_name_} is running...")
time.sleep(5)
def stop(self):
self.is_running = False
if __name__ == "__main__":
ExampleService.parse_command_line()
```
Example that demonstrates support for `multiprocessing` ([example_service_multiprocessing.py](examples/example_service_multiprocessing.py)):
```python
import time
from multiprocessing import Process, freeze_support
from windowsservice import BaseService, utils
def stub_server():
"""
A function that simulates a server process hosted by the Windows service.
This function logs a message every 5 seconds for a total of 100 times.
"""
for _ in range(100):
utils.log("Hello from a process hosted by a Windows service...")
time.sleep(5)
class ExampleService(BaseService):
"""Example Windows service in Python."""
_svc_name_ = "PythonExampleWindowsService"
_svc_display_name_ = "Python Example Windows Service"
_svc_description_ = "Example Windows service in Python"
def start(self):
self.server_process = Process(target=stub_server)
def main(self):
self.server_process.start()
self.server_process.join()
def stop(self):
if self.server_process:
self.server_process.terminate()
if __name__ == "__main__":
freeze_support()
ExampleService.parse_command_line()
```
## Usage
Some interactions with a Windows service may require administrative privileges, so you must use an elevated command line interface.
All arguments and options can be listed by invoking the module:
```cli
python .\examples\example_service.py
```
```stdout
Usage: 'example_service.py [options] install|update|remove|start [...]|stop|restart [...]|debug [...]'
Options for 'install' and 'update' commands only:
--username domain\username : The Username the service is to run under
--password password : The password for the username
--startup [manual|auto|disabled|delayed] : How the service starts, default = manual
--interactive : Allow the service to interact with the desktop.
--perfmonini file: .ini file to use for registering performance monitor data
--perfmondll file: .dll file to use when querying the service for
performance data, default = perfmondata.dll
Options for 'start' and 'stop' commands only:
--wait seconds: Wait for the service to actually start or stop.
If you specify --wait with the 'stop' option, the service
and all dependent services will be stopped, each waiting
the specified period.
```
### Install the service
If you want to install the service from the `example_service.py` example, run:
```cli
python .\examples\example_service.py install
```
```stdout
Installing service PythonExampleWindowsService
Service installed
```
You can also choose to install the service so that it will start automatically when Windows starts:
```cli
python .\examples\example_service.py --startup=auto install
```
### Start the service
To start/stop the service you can now use the [service control manager](https://docs.microsoft.com/en-us/windows/win32/services/service-control-manager).
Or, from the command line interface, you can run:
```cli
python .\examples\example_service.py start
```
To start the service in debug mode, run:
```cli
python .\examples\example_service.py debug
```
To verify that the service is working, make sure it is running, and then look into the Windows Event Viewer or, if it is running in debug mode, look at the standard output stream. You should see a message every 5 seconds.
### Remove the service
To remove the service, run:
```cli
python .\examples\example_service.py remove
```
## PyInstaller
To bundle the service into a convenient standalone executable, you can use PyInstaller.
### Install PyInstaller
Install [PyInstaller](https://www.pyinstaller.org/) inside your activated virtual environment:
```cli
pip install pyinstaller
```
### Create executable
To create a standalone (**one-file**) executable, use the `pyinstaller` command:
```cli
pyinstaller .\examples\example_service.py --clean --noupx --onefile --noconfirm --hidden-import=win32timezone
```
The resulting `example_service.exe` executable can be found in the `.\dist` directory.
You can use this executable with the same arguments and options as discussed above. For example, to install the service, run:
```cli
.\dist\example_service.exe install
```
You can also create a **one-folder** bundle. Because the executable does not have to be unpacked first in a temporary location, this has the advantage of making the service start faster.
```cli
pyinstaller .\examples\example_service.py --clean --noupx --onedir --noconfirm --hidden-import=win32timezone
```
In this case, the resulting executable can be found in the `dist\example_service` directory.
### Acknowledgement
This package utilizes the [pywin32](https://github.com/mhammond/pywin32) library, a collection of Python extensions for Windows. The maintenance and development of this library is credited to Mark Hammond and others in the Python community. Their contributions enable the development of Windows services in Python. Please note that the `windowsservice` package does not aim to replace `pywin32` or `win32serviceutil.ServiceFramework`, it's just here to make it a little bit easier to use.
Raw data
{
"_id": null,
"home_page": null,
"name": "windowsservice",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "multiprocessing, pyinstaller, python, pywin32, service, windows, windowsservice",
"author": null,
"author_email": "Hylke Postma <info@hylkepostma.nl>",
"download_url": "https://files.pythonhosted.org/packages/60/8e/3b4feda542c85e95e9e6d03e212336c64c75c7ced3000e14a16b1225954a/windowsservice-2.0.0.tar.gz",
"platform": null,
"description": "# windowsservice\n\n`windowsservice` is a Python package for building Windows services.\n\nThe key features are:\n\n- Easy to use\n- Support for [PyInstaller](https://www.pyinstaller.org/)\n- Support for [`multiprocessing`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.freeze_support)\n\n## Getting ready\n\nCreate and activate a virtual environment:\n\n```cli\npython -m venv venv\n```\n\n```cli\n.\\venv\\Scripts\\activate\n```\n\n## Installation\n\nInstall the windowsservice package from PyPI:\n\n```cli\npip install windowsservice\n```\n\nThe windowsservice package depends on [pywin32](https://github.com/mhammond/pywin32) created by Mark Hammond. Installing the windowsservice package also installs the pywin32 dependency.\n\n## Coding\n\n1. Import the `BaseService` class:\n\n ```python\n from windowsservice import BaseService\n ```\n\n2. Create a new subclass that inherits from the `BaseService` class.\n\n3. Define the following three class variables in the subclass:\n\n - `_svc_name_`: A unique identifier for your service.\n - `_svc_display_name_`: The name shown in the service control manager.\n - `_svc_description_`: The description shown in the service control manager.\n\n For example:\n\n ```python\n _svc_name_ = \"MyWindowsService\"\n _svc_display_name_ = \"My Windows Service\"\n _svc_description_ = \"This is my custom Windows service.\"\n ```\n\n4. Override the following methods in the subclass:\n\n - `start(self)`: This method is invoked when the service starts. Override\n this to add setup code, such as initializing a running condition.\n\n - `main(self)`: This method is invoked after `start`. Override this to\n create a run loop, typically based on a running condition.\n\n - `stop(self)`: This method is invoked when the service stops. Override\n this to add cleanup code, such as releasing resources or to invalidate a\n running condition.\n\n For example:\n\n ```python\n def start(self):\n self.is_running = True\n\n def main(self):\n while self.is_running:\n time.sleep(5)\n\n def stop(self):\n self.is_running = False\n ```\n\n5. Call the `parse_command_line` class method from the module's entry point. This handles command-line arguments for installing, starting, stopping,\nand debugging the service.\n\n For example:\n\n ```python\n if __name__ == \"__main__\":\n ExampleService.parse_command_line()\n ```\n\n### Examples\n\nBasic example ([example_service.py](examples/example_service.py)):\n\n```python\nimport time\n\nfrom windowsservice import BaseService, utils\n\n\nclass ExampleService(BaseService):\n \"\"\"Example Windows service in Python.\"\"\"\n\n _svc_name_ = \"PythonExampleWindowsService\"\n _svc_display_name_ = \"Python Example Windows Service\"\n _svc_description_ = \"Example Windows service in Python\"\n\n def start(self):\n self.is_running = True\n\n def main(self):\n while self.is_running:\n utils.log(f\"{self._svc_display_name_} is running...\")\n time.sleep(5)\n\n def stop(self):\n self.is_running = False\n\n\nif __name__ == \"__main__\":\n ExampleService.parse_command_line()\n```\n\nExample that demonstrates support for `multiprocessing` ([example_service_multiprocessing.py](examples/example_service_multiprocessing.py)):\n\n```python\nimport time\nfrom multiprocessing import Process, freeze_support\n\nfrom windowsservice import BaseService, utils\n\n\ndef stub_server():\n \"\"\"\n A function that simulates a server process hosted by the Windows service.\n\n This function logs a message every 5 seconds for a total of 100 times.\n \"\"\"\n for _ in range(100):\n utils.log(\"Hello from a process hosted by a Windows service...\")\n time.sleep(5)\n\n\nclass ExampleService(BaseService):\n \"\"\"Example Windows service in Python.\"\"\"\n\n _svc_name_ = \"PythonExampleWindowsService\"\n _svc_display_name_ = \"Python Example Windows Service\"\n _svc_description_ = \"Example Windows service in Python\"\n\n def start(self):\n self.server_process = Process(target=stub_server)\n\n def main(self):\n self.server_process.start()\n self.server_process.join()\n\n def stop(self):\n if self.server_process:\n self.server_process.terminate()\n\n\nif __name__ == \"__main__\":\n freeze_support()\n ExampleService.parse_command_line()\n```\n\n## Usage\n\nSome interactions with a Windows service may require administrative privileges, so you must use an elevated command line interface.\n\nAll arguments and options can be listed by invoking the module:\n\n```cli\npython .\\examples\\example_service.py\n```\n\n```stdout\nUsage: 'example_service.py [options] install|update|remove|start [...]|stop|restart [...]|debug [...]'\nOptions for 'install' and 'update' commands only:\n --username domain\\username : The Username the service is to run under\n --password password : The password for the username\n --startup [manual|auto|disabled|delayed] : How the service starts, default = manual\n --interactive : Allow the service to interact with the desktop.\n --perfmonini file: .ini file to use for registering performance monitor data\n --perfmondll file: .dll file to use when querying the service for\n performance data, default = perfmondata.dll\nOptions for 'start' and 'stop' commands only:\n --wait seconds: Wait for the service to actually start or stop.\n If you specify --wait with the 'stop' option, the service\n and all dependent services will be stopped, each waiting\n the specified period.\n```\n\n### Install the service\n\nIf you want to install the service from the `example_service.py` example, run:\n\n```cli\npython .\\examples\\example_service.py install\n```\n\n```stdout\nInstalling service PythonExampleWindowsService\nService installed\n```\n\nYou can also choose to install the service so that it will start automatically when Windows starts:\n\n```cli\npython .\\examples\\example_service.py --startup=auto install\n```\n\n### Start the service\n\nTo start/stop the service you can now use the [service control manager](https://docs.microsoft.com/en-us/windows/win32/services/service-control-manager).\n\nOr, from the command line interface, you can run:\n\n```cli\npython .\\examples\\example_service.py start\n```\n\nTo start the service in debug mode, run:\n\n```cli\npython .\\examples\\example_service.py debug\n```\n\nTo verify that the service is working, make sure it is running, and then look into the Windows Event Viewer or, if it is running in debug mode, look at the standard output stream. You should see a message every 5 seconds.\n\n### Remove the service\n\nTo remove the service, run:\n\n```cli\npython .\\examples\\example_service.py remove\n```\n\n## PyInstaller\n\nTo bundle the service into a convenient standalone executable, you can use PyInstaller.\n\n### Install PyInstaller\n\nInstall [PyInstaller](https://www.pyinstaller.org/) inside your activated virtual environment:\n\n```cli\npip install pyinstaller\n```\n\n### Create executable\n\nTo create a standalone (**one-file**) executable, use the `pyinstaller` command:\n\n```cli\npyinstaller .\\examples\\example_service.py --clean --noupx --onefile --noconfirm --hidden-import=win32timezone\n```\n\nThe resulting `example_service.exe` executable can be found in the `.\\dist` directory.\n\nYou can use this executable with the same arguments and options as discussed above. For example, to install the service, run:\n\n```cli\n.\\dist\\example_service.exe install\n```\n\nYou can also create a **one-folder** bundle. Because the executable does not have to be unpacked first in a temporary location, this has the advantage of making the service start faster.\n\n```cli\npyinstaller .\\examples\\example_service.py --clean --noupx --onedir --noconfirm --hidden-import=win32timezone\n```\n\nIn this case, the resulting executable can be found in the `dist\\example_service` directory.\n\n### Acknowledgement\n\nThis package utilizes the [pywin32](https://github.com/mhammond/pywin32) library, a collection of Python extensions for Windows. The maintenance and development of this library is credited to Mark Hammond and others in the Python community. Their contributions enable the development of Windows services in Python. Please note that the `windowsservice` package does not aim to replace `pywin32` or `win32serviceutil.ServiceFramework`, it's just here to make it a little bit easier to use.\n",
"bugtrack_url": null,
"license": null,
"summary": "A Python package for building Windows services.",
"version": "2.0.0",
"project_urls": {
"Documentation": "https://github.com/hylkepostma/windowsservice#windowsservice",
"Homepage": "https://github.com/hylkepostma/windowsservice"
},
"split_keywords": [
"multiprocessing",
" pyinstaller",
" python",
" pywin32",
" service",
" windows",
" windowsservice"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "627c3a01ef7b0e13f593fd42877c7e1f4f039a6d7dcb525a41929b1fbd514381",
"md5": "7de819e53fc5d5ffb13da4263cbc38d6",
"sha256": "be812a4c0f19fa508175f51964ee8f56bcc27059a6a7ccffac75de55d2848012"
},
"downloads": -1,
"filename": "windowsservice-2.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "7de819e53fc5d5ffb13da4263cbc38d6",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 7009,
"upload_time": "2024-03-24T15:43:30",
"upload_time_iso_8601": "2024-03-24T15:43:30.125907Z",
"url": "https://files.pythonhosted.org/packages/62/7c/3a01ef7b0e13f593fd42877c7e1f4f039a6d7dcb525a41929b1fbd514381/windowsservice-2.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "608e3b4feda542c85e95e9e6d03e212336c64c75c7ced3000e14a16b1225954a",
"md5": "fb061a64d79e584b322e630de11c5e6b",
"sha256": "6a83d025f0afbc33740a172fefd1f4a833a6fe3287ec17f3a205f23dbc2fecc3"
},
"downloads": -1,
"filename": "windowsservice-2.0.0.tar.gz",
"has_sig": false,
"md5_digest": "fb061a64d79e584b322e630de11c5e6b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 8762,
"upload_time": "2024-03-24T15:43:31",
"upload_time_iso_8601": "2024-03-24T15:43:31.391746Z",
"url": "https://files.pythonhosted.org/packages/60/8e/3b4feda542c85e95e9e6d03e212336c64c75c7ced3000e14a16b1225954a/windowsservice-2.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-03-24 15:43:31",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "hylkepostma",
"github_project": "windowsservice#windowsservice",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "windowsservice"
}