Skip to content

Commit

Permalink
🎉 initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
nazmulnnb committed Aug 25, 2022
1 parent 74bd510 commit 15ed128
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 0 deletions.
54 changes: 54 additions & 0 deletions processpy/PManager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import multiprocessing
from typing import Any, Callable, Dict

class ProcessManager(object):
def __init__(self, func: Callable, kill_previous: Any = False, concurrent_running: Any = False) -> None:
"""ProcessManager initializer
Args:
func (Callable): function to be executed
kill_previous (Any, optional): Do you want to kill previous process? if not, new process won't be executed if concurrent is set to False.
If True, it will kill the unfinished previous process and start the new one.
Defaults to False.
concurrent_running (Any, optional): If True, all the process of the function will run concurrently. Defaults to False.
Raises:
ValueError: kill_previous and concurrent_running can't be used together. If you kill previous, what do you wanna run concurrently?
"""
if concurrent_running and kill_previous:
raise ValueError("Using kill_previous is not allowed while using concurrent_running.")
self.func = func
self.kill_previous = kill_previous
self.concurrent_running = concurrent_running

"""
We really don't need to keep track of multiple process. We will need that only when concurrent_running is true
and we don't need to terminate any process. So, no use of the process ids.
In the future, all the process management will be added if needed.
"""
self.process = None

def run(self, kwargs: Dict = None) -> None:
""" create a new process of the function
Args:
kwargs (Dict, optional): arguments to be passed to your function. Defaults to None.
"""
if self.concurrent_running == False and self.process is not None and self.process.is_alive():
if self.kill_previous:
self.kill()
else:
return

if kwargs == None:
self.process = multiprocessing.Process(target=self.func)
else:
self.process = multiprocessing.Process(target=self.func, kwargs=kwargs)
self.process.daemon = True
self.process.start()

def kill(self) -> None:
"""terminate the currently running process
"""
if self.process is not None and self.process.is_alive:
self.process.terminate()
3 changes: 3 additions & 0 deletions processpy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .PManager import ProcessManager

__all__ = ["ProcessManager"]
32 changes: 32 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[tool.poetry]
name = "processpy"
version = "0.1.0"
description = "Python Process Manager"
authors = [
"Nazmul Hasan <[email protected]>"
]

license = "MIT"
readme = "README.md"
repository = "https://github.com/nazmulnnb/processpy"

classifiers = [
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3 :: Only',
]

[tool.poetry.dependencies]
python = "^3.6"

[tool.poetry.dev-dependencies]
pytest = "^7.1"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
80 changes: 80 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Python Process Manager (processpy)


processpy is simple process manager for python.
If you want to run multiple process for the same function, this tool is for you.

* You can run multiple process of the same function concurrently.
* You can choose to kill previous running process before running a new process of the same function.
* You can choose to ignore new process of the same function if it's already running.


## Installation

```bash
pip install processpy
```

## Example (No concurrency and no previous kill)

```python
from processpy import ProcessManager
import time

def sum(a, b):
time.sleep(30)
print(a+b)

sum_process = ProcessManager(sum, kill_previous=False, concurrent_running=False)
sum_process.run({'a': 10, 'b': 20})
time.sleep(5)

"""
The following will not run. Because concurrent run is false and kill previous is also false. So, it will simply return with doing nothing and let the previous run.
"""
sum_process.run({'a': 10, 'b': 20})

```

## Example (No concurrency but with previous kill)
```python
from processpy import ProcessManager
import time

def sum(a, b):
time.sleep(30)
print(a+b)

sum_process = ProcessManager(sum, kill_previous=True, concurrent_running=False)
sum_process.run({'a': 10, 'b': 20})
time.sleep(5)

"""
The following will kill the previous unfinished process and run. Because concurrent run is false and kill previous is True. So, it will simply kill the previous unfinished process. If previous one is already finished, nothing to kill.
"""
sum_process.run({'a': 10, 'b': 20})
```

## Example (with concurrency)
```python
from processpy import ProcessManager
import time

def sum(a, b):
time.sleep(30)
print(a+b)

sum_process = ProcessManager(sum, concurrent_running=True)
sum_process.run({'a': 10, 'b': 20})
time.sleep(5)

"""
The following will run alongside of the previous process.
"""
sum_process.run({'a': 10, 'b': 20})
```

## You can also kill the running process (if concurrent_running=False )
```python
sub_process.kill()
```

0 comments on commit 15ed128

Please sign in to comment.