Skip to content

Commit

Permalink
Merge pull request #21 from jsconan/release-0.6.0
Browse files Browse the repository at this point in the history
Release 0.6.0
  • Loading branch information
jsconan authored Sep 14, 2023
2 parents 52c3c14 + cafed82 commit 0b21b0b
Show file tree
Hide file tree
Showing 14 changed files with 699 additions and 24 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.6.0] - 2023-09-14

### Added

- `fetch_content(url, ...)` - Fetch content from a remote HTTP address.
- `read_zip_file(buffer, ...)` - Reads a file content from a Zip archive.
- `read_zip_csv(buffer, ...)` - Reads a CSV content from a Zip.

## [0.5.1] - 2023-09-13

### Changed
Expand Down
3 changes: 3 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,12 @@
- [`mappers.boolean`](./toolbox.data.mappers.md#function-boolean): Converts a value to a boolean value.
- [`mappers.passthrough`](./toolbox.data.mappers.md#function-passthrough): A passthrough mapper. It returns the value as it is.
- [`csv_file.read_csv_file`](./toolbox.files.csv_file.md#function-read_csv_file): Reads a CSV content from a file.
- [`csv_file.read_zip_csv`](./toolbox.files.csv_file.md#function-read_zip_csv): Reads a CSV content from a Zip.
- [`csv_file.write_csv_file`](./toolbox.files.csv_file.md#function-write_csv_file): Writes a CSV content to a file.
- [`file.fetch_content`](./toolbox.files.file.md#function-fetch_content): Downloads content from the given URL.
- [`file.get_file_mode`](./toolbox.files.file.md#function-get_file_mode): Gets the file access mode given the expectations.
- [`file.read_file`](./toolbox.files.file.md#function-read_file): Reads a content from a file.
- [`file.read_zip_file`](./toolbox.files.file.md#function-read_zip_file): Extracts a file content from a Zip archive.
- [`file.write_file`](./toolbox.files.file.md#function-write_file): Writes a content to a file.
- [`json_file.read_json_file`](./toolbox.files.json_file.md#function-read_json_file): Reads a JSON content from a file.
- [`json_file.write_json_file`](./toolbox.files.json_file.md#function-write_json_file): Writes a JSON content to a file.
Expand Down
2 changes: 1 addition & 1 deletion docs/toolbox.config.config.md
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ set_option(
value: Any = None,
default: Any = None,
description: str = None,
mapper: Callable = <function passthrough at 0x100ed1580>,
mapper: Callable = <function passthrough at 0x1030c9580>,
choices: list = None
) → None
```
Expand Down
2 changes: 1 addition & 1 deletion docs/toolbox.config.config_option.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ __init__(
value: 'Any' = None,
default: 'Any' = None,
description: 'str' = '',
mapper: 'ValueMapper' = <function passthrough at 0x100ed1580>,
mapper: 'ValueMapper' = <function passthrough at 0x1030c9580>,
choices: 'Iterable' = None
) → None
```
Expand Down
86 changes: 77 additions & 9 deletions docs/toolbox.files.csv_file.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ with file:

---

<a href="../toolbox/files/csv_file.py#L460"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
<a href="../toolbox/files/csv_file.py#L461"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

## <kbd>function</kbd> `read_csv_file`

Expand Down Expand Up @@ -115,7 +115,7 @@ csv_data = read_csv_file('path/to/file', encoding='UTF-8', dialect='excel')

---

<a href="../toolbox/files/csv_file.py#L522"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
<a href="../toolbox/files/csv_file.py#L523"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

## <kbd>function</kbd> `write_csv_file`

Expand Down Expand Up @@ -181,7 +181,75 @@ write_csv_file('path/to/file', csv_data, encoding='UTF-8', dialect='excel')

---

<a href="../toolbox/files/csv_file.py#L91"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
<a href="../toolbox/files/csv_file.py#L596"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

## <kbd>function</kbd> `read_zip_csv`

```python
read_zip_csv(
buffer: 'bytes',
filename: 'str' = None,
encoding: 'str' = 'utf-8',
decoding_errors: 'str' = 'ignore',
dialect: 'str' = 'unix',
**kwargs
) → list[dict | list]
```

Reads a CSV content from a Zip.



**Args:**

- <b>`buffer`</b> (bytes): A buffer of bytes representing the zipped content.
- <b>`filename`</b> (str, optional): The name of the file to extract from the zip If omitted, the first file having a '.csv' extension will be selected. Defaults to None.
- <b>`encoding`</b> (str, optional): The file encoding. Defaults to CSV_ENCODING.
- <b>`decoding_errors`</b> (str, optional): Controls how decoding errors are handled. If 'strict', a UnicodeError exception is raised. Other possible values are 'ignore', 'replace', and any other name registered via codecs.register_error(). See Error Handlers for details. Defaults to "ignore".
- <b>`dialect`</b> (str, optional): The CSV dialect to use. If 'auto' is given, the reader will try detecting the CSV dialect by reading a sample at the head of the file. Defaults to CSV_DIALECT.
- <b>`delimiter`</b> (str, optional): A one-character string used to separate fields. Defaults to ','.
- <b>`doublequote`</b> (bool, optional): Controls how instances of quotechar appearing inside a field should themselves be quoted. When True, the character is doubled. When False, the escapechar is used as a prefix to the quotechar. Defaults to True.
- <b>`escapechar`</b> (str, optional): A one-character string used to removes any special meaning from the following character. Defaults to None, which disables escaping.
- <b>`quotechar`</b> (str, optional): A one-character string used to quote fields containing special characters, such as the delimiter or quotechar, or which contain new-line characters. Defaults to '"'.
- <b>`quoting`</b> (bool, optional): Controls when quotes should be be recognized by the reader. It can take on any of the QUOTE_* constants. Defaults to QUOTE_MINIMAL.
- <b>`skipinitialspace`</b> (bool, optional): When True, spaces immediately following the delimiter are ignored. The default is False.
- <b>`strict`</b> (bool, optional): When True, raise exception Error on bad CSV input. Defaults to False.
- <b>`fieldnames`</b> (sequence, optional): The name of each column in the CSV. If fieldnames is omitted, the values in the first row of the file will be used as the fieldnames. Regardless of how the fieldnames are determined, the dictionary preserves their original ordering. If a row has more fields than fieldnames, the remaining data is put in a list and stored with the fieldname specified by restkey (which defaults to None). If a non-blank row has fewer fields than fieldnames, the missing values are filled-in with the value of restval (which defaults to None).

For reading headless CSV, set fieldnames to False.



**Raises:**

- <b>`FileNotFoundError`</b>: If the file does not exist.



**Returns:**

- <b>`list[dict | list]`</b>: The data read from the CSV file.



**Examples:**
```python
from toolbox.files import read_zip_csv

with open('path/to/file.zip', 'rb') as file:
zip = file.read()

# The first CSV file in the archive will be extracted
csv_data = read_zip_csv(zip)

# The specified CSV file will be extracted from the archive
csv_data = read_zip_csv(zip, 'foo.csv')
```


---

<a href="../toolbox/files/csv_file.py#L93"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

## <kbd>class</kbd> `CSVFile`
Offers a simple API for reading and writing CSV files.
Expand Down Expand Up @@ -226,7 +294,7 @@ with file(create=True):
csv = file.read_file()
```

<a href="../toolbox/files/csv_file.py#L132"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
<a href="../toolbox/files/csv_file.py#L134"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

### <kbd>method</kbd> `__init__`

Expand Down Expand Up @@ -482,7 +550,7 @@ size = file.size

---

<a href="../toolbox/files/csv_file.py#L261"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
<a href="../toolbox/files/csv_file.py#L263"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

### <kbd>method</kbd> `close`

Expand Down Expand Up @@ -520,7 +588,7 @@ file.close()

---

<a href="../toolbox/files/csv_file.py#L347"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
<a href="../toolbox/files/csv_file.py#L349"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

### <kbd>method</kbd> `read`

Expand Down Expand Up @@ -564,7 +632,7 @@ csv_data = [row for row in file]

---

<a href="../toolbox/files/csv_file.py#L292"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
<a href="../toolbox/files/csv_file.py#L294"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

### <kbd>method</kbd> `read_file`

Expand Down Expand Up @@ -603,7 +671,7 @@ data = file.read_file()

---

<a href="../toolbox/files/csv_file.py#L398"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
<a href="../toolbox/files/csv_file.py#L400"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

### <kbd>method</kbd> `write`

Expand Down Expand Up @@ -650,7 +718,7 @@ with file(create=True):

---

<a href="../toolbox/files/csv_file.py#L316"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
<a href="../toolbox/files/csv_file.py#L318"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

### <kbd>method</kbd> `write_file`

Expand Down
136 changes: 131 additions & 5 deletions docs/toolbox.files.file.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ A collection of utilities for accessing files.

**Examples:**
```python
from toolbox.files import get_file_mode, read_file, write_file
from toolbox.files import fetch_content, get_file_mode, read_file, read_zip_file, write_file

# get_file_mode() is used to build a file access mode.
# For example to create a text file:
Expand All @@ -29,12 +29,21 @@ text = read_file('path/to/file', encoding='UTF-8')

# Load a binary file
data = read_file('path/to/file', binary=True)

# Fetch text content from a remote address
text = fetch_content("http://example.com/text")

# Fetch binary content from a remote address
data = fetch_content("http://example.com/data", binary=True)

# Considering the fetched content is a zip archive, extract the first file
content = read_zip_file(data)
```


---

<a href="../toolbox/files/file.py#L29"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
<a href="../toolbox/files/file.py#L43"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

## <kbd>function</kbd> `get_file_mode`

Expand All @@ -50,7 +59,7 @@ get_file_mode(

Gets the file access mode given the expectations.

The file access mode is defined by a string that contains flags for selecting the modes. More info at https://docs.python.org/3/library/functions.html#open
The file access mode is defined by a string that contains flags for selecting the modes. For more info see [builtin open](https://docs.python.org/3/library/functions.html#open).



Expand Down Expand Up @@ -98,7 +107,7 @@ with open('path/to/file', get_file_mode(binary=True)) as file:

---

<a href="../toolbox/files/file.py#L107"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
<a href="../toolbox/files/file.py#L121"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

## <kbd>function</kbd> `read_file`

Expand Down Expand Up @@ -150,7 +159,7 @@ data = read_file('path/to/file', binary=True)

---

<a href="../toolbox/files/file.py#L149"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
<a href="../toolbox/files/file.py#L163"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

## <kbd>function</kbd> `write_file`

Expand Down Expand Up @@ -203,6 +212,123 @@ write_file('path/to/file', data, binary=True)
```


---

<a href="../toolbox/files/file.py#L208"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

## <kbd>function</kbd> `fetch_content`

```python
fetch_content(
url: str,
binary: bool = False,
timeout: int | tuple = (6, 30),
**kwargs
) → str | bytes
```

Downloads content from the given URL.

It uses an HTTP/GET request to fetch the remote data.

Under the hood, it relies on requests to process the query.



**Args:**

- <b>`url`</b> (str): The URL of the content to fetch.
- <b>`binary`</b> (bool): Tells if the content is binary (True) or text (False). When True, the function will return a bytes sequence, otherwise it will return a string sequence.
- <b>`timeout`</b> (int | tuple): The request timeout. Defaults to (6, 30).
- <b>`**kwargs`</b>: Additional parameters for the GET request. For more info, see [requests/api](https://requests.readthedocs.io/en/latest/api/).



**Raises:**

- <b>`requests.RequestException`</b>: There was an ambiguous exception that occurred while handling the request.
- <b>`requests.ConnectionError`</b>: A Connection error occurred.
- <b>`requests.HTTPError`</b>: An HTTP error occurred.
- <b>`requests.URLRequired`</b>: A valid URL is required to make a request.
- <b>`requests.TooManyRedirects`</b>: Too many redirects.
- <b>`requests.ConnectTimeout`</b>: The request timed out while trying to connect to the remote server. Requests that produced this error are safe to retry.
- <b>`requests.ReadTimeout`</b>: The server did not send any data in the allotted amount of time.
- <b>`requests.Timeout`</b>: The request timed out. Catching this error will catch both ConnectTimeout and ReadTimeout errors.



**Returns:**

- <b>`str | bytes`</b>: Returns a bytes buffer.



**Examples:**
```python
from toolbox.files import fetch_content

# Fetch text content from a remote address
text = fetch_content("http://example.com/text")

# Fetch binary content from a remote address
data = fetch_content("http://example.com/data", binary=True)
```


---

<a href="../toolbox/files/file.py#L259"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>

## <kbd>function</kbd> `read_zip_file`

```python
read_zip_file(buffer: bytes, filename: str = None, ext: str = None) → bytes
```

Extracts a file content from a Zip archive.

If a filename is given, the corresponding file will be extracted from the archive. Otherwise, if a file extension is given, the first file having this extension in the archive will be extracted. If no filename nor extension is given, the fist available file is extracted.



**Args:**

- <b>`buffer`</b> (bytes): A buffer of bytes representing the Zip archive.
- <b>`filename`</b> (str, optional): The name of the file to extract from the zip. If omitted, and the extension is given, the first file having the extension will be selected. Otherwise, the first available file will be selected. Defaults to None.
- <b>`ext`</b> (str, optional): The extension of the file to extract from the zip. This value is used if the filename is omitted, and in this case, the first file having the extension will be selected. Defaults to None.



**Raises:**

- <b>`FileNotFoundError`</b>: If the file does not exist.



**Returns:**

- <b>`bytes`</b>: The content of the file extracted from the Zip archive.



**Examples:**
```python
from toolbox.files import read_zip

with open('path/to/file.zip', 'rb') as file:
zip = file.read()

# The first file in the archive will be extracted
data = read_zip(zip)

# The specified file will be extracted from the archive
data = read_zip(zip, filename='foo')

# The first file having the extension will be extracted from the archive
data = read_zip(zip, ext='.txt')
```




---
Expand Down
Loading

0 comments on commit 0b21b0b

Please sign in to comment.