diff --git a/README.md b/README.md index 9f10d09..1545b7e 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,18 @@
+ + Logo + +

Thread

A python threading library extension
+ Explore the docs » +
+
Report Bug · Request Feature @@ -31,9 +38,10 @@ ## About The Project -> Wraps around the python threading library and provides extra functionality -Strictly type-safe +[![Social Card][socialcard]](https://thread.ngjx.org) + +Strictly type-safe and Wraps around the python threading library and provides extra functionality Fully compatible with the threading library, this project hopes to provide a more out-of-the-box solution with multi-threaded processing and fetching values from a completed thread, etc. @@ -166,3 +174,4 @@ Project Link: [https://github.com/python-thread/thread](https://github.com/pytho [stars-url]: https://github.com/python-thread/thread/stargazers [license-shield]: https://img.shields.io/github/license/python-thread/thread.svg?style=for-the-badge [license-url]: https://github.com/python-thread/thread/blob/master/LICENSE.txt +[socialcard]: images/socialcard.jpg diff --git a/docs/command-line.md b/docs/command-line.md deleted file mode 100644 index d61a6ad..0000000 --- a/docs/command-line.md +++ /dev/null @@ -1,152 +0,0 @@ -# CLI Documentation - -I will lay out how to use the comamnd line! - -
-

