streams.py


Namestreams.py JSON
Version 1.2.1 PyPI version JSON
download
home_pagehttps://github.com/PickwickSoft/pystreamapi
SummaryA stream library for Python inspired by Java Stream API
upload_time2024-02-23 20:47:20
maintainer
docs_urlNone
authorStefan Garlonta
requires_python>=3.7,<4.0
licenseGPL-3.0-or-later
keywords streams parallel data
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ![Header](https://raw.githubusercontent.com/PickwickSoft/pystreamapi/main/assets/header.png)

<h1 align="center">PyStreamAPI</h1>

<p align="center">
  <a href="https://deepsource.io/gh/PickwickSoft/pystreamapi/?ref=repository-badge"><img src="https://deepsource.io/gh/PickwickSoft/pystreamapi.svg/?label=active+issues&show_trend=true&token=7lV9pH1U-N1oId03M-XKZL5B"  alt="DeepSource"/></a>
  <a href="https://github.com/PickwickSoft/pystreamapi/actions/workflows/unittests.yml"><img src="https://github.com/PickwickSoft/pystreamapi/actions/workflows/unittests.yml/badge.svg"  alt="Tests"/></a>
  <a href="https://github.com/PickwickSoft/pystreamapi/actions/workflows/pylint.yml"><img src="https://github.com/PickwickSoft/pystreamapi/actions/workflows/pylint.yml/badge.svg"  alt="Pylint"/></a>
  <a href="https://sonarcloud.io/summary/new_code?id=PickwickSoft_pystreamapi"><img src="https://sonarcloud.io/api/project_badges/measure?project=PickwickSoft_pystreamapi&metric=alert_status"  alt="Quality Gate"/></a>
  <a href="https://sonarcloud.io/summary/new_code?id=PickwickSoft_pystreamapi"><img src="https://sonarcloud.io/api/project_badges/measure?project=PickwickSoft_pystreamapi&metric=coverage"  alt="Coverage"/></a>
  <a href="https://pypi.org/project/streams-py/"><img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/streams.py"></a>
  <a href="https://pypi.org/project/streams-py/"><img alt="PyPI" src="https://img.shields.io/pypi/v/streams.py"></a>
</p>

PyStreamAPI is a Python stream library that draws inspiration from the Java Stream API. 
Although it closely mirrors the Java API, PyStreamAPI adds some innovative features to make streams in Python even more 
innovative, declarative and easy to use.

PyStreamAPI offers both sequential and parallel streams and utilizes lazy execution.

Now you might be wondering why another library when there are already a few implementations? Well, here are a few advantages of this particular implementation:

* It provides both sequential and parallel streams.
* Lazy execution is supported, enhancing performance.
* It boasts high speed and efficiency.
* The implementation achieves 100% test coverage.
* It follows Pythonic principles, resulting in clean and readable code.
* It adds some cool innovative features such as conditions or error handling and an even more declarative look.
* It provides loaders for various data sources such as CSV, JSON and XML files.

Let's take a look at a small example:

```python
from pystreamapi import Stream

Stream.of([" ", '3', None, "2", 1, ""]) \
    .filter(lambda x: x is not None) \
    .map(str) \
    .map(lambda x: x.strip()) \
    .filter(lambda x: len(x) > 0) \
    .map(int) \
    .sorted() \
    .for_each(print) # Output: 1 2 3
```

And here's the equivalent code in Java:

```java
Object[] words = { " ", '3', null, "2", 1, "" };
Arrays.stream( words )
      .filter( Objects::nonNull )
      .map( Objects::toString )
      .map( String::trim )
      .filter( s -> ! s.isEmpty() )
      .map( Integer::parseInt )
      .sorted()
      .forEach( System.out::println );  // Output: 1 2 3
```

## What is a Stream?

A `Stream` is a powerful abstraction for processing sequences of data in a functional and declarative manner. It enables efficient and concise data manipulation and transformation.

Similar to its counterparts in Java and Kotlin, a Stream represents a pipeline of operations that can be applied to a collection or any iterable data source. It allows developers to express complex data processing logic using a combination of high-level operations, promoting code reusability and readability.

With Streams, you can perform a wide range of operations on your data, such as filtering elements, transforming values, aggregating results, sorting, and more. These operations can be seamlessly chained together to form a processing pipeline, where each operation processes the data and passes it on to the next operation.

One of the key benefits of Stream is lazy evaluation. This means that the operations are executed only when the result is actually needed, optimizing resource usage and enabling efficient processing of large or infinite datasets.

Furthermore, Stream supports both sequential and parallel execution. This allows you to leverage parallel processing capabilities when dealing with computationally intensive tasks or large amounts of data, significantly improving performance.

`pystreamapi.Stream` represents a stream that facilitates the execution of one or more operations. Stream operations can be categorized as either intermediate or terminal.

Terminal operations return a result of a specific type, while intermediate operations return the stream itself, enabling method chaining for multi-step operations.

Let's examine an example using Stream:

```python
Stream.of([" ", '3', None, "2", 1, ""]) \
    .filter(lambda x: x is not None) \ # Intermediate operation
    .map(str) \ # Intermediate operation
    .map(lambda x: x.strip()) \ # Intermediate operation
    .filter(lambda x: len(x) > 0) \ # Intermediate operation
    .map(int) \ # Intermediate operation
    .sorted() \ # Intermediate operation
    .for_each(print) # Terminal Operation (Output: 1 2 3)
```

Operations can be performed on a stream either in parallel or sequentially. A parallel stream executes operations concurrently, while a sequential stream processes operations in order.

Considering the above characteristics, a stream can be defined as follows:

* It is not a data structure itself but operates on existing data structures.
* It does not provide indexed access like traditional collections.
* It is designed to work seamlessly with lambda functions, enabling concise and expressive code.
* It facilitates easy aggregation of results into lists, tuples, or sets.
* It can be parallelized, allowing for concurrent execution of operations to improve performance.
* It employs lazy evaluation, executing operations only when necessary.

## Use conditions to speed up your workflow!

![Conditions](https://raw.githubusercontent.com/PickwickSoft/pystreamapi/main/assets/conditions.png)

Conditions provide a convenient means for performing logical operations within your Stream, such as using `filter()`, `take_while()`, `drop_while()`, and more. With PyStreamAPI, you have access to a staggering 111 diverse conditions that enable you to process various data types including strings, types, numbers, and dates. Additionally, PyStreamAPI offers a powerful combiner that allows you to effortlessly combine multiple conditions, facilitating the implementation of highly intricate pipelines.

## Error handling: Work with data that you don't know
PyStreamAPI offers a powerful error handling mechanism that allows you to handle errors in a declarative manner. This is especially useful when working with data that you don't know.

PyStreamAPI offers three different error levels:
- `ErrorLevel.RAISE`: This is the default error level. It will raise an exception if an error occurs.
- `ErrorLevel.IGNORE`: This error level will ignore any errors that occur and won't inform you.
- `ErrorLevel.WARN`: This error level will warn you about any errors that occur and logs them as a warning with default logger.


This is how you can use them:

```python
from pystreamapi import Stream, ErrorLevel

Stream.of([" ", '3', None, "2", 1, ""]) \
    .error_level(ErrorLevel.IGNORE) \
    .map_to_int() \
    .error_level(ErrorLevel.RAISE) \
    .sorted() \
    .for_each(print) # Output: 1 2 3
```

The code above will ignore all errors that occur during mapping to int and will just skip the elements.

For more details on how to use error handling, please refer to the documentation.

## Get started: Installation

To start using PyStreamAPI just install the module with this command:

```bash
pip install streams.py  
```

Afterward, you can import it with:

```python
from pystreamapi import Stream
```

:tada: PyStreamAPI is now ready to process your data

## Build a new Stream

PyStreamAPI offers two types of Streams, both of which are available in either sequential or parallel versions:

- (Normal) `Stream`: Offers operations that do not depend on the types. The same functionality as Streams in other programming languages.

- `NumericStream`: This stream extends the capabilities of the default stream by 
  introducing numerical operations. It is designed specifically for use 
  with numerical data sources and can only be applied to such data.

There are a few factory methods that create new Streams:

```python
Stream.of([1, 2, 3]) # Can return a sequential or a parallel stream
```

Using the `of()` method will let the implementation decide which `Stream` to use. If the source is numerical, a `NumericStream` is created.

> **Note** 
> 
> Currently, it always returns a `SequentialStream` or a `SequentialNumericStream`

---

```python
Stream.parallel_of([1, 2, 3]) # Returns a parallel stream (Either normal or numeric)
```

---

```python
Stream.sequential_of([1, 2, 3]) # Returns a sequential stream (Either normal or numeric)
```

---

```python
# Can return a sequential or a parallel stream (Either normal or numeric)
Stream.of_noneable([1, 2, 3])

# Returns a sequential or a parallel, empty stream (Either normal or numeric)
Stream.of_noneable(None) 
```

If the source is `None`, you get an empty `Stream`

---

```python
Stream.iterate(0, lambda n: n + 2)
```

Creates a Stream of an infinite Iterator created by iterative application of a
function f to an initial element seed, producing a Stream consisting of seed,
f(seed), f(f(seed)), etc.

> **Note**
> Do not forget to limit the stream with `.limit()`

---

```python
Stream.concat(Stream.of([1, 2]), Stream.of([3, 4])) 
# Like Stream.of([1, 2, 3, 4])
```

Creates a new Stream from multiple Streams. Order doesn't change.

## Use loaders: Load data from CSV, JSON and XML files in just one line

PyStreamAPI offers a convenient way to load data from CSV, JSON and XML files. Like that you can start processing your
files right away without having to worry about reading and parsing the files.

You can import the loaders with:

```python
from pystreamapi.loaders import csv, json, xml
```
Now you can use the loaders directly when creating your Stream:

For CSV:

```python
Stream.of(csv("data.csv", delimiter=";")) \
    .map(lambda x: x.attr1) \
    .for_each(print)
```

For JSON:
```python
Stream.of(json("data.json")) \
    .map(lambda x: x.attr1) \
    .for_each(print)
```

You can access the attributes of the data structures directly like you would do with a normal object.

For XML:

In order to use the XML loader, you need to install the optional xml dependency:

```bash
pip install streams.py[xml_loader]
```

Afterward, you can use the XML loader like this:

```python
Stream.of(xml("data.xml"))
  .map(lambda x: x.attr1)
  .for_each(print)
```

The access to the attributes is using a node path syntax. For more details on how to use the node path syntax, please
refer to the [documentation](https://pystreamapi.pickwicksoft.org/reference/data-loaders).

## API Reference
For a more detailed documentation view the docs on GitBook: [PyStreamAPI Docs](https://pystreamapi.pickwicksoft.org/)

## Complex Examples

#### Get all numbers from list of different types. Use parallelization.

```python
Stream.parallel_of([" ", '3', None, "2", 1, ""]) \
    .filter(lambda x: x is not None) \
    .map(str) \
    .map(lambda x: x.strip()) \
    .filter(lambda x: len(x) > 0) \
    .map(int) \
    .sorted()\
    .for_each(print) # 1 2 3
```

#### Generate a Stream of 10 Fibonacci numbers

```python
def fib():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

Stream.of(fib()) \
    .limit(10) \
    .for_each(print) # 0 1 1 2 3 5 8 13 21 34
```

## Performance

Note that parallel Streams are not always faster than sequential Streams. Especially when the number of elements is small, we can expect sequential Streams to be faster.

## Bug Reports

Bug reports can be submitted in GitHub's [issue tracker](https://github.com/PickwickSoft/pystreamapi/issues).

## Contributing

Contributions are welcome! Please submit a pull request or open an issue.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/PickwickSoft/pystreamapi",
    "name": "streams.py",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7,<4.0",
    "maintainer_email": "",
    "keywords": "streams,parallel,data",
    "author": "Stefan Garlonta",
    "author_email": "stefan@pickwicksoft.org",
    "download_url": "https://files.pythonhosted.org/packages/8c/2f/3a2374cb6cb24596ee8dfe64423ccc18df6be7471c9e297d3a914639313a/streams_py-1.2.1.tar.gz",
    "platform": null,
    "description": "![Header](https://raw.githubusercontent.com/PickwickSoft/pystreamapi/main/assets/header.png)\n\n<h1 align=\"center\">PyStreamAPI</h1>\n\n<p align=\"center\">\n  <a href=\"https://deepsource.io/gh/PickwickSoft/pystreamapi/?ref=repository-badge\"><img src=\"https://deepsource.io/gh/PickwickSoft/pystreamapi.svg/?label=active+issues&show_trend=true&token=7lV9pH1U-N1oId03M-XKZL5B\"  alt=\"DeepSource\"/></a>\n  <a href=\"https://github.com/PickwickSoft/pystreamapi/actions/workflows/unittests.yml\"><img src=\"https://github.com/PickwickSoft/pystreamapi/actions/workflows/unittests.yml/badge.svg\"  alt=\"Tests\"/></a>\n  <a href=\"https://github.com/PickwickSoft/pystreamapi/actions/workflows/pylint.yml\"><img src=\"https://github.com/PickwickSoft/pystreamapi/actions/workflows/pylint.yml/badge.svg\"  alt=\"Pylint\"/></a>\n  <a href=\"https://sonarcloud.io/summary/new_code?id=PickwickSoft_pystreamapi\"><img src=\"https://sonarcloud.io/api/project_badges/measure?project=PickwickSoft_pystreamapi&metric=alert_status\"  alt=\"Quality Gate\"/></a>\n  <a href=\"https://sonarcloud.io/summary/new_code?id=PickwickSoft_pystreamapi\"><img src=\"https://sonarcloud.io/api/project_badges/measure?project=PickwickSoft_pystreamapi&metric=coverage\"  alt=\"Coverage\"/></a>\n  <a href=\"https://pypi.org/project/streams-py/\"><img alt=\"PyPI - Downloads\" src=\"https://img.shields.io/pypi/dm/streams.py\"></a>\n  <a href=\"https://pypi.org/project/streams-py/\"><img alt=\"PyPI\" src=\"https://img.shields.io/pypi/v/streams.py\"></a>\n</p>\n\nPyStreamAPI is a Python stream library that draws inspiration from the Java Stream API. \nAlthough it closely mirrors the Java API, PyStreamAPI adds some innovative features to make streams in Python even more \ninnovative, declarative and easy to use.\n\nPyStreamAPI offers both sequential and parallel streams and utilizes lazy execution.\n\nNow you might be wondering why another library when there are already a few implementations? Well, here are a few advantages of this particular implementation:\n\n* It provides both sequential and parallel streams.\n* Lazy execution is supported, enhancing performance.\n* It boasts high speed and efficiency.\n* The implementation achieves 100% test coverage.\n* It follows Pythonic principles, resulting in clean and readable code.\n* It adds some cool innovative features such as conditions or error handling and an even more declarative look.\n* It provides loaders for various data sources such as CSV, JSON and XML files.\n\nLet's take a look at a small example:\n\n```python\nfrom pystreamapi import Stream\n\nStream.of([\" \", '3', None, \"2\", 1, \"\"]) \\\n    .filter(lambda x: x is not None) \\\n    .map(str) \\\n    .map(lambda x: x.strip()) \\\n    .filter(lambda x: len(x) > 0) \\\n    .map(int) \\\n    .sorted() \\\n    .for_each(print) # Output: 1 2 3\n```\n\nAnd here's the equivalent code in Java:\n\n```java\nObject[] words = { \" \", '3', null, \"2\", 1, \"\" };\nArrays.stream( words )\n      .filter( Objects::nonNull )\n      .map( Objects::toString )\n      .map( String::trim )\n      .filter( s -> ! s.isEmpty() )\n      .map( Integer::parseInt )\n      .sorted()\n      .forEach( System.out::println );  // Output: 1 2 3\n```\n\n## What is a Stream?\n\nA `Stream` is a powerful abstraction for processing sequences of data in a functional and declarative manner. It enables efficient and concise data manipulation and transformation.\n\nSimilar to its counterparts in Java and Kotlin, a Stream represents a pipeline of operations that can be applied to a collection or any iterable data source. It allows developers to express complex data processing logic using a combination of high-level operations, promoting code reusability and readability.\n\nWith Streams, you can perform a wide range of operations on your data, such as filtering elements, transforming values, aggregating results, sorting, and more. These operations can be seamlessly chained together to form a processing pipeline, where each operation processes the data and passes it on to the next operation.\n\nOne of the key benefits of Stream is lazy evaluation. This means that the operations are executed only when the result is actually needed, optimizing resource usage and enabling efficient processing of large or infinite datasets.\n\nFurthermore, Stream supports both sequential and parallel execution. This allows you to leverage parallel processing capabilities when dealing with computationally intensive tasks or large amounts of data, significantly improving performance.\n\n`pystreamapi.Stream` represents a stream that facilitates the execution of one or more operations. Stream operations can be categorized as either intermediate or terminal.\n\nTerminal operations return a result of a specific type, while intermediate operations return the stream itself, enabling method chaining for multi-step operations.\n\nLet's examine an example using Stream:\n\n```python\nStream.of([\" \", '3', None, \"2\", 1, \"\"]) \\\n    .filter(lambda x: x is not None) \\ # Intermediate operation\n    .map(str) \\ # Intermediate operation\n    .map(lambda x: x.strip()) \\ # Intermediate operation\n    .filter(lambda x: len(x) > 0) \\ # Intermediate operation\n    .map(int) \\ # Intermediate operation\n    .sorted() \\ # Intermediate operation\n    .for_each(print) # Terminal Operation (Output: 1 2 3)\n```\n\nOperations can be performed on a stream either in parallel or sequentially. A parallel stream executes operations concurrently, while a sequential stream processes operations in order.\n\nConsidering the above characteristics, a stream can be defined as follows:\n\n* It is not a data structure itself but operates on existing data structures.\n* It does not provide indexed access like traditional collections.\n* It is designed to work seamlessly with lambda functions, enabling concise and expressive code.\n* It facilitates easy aggregation of results into lists, tuples, or sets.\n* It can be parallelized, allowing for concurrent execution of operations to improve performance.\n* It employs lazy evaluation, executing operations only when necessary.\n\n## Use conditions to speed up your workflow!\n\n![Conditions](https://raw.githubusercontent.com/PickwickSoft/pystreamapi/main/assets/conditions.png)\n\nConditions provide a convenient means for performing logical operations within your Stream, such as using `filter()`, `take_while()`, `drop_while()`, and more. With PyStreamAPI, you have access to a staggering 111 diverse conditions that enable you to process various data types including strings, types, numbers, and dates. Additionally, PyStreamAPI offers a powerful combiner that allows you to effortlessly combine multiple conditions, facilitating the implementation of highly intricate pipelines.\n\n## Error handling: Work with data that you don't know\nPyStreamAPI offers a powerful error handling mechanism that allows you to handle errors in a declarative manner. This is especially useful when working with data that you don't know.\n\nPyStreamAPI offers three different error levels:\n- `ErrorLevel.RAISE`: This is the default error level. It will raise an exception if an error occurs.\n- `ErrorLevel.IGNORE`: This error level will ignore any errors that occur and won't inform you.\n- `ErrorLevel.WARN`: This error level will warn you about any errors that occur and logs them as a warning with default logger.\n\n\nThis is how you can use them:\n\n```python\nfrom pystreamapi import Stream, ErrorLevel\n\nStream.of([\" \", '3', None, \"2\", 1, \"\"]) \\\n    .error_level(ErrorLevel.IGNORE) \\\n    .map_to_int() \\\n    .error_level(ErrorLevel.RAISE) \\\n    .sorted() \\\n    .for_each(print) # Output: 1 2 3\n```\n\nThe code above will ignore all errors that occur during mapping to int and will just skip the elements.\n\nFor more details on how to use error handling, please refer to the documentation.\n\n## Get started: Installation\n\nTo start using PyStreamAPI just install the module with this command:\n\n```bash\npip install streams.py  \n```\n\nAfterward, you can import it with:\n\n```python\nfrom pystreamapi import Stream\n```\n\n:tada: PyStreamAPI is now ready to process your data\n\n## Build a new Stream\n\nPyStreamAPI offers two types of Streams, both of which are available in either sequential or parallel versions:\n\n- (Normal) `Stream`: Offers operations that do not depend on the types. The same functionality as Streams in other programming languages.\n\n- `NumericStream`: This stream extends the capabilities of the default stream by \n  introducing numerical operations. It is designed specifically for use \n  with numerical data sources and can only be applied to such data.\n\nThere are a few factory methods that create new Streams:\n\n```python\nStream.of([1, 2, 3]) # Can return a sequential or a parallel stream\n```\n\nUsing the `of()` method will let the implementation decide which `Stream` to use. If the source is numerical, a `NumericStream` is created.\n\n> **Note** \n> \n> Currently, it always returns a `SequentialStream` or a `SequentialNumericStream`\n\n---\n\n```python\nStream.parallel_of([1, 2, 3]) # Returns a parallel stream (Either normal or numeric)\n```\n\n---\n\n```python\nStream.sequential_of([1, 2, 3]) # Returns a sequential stream (Either normal or numeric)\n```\n\n---\n\n```python\n# Can return a sequential or a parallel stream (Either normal or numeric)\nStream.of_noneable([1, 2, 3])\n\n# Returns a sequential or a parallel, empty stream (Either normal or numeric)\nStream.of_noneable(None) \n```\n\nIf the source is `None`, you get an empty `Stream`\n\n---\n\n```python\nStream.iterate(0, lambda n: n + 2)\n```\n\nCreates a Stream of an infinite Iterator created by iterative application of a\nfunction f to an initial element seed, producing a Stream consisting of seed,\nf(seed), f(f(seed)), etc.\n\n> **Note**\n> Do not forget to limit the stream with `.limit()`\n\n---\n\n```python\nStream.concat(Stream.of([1, 2]), Stream.of([3, 4])) \n# Like Stream.of([1, 2, 3, 4])\n```\n\nCreates a new Stream from multiple Streams. Order doesn't change.\n\n## Use loaders: Load data from CSV, JSON and XML files in just one line\n\nPyStreamAPI offers a convenient way to load data from CSV, JSON and XML files. Like that you can start processing your\nfiles right away without having to worry about reading and parsing the files.\n\nYou can import the loaders with:\n\n```python\nfrom pystreamapi.loaders import csv, json, xml\n```\nNow you can use the loaders directly when creating your Stream:\n\nFor CSV:\n\n```python\nStream.of(csv(\"data.csv\", delimiter=\";\")) \\\n    .map(lambda x: x.attr1) \\\n    .for_each(print)\n```\n\nFor JSON:\n```python\nStream.of(json(\"data.json\")) \\\n    .map(lambda x: x.attr1) \\\n    .for_each(print)\n```\n\nYou can access the attributes of the data structures directly like you would do with a normal object.\n\nFor XML:\n\nIn order to use the XML loader, you need to install the optional xml dependency:\n\n```bash\npip install streams.py[xml_loader]\n```\n\nAfterward, you can use the XML loader like this:\n\n```python\nStream.of(xml(\"data.xml\"))\n  .map(lambda x: x.attr1)\n  .for_each(print)\n```\n\nThe access to the attributes is using a node path syntax. For more details on how to use the node path syntax, please\nrefer to the [documentation](https://pystreamapi.pickwicksoft.org/reference/data-loaders).\n\n## API Reference\nFor a more detailed documentation view the docs on GitBook: [PyStreamAPI Docs](https://pystreamapi.pickwicksoft.org/)\n\n## Complex Examples\n\n#### Get all numbers from list of different types. Use parallelization.\n\n```python\nStream.parallel_of([\" \", '3', None, \"2\", 1, \"\"]) \\\n    .filter(lambda x: x is not None) \\\n    .map(str) \\\n    .map(lambda x: x.strip()) \\\n    .filter(lambda x: len(x) > 0) \\\n    .map(int) \\\n    .sorted()\\\n    .for_each(print) # 1 2 3\n```\n\n#### Generate a Stream of 10 Fibonacci numbers\n\n```python\ndef fib():\n    a, b = 0, 1\n    while True:\n        yield a\n        a, b = b, a + b\n\nStream.of(fib()) \\\n    .limit(10) \\\n    .for_each(print) # 0 1 1 2 3 5 8 13 21 34\n```\n\n## Performance\n\nNote that parallel Streams are not always faster than sequential Streams. Especially when the number of elements is small, we can expect sequential Streams to be faster.\n\n## Bug Reports\n\nBug reports can be submitted in GitHub's [issue tracker](https://github.com/PickwickSoft/pystreamapi/issues).\n\n## Contributing\n\nContributions are welcome! Please submit a pull request or open an issue.\n",
    "bugtrack_url": null,
    "license": "GPL-3.0-or-later",
    "summary": "A stream library for Python inspired by Java Stream API",
    "version": "1.2.1",
    "project_urls": {
        "Homepage": "https://github.com/PickwickSoft/pystreamapi",
        "Repository": "https://github.com/PickwickSoft/pystreamapi"
    },
    "split_keywords": [
        "streams",
        "parallel",
        "data"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "3b4af37c5cd9121107b2ea969886268ad6650b0896d40b42ab217ec065354664",
                "md5": "44644e7457a2a0f8bb36364a6b869eab",
                "sha256": "dae32da8a823ba23c8d279968d55bc7a6b9a48b94fd219fd5b335f0cf65b5478"
            },
            "downloads": -1,
            "filename": "streams_py-1.2.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "44644e7457a2a0f8bb36364a6b869eab",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7,<4.0",
            "size": 43985,
            "upload_time": "2024-02-23T20:47:18",
            "upload_time_iso_8601": "2024-02-23T20:47:18.074958Z",
            "url": "https://files.pythonhosted.org/packages/3b/4a/f37c5cd9121107b2ea969886268ad6650b0896d40b42ab217ec065354664/streams_py-1.2.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "8c2f3a2374cb6cb24596ee8dfe64423ccc18df6be7471c9e297d3a914639313a",
                "md5": "7859673b937223608a926871c65c01a4",
                "sha256": "8dd908aff93dce8f72d0cb4575bc3c29e42552d4c62c06ba9685a3d478be5784"
            },
            "downloads": -1,
            "filename": "streams_py-1.2.1.tar.gz",
            "has_sig": false,
            "md5_digest": "7859673b937223608a926871c65c01a4",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7,<4.0",
            "size": 36909,
            "upload_time": "2024-02-23T20:47:20",
            "upload_time_iso_8601": "2024-02-23T20:47:20.441820Z",
            "url": "https://files.pythonhosted.org/packages/8c/2f/3a2374cb6cb24596ee8dfe64423ccc18df6be7471c9e297d3a914639313a/streams_py-1.2.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-23 20:47:20",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "PickwickSoft",
    "github_project": "pystreamapi",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "streams.py"
}
        
Elapsed time: 0.22695s