- Jump to - - -
- - -Don't have the thread library? [See here](./getting-started.md) for installing thread - ---- - -## Getting started - -Try running the help command! -```sh -$ thread -h/--help -``` - -![Help Command Output](images/cli_help.png) - -
- - -## Log levels - -Thread CLI uses the [python logging library.](https://docs.python.org/3/library/logging.html) - --------------- -| Name | Level | -| :-----: | :---: | -| NOTSET | 0 | -| DEBUG | 10 | -| INFO | 20 | -| WARN | 30 | -| ERROR | 40 | -| CRITICAL | 50 | - -
- - -## Commands - -List of commands - -
- - -### Documentation (thread docs) - -```sh -$ thread docs -``` -Ran with no arguments and options, this command will attempt to open your brower to this MD file! -
-If unable, will instead print out the link. - -
- - -### Help (thread help) - -```sh -$ thread help -``` -Ran with no arguments and options, this command will attempt to open your brower to the issue tracker! -
-If unable, will instead print out the link. - -
- - -### Report (thread report) - -```sh -$ thread report -``` -Ran with no arguments and options, this command will attempt to open your brower to this MD file! -
-If unable, will instead print out the link. - -
- - -### Configuration (thread config ...) - -```sh -$ thread config -``` -Comming soon. - - -
- - -### Parallel Processing (thread process ...) - -```sh -$ thread process -``` -Invokes the [parallel processing class](parallel-processing.md#importing-the-class)
-
- -> **Help Command Output** - -![Process Command Help Output](images/process_help.png) - -> **Example Usage** -```sh -$ thread process 'lambda x: x**2' '[ i for i in range(1000) ]' -=> Writes to "output.json" every number from 0 to 1000 squared. - -$ thread process home.Downloads.clean_data:clean ./dataset.csv -t 20 -=> The same as: - from home.Downloads.clean_data import clean - dataset = open('./dataset.csv', 'r') - - newProcess = ParallelProcess( - target = clean, - dataset = dataset, - max_threads = 20 - ) - newProcess.start() - dataset.close() - - prints or writes to file the result -``` - -
- - -Now you know how to use the [`Thread CLI`](#cli-documentation)! - -[See here](./parallel-processing.md) for how to using the `thread.ParallelProcessing` class! diff --git a/docs/configuration.md b/docs/configuration.md deleted file mode 100644 index 0ea6af2..0000000 --- a/docs/configuration.md +++ /dev/null @@ -1,43 +0,0 @@ -# Thread Configuration Documentation - -I will lay out the configuration options! - -
-
- Jump to - -
- - -Don't have the thread library? [See here](./getting-started.md) for installing thread - ---- - -## Importing the class - -```py -from thread import Thread -``` - -
- - -## Graceful Exiting - -```py -from thread import Settings - -# Enable/Disable graceful exiting -Settings.set_graceful_exit(True) -Settings.set_graceful_exit(False) -``` - -
- - -Now you know the configuration options available! - -[See here](./parallel-processing.md) for how to using the `thread.ParallelProcessing` class! diff --git a/docs/exceptions.md b/docs/exceptions.md deleted file mode 100644 index e76362b..0000000 --- a/docs/exceptions.md +++ /dev/null @@ -1,166 +0,0 @@ -# Exceptions - -> [!NOTE] -> Exceptions from Python's `threading` module are not included - -
-
- Jump to - -
- - -Don't have the thread library? [See here](./getting-started.md) for installing thread - ---- - -## Ignoring exceptions - -When initializing a thread, you can parse a [**suppress_errors**](./threading.md#parameters) bool.
-By default it is false, but if set to true, exceptions will not be propagated but just stored within `Thread._errors` - -When initializing a thread, you can parse a [**ignore_errors**](./threading.md#parameters) sequence.
-By default it is an empty tuple.
-Ignored errors will not be propagated and not stored within `Thread._errors` - -
- -### Example -```py -from thread import Thread - -def bad_function(): - raise RuntimeError('>:cc') - - -# Normal behaviour -thread0 = Thread( - target = bad_function -) -thread0.start() -thread0.join() -# exit(1) RuntimeError(':<<') - - -# Suppress exceptions -thread1 = Thread( - target = bad_function, - suppress_errors = True -) -thread1.start() -thread1.join() -print(thread1._errors) # list[RuntimeError('>:cc')] - - -# Ignore error -thread2 = Thread( - target = bad_function, - ignore_errors = [RuntimeError] -) -thread2.start() -thread2.join() -print(thread2._errors) # list[] - - -# Non-ignored error -thread3 = Thread( - target = bad_function, - ignore_errors = [ValueError] -) -thread3.start() -thread3.join() -# exit(1) RuntimeError(':<<') - - -# Non-ignored error with suppressing -thread4 = Thread( - target = bad_function, - ignore_errors = [ValueError], - suppress_errors = True -) -thread4.start() -thread4.join() -print(thread4._errors) # list[RuntimeError(':<<')] - - -# Ignored error with suppressing -thread5 = Thread( - target = bad_function, - ignore_errors = [RuntimeError], - suppress_errors = True -) -thread5.start() -thread5.join() -print(thread5._errors) # list[] -``` - -
- - -## Exceptions - -The list of exceptions that can be thrown - -
- - -### ThreadErrorBase - -This is the base exception class that all exceptions inherit from - -
- - -### ThreadStillRunningError - -This is raised when you attempt to invoke a method which requries the thread to not be running, but is running. -> You can wait for the thread to terminate with [**Thread.join()**](./threading.md#methods) before invoking the method - -> You can check if the thread is running with [**Thread.is_alive()**](threading.md#methods) before invoking the method - -
- - -### ThreadNotRunningError - -This is raised when you attempt to invoke a method which requires the thread to be running, but isn't -> You can run the thread with [**Thread.start()**](threading.md#methods) before invoking the method - -
- - -### ThreadNotInitializedError - -This is raised when you attempt to invoke a method which requires the thread to be initialized, but isn't -> You can initialize and start the thread with [**Thread.start()**](threading.md#methods) before invoking the method - -
- - -### HookRuntimeError - -This is raised when hooks raise an exception
-Conforms to when thread is ran with errors suppressed or ignored - -Example traceback -```text -HookRuntimeError: Encountered runtime errors in hooks - -1. my_function ->>>>>>>>>> -/usr/home/proj/main.py:50 -ZeroDivisionError: -<<<<<<<<<< - -2. my_otherfunction ->>>>>>>>>> -ImportError: -<<<<<<<<<< -``` - -
- -[See here](./threading.md) for how to using the `thread.Thread` class! diff --git a/docs/getting-started.md b/docs/getting-started.md deleted file mode 100644 index b55da92..0000000 --- a/docs/getting-started.md +++ /dev/null @@ -1,51 +0,0 @@ -# Getting started with thread - -Thanks for using thread! I hope you find it useful for your projects. - -Here's to you get started. - ---- - -## Prerequisites - -* Python 3.9+ - - -
- - -## Installing - -### From pip (Recommended) -```sh -pip install thread -``` - -### Building from source (Not Recommended) -```sh -# Clone this repository -git clone https://github.com/python-thread/thread - -# Install dependencies -pip install poetry - -# Build the distribution -python3 -m poetry build - -# Install the distribution -pip install -e . -``` - -
- - -## Importing thread - -Import thread into your .py file -```py -import thread -``` - -Now you have successfully installed thread! - -[See here](./threading.md) for how to using the `thread.Thread` class! diff --git a/docs/images/cli_help.png b/docs/images/cli_help.png deleted file mode 100644 index ea18c50..0000000 Binary files a/docs/images/cli_help.png and /dev/null differ diff --git a/docs/images/process_help.png b/docs/images/process_help.png deleted file mode 100644 index 0ae3906..0000000 Binary files a/docs/images/process_help.png and /dev/null differ diff --git a/docs/parallel-processing.md b/docs/parallel-processing.md deleted file mode 100644 index 72cd5d7..0000000 --- a/docs/parallel-processing.md +++ /dev/null @@ -1,151 +0,0 @@ -# Parallel Processing Documentation - -I will lay out how to use the `thread.ParallelProcessing` class! - -
-
- Jump to - -
- - -Don't have the thread library? [See here](./getting-started.md) for installing thread - ---- - -## Importing the class - -```py -from thread import ParallelProcessing -``` - -
- - -## How does it work? - -Parallel Processing works best by optimizing data processing with large datasets. - -What it does: -```py -dataset = [1, 2, 3, ..., 2e10] - -# Splits into chunks as evenly as possible -# thread_count = min(max_threads, len(dataset)) -# n == len(chunks) == len(thread_count) -chunks = [[1, 2, 3, ...], [50, 51, 52, ...], ...] - -# Initialize and run n threads -# each thread handles 1 chunk of data and parses it into the function - -# processed data is arranged back in order - -# processed data is returned as a list[Data_Out] -``` - -
- - -## Initializing a parallel process - -A simple example -```py -def my_data_processor(Data_In) -> Data_Out: ... - -# Reccommended way -my_processor = ParallelProcessing( - function = my_data_processor, - dataset = [i in range(0, n)] -) - -# OR -# Not the reccommended way -my_processor = ParallelProcessing(my_data_processor, [i in range(0, n)]) -``` - -It can be ran by invoking the `start()` method -```py -my_processor.start() -``` - -> [!NOTE] -> The **threading.ParallelProcessing()** class from python will only be initialized when **start()** is invoked - -
- - -### Parameters - -* function : (DataProcessor, dataset, *args, **kwargs) -> Any | Data_Out - > This should be a function that takes in a dataset and/or anything and returns Data_Out and/or anything - -* dataset : Sequence[Data_In] = () - > This should be an interable sequence of arguments parsed to the `DataProcessor` function
- > (e.g. tuple('foo', 'bar')) - -* *overflow_args : Overflow_In - > These are arguments parsed to [**thread.Thread**](./threading.md#parameters) - -* **overflow_kwargs : Overflow_In - > These are arguments parsed to [**thread.Thread**](./threading.md#parameters)
- > [!NOTE]
- > If `args` is present, then it will automatically be removed from kwargs and joined with `overflow_args` - -* **Raises** AssertionError: max_threads is invalid - -
- - -### Attributes - -These are attributes of [`ParallelProcessing`](#importing-the-class) class - -* results : List[Data_Out] - > The result value
- > **Raises** [`ThreadNotInitializedError`](./exceptions.md#threadNotInitializedError)
- > **Raises** [`ThreadNotRunningError`](./exceptions.md#threadnotrunningerror)
- > **Raises** [`ThreadStillRunningError`](./exceptions.md#threadStillRunningError) - -
- - -### Methods - -These are methods of [`ParallelProcessing`](#importing-the-class) class - -* start : () -> None - > Initializes the threads and starts it
- > **Raises** [`ThreadStillRunningError`](./exceptions.md#threadStillRunningError) - -* is_alive : () -> bool - > Indicates whether the thread is still alive
- > **Raises** [`ThreadNotInitializedError`](./exceptions.md#threadNotInitializedError) - -* get_return_values : () -> Data_Out - > Halts the current thread execution until the thread completes - -* join : () -> JoinTerminatedStatus - > Halts the current thread execution until a thread completes or exceeds the timeout
- > **Raises** [`ThreadNotInitializedError`](./exceptions.md#threadNotInitializedError)
- > **Raises** [`ThreadNotRunningError`](./exceptions.md#threadnotrunningerror) - -* kill : (yielding: bool = False, timeout: float = 5) -> bool - > Schedules the thread to be killed
- > If yielding is True, it halts the current thread execution until the thread is killed or the timeout is exceeded
- > **Raises** [`ThreadNotInitializedError`](./exceptions.md#threadnotinitializederror)
- > **Raises** [`ThreadNotRunningError`](./exceptions.md#threadnotrunningerror)
- > [!NOTE]
- > This only schedules the thread to be killed, and does not immediately kill the thread - -
- - -Now you know how to use the [`ParallelProcessing`](#importing-the-class) class! - -[See here](./parallel-processing.md) for how to using the `thread.ParallelProcessing` class! diff --git a/docs/threading.md b/docs/threading.md deleted file mode 100644 index 0e1e675..0000000 --- a/docs/threading.md +++ /dev/null @@ -1,180 +0,0 @@ -# Thread Class Documentation - -I will lay out how to use the `thread.Thread` class! - -
-
- Jump to - -
- - -Don't have the thread library? [See here](./getting-started.md) for installing thread - ---- - -## Importing the class - -```py -from thread import Thread -``` - -
- - -## Initializing a thread - -A simple thread can be prepared to be initialized with this -```py -def my_target(): ... - -# Reccommended way -my_thread = Thread( - target = my_target -) - -# OR -# Not the reccommended way -my_thread = Thread(my_target) -``` - -A thread can be ran by invoking the `start()` method -```py -my_thread.start() -``` - -
- - -### Parameters - -* target : (Data_In, *args, **kwargs) -> Any | Data_Out - > This should be a function that takes in anything and returns anything - -* args : Sequence[Data_In] = () - > This should be an interable sequence of arguments parsed to the `target` function
- > (e.g. tuple('foo', 'bar')) - -* kwargs : Mapping[str, Data_In] = {} - > This should be the kwargs pased to the `target` function
- > (e.g. dict(foo = 'bar')) - -* ignore_errors : Sequence[type[Exception]] = () - > This should be an interable sequence of all exceptions to ignore.
- > To ignore all exceptions, parse tuple(Exception) - -* suppress_errors : bool = False - > This should be a boolean indicating whether exceptions will be raised.
- > If true, exceptions will only write to internal `errors` property
- > If false, exceptions will propagate if not ignored - -* name : Optional[str] = None - > This is an argument parsed to `threading.Thread` - -* daemon : bool = False - > This is an argument parsed to `threading.Thread` - -* group : None = None - > This is an argument parsed to `threading.Thread`
- > [!NOTE]
- > This does nothing - -* *overflow_args : Overflow_In - > These are arguments parsed to `threading.Thread` - -* **overflow_kwargs : Overflow_In - > These are arguments parsed to `threading.Thread` - -
- - -### Attributes - -These are attributes of [`Thread`](#importing-the-class) class - -* result : Data_Out - > The result value of the thread - > **Raises** [`ThreadNotInitializedError`](./exceptions.md#threadNotInitializedError)
- > **Raises** [`ThreadNotRunningError`](./exceptions.md#threadnotrunningerror)
- > **Raises** [`ThreadStillRunningError`](./exceptions.md#threadStillRunningError) - -* status : str - > The current status of the thread - -
- - -### Methods - -These are methods of [`Thread`](#importing-the-class) class - -* start : () -> None - > Initializes the thread and starts it
- > **Raises** [`ThreadStillRunningError`](./exceptions.md#threadStillRunningError) - -* is_alive : () -> bool - > Indicates whether the thread is still alive
- > **Raises** [`ThreadNotInitializedError`](./exceptions.md#threadNotInitializedError) - -* add_hook : ((Data_Out) -> Any | None) -> None - > Hooks will be automatically invoked after a thread successfully completes, parsing the return value as the first argument
- > **Raises** [`ThreadNotInitializedError`](./exceptions.md#threadNotInitializedError)
- > **Raises** [`ThreadNotRunningError`](./exceptions.md#threadnotrunningerror) - -* get_return_value : () -> Data_Out - > Halts the current thread execution until the thread completes - -* join : () -> JoinTerminatedStatus - > Halts the current thread execution until a thread completes or exceeds the timeout
- > **Raises** [`ThreadNotInitializedError`](./exceptions.md#threadNotInitializedError)
- > **Raises** [`ThreadNotRunningError`](./exceptions.md#threadnotrunningerror) - -* kill : (yielding: bool = False, timeout: float = 5) -> bool - > Schedules the thread to be killed
- > If yielding is True, it halts the current thread execution until the thread is killed or the timeout is exceeded
- > **Raises** [`ThreadNotInitializedError`](./exceptions.md#threadnotinitializederror)
- > **Raises** [`ThreadNotRunningError`](./exceptions.md#threadnotrunningerror)
- > [!NOTE]
- > This only schedules the thread to be killed, and does not immediately kill the thread - -
- - -## Behviours - -These are a list of thread behvaiours - -### Killing Threads - Introduced in v0.1.2 - -While preferably not utilized, we do support killing threads.
-We mark a thread to be killed, and will only be killed when the thread invokes `sys.settrace()`. - -> [!IMPORTANT]
-> This means that if your `target` has a long `time.wait()` call, it will only be killed after it moves onto the next line. - -
- -Want an alternative? Learn about [Daemonized Threads!](https://www.geeksforgeeks.org/python-daemon-threads/) - -
- - -### Gracefull Exiting - Introduced in v0.1.2 - -When the program is abruptly stopped with `CTRL+C` for example, active threads will now attempt to gracefully kill itself.
- -This is not to be an "end-all be-all" for managing threads. You should still try to properly exit a thread before abruptly exiting the program, or utilize a `Daemonized Thread`. - -
- - -Now you know how to use the [`Thread`](#importing-the-class) class! - -[See here](./parallel-processing.md) for how to using the `thread.ParallelProcessing` class! diff --git a/images/logo.svg b/images/logo.svg new file mode 100644 index 0000000..2d647d0 --- /dev/null +++ b/images/logo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/images/socialcard.jpg b/images/socialcard.jpg new file mode 100644 index 0000000..8a99961 Binary files /dev/null and b/images/socialcard.jpg differ