sqlcompose 0.0.4a1__tar.gz → 0.0.4a2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. {sqlcompose-0.0.4a1/src/sqlcompose.egg-info → sqlcompose-0.0.4a2}/PKG-INFO +22 -7
  2. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/README.md +19 -5
  3. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/pyproject.toml +6 -3
  4. sqlcompose-0.0.4a2/src/sqlcompose/core/app.py +30 -0
  5. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/src/sqlcompose/core/compat.py +31 -0
  6. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2/src/sqlcompose.egg-info}/PKG-INFO +22 -7
  7. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/src/sqlcompose.egg-info/requires.txt +1 -0
  8. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/tests/test_app.py +18 -1
  9. sqlcompose-0.0.4a1/src/sqlcompose/core/app.py +0 -25
  10. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/LICENSE +0 -0
  11. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/setup.cfg +0 -0
  12. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/src/sqlcompose/__init__.py +0 -0
  13. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/src/sqlcompose/__main__.py +0 -0
  14. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/src/sqlcompose/core/circular_dependency_error.py +0 -0
  15. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/src/sqlcompose/core/file_not_found_err.py +0 -0
  16. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/src/sqlcompose/core/functions.py +0 -0
  17. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/src/sqlcompose/core/include.py +0 -0
  18. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/src/sqlcompose/py.typed +0 -0
  19. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/src/sqlcompose.egg-info/SOURCES.txt +0 -0
  20. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/src/sqlcompose.egg-info/dependency_links.txt +0 -0
  21. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/src/sqlcompose.egg-info/entry_points.txt +0 -0
  22. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/src/sqlcompose.egg-info/top_level.txt +0 -0
  23. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/tests/test_compat.py +0 -0
  24. {sqlcompose-0.0.4a1 → sqlcompose-0.0.4a2}/tests/test_functions.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlcompose
3
- Version: 0.0.4a1
4
- Summary: Composition of linked SQL files
3
+ Version: 0.0.4a2
4
+ Summary: Composition of SQL files
5
5
  Author-email: Anders Madsen <anders.madsen@alphavue.com>
6
6
  License-Expression: MIT
7
7
  Project-URL: repository, https://github.com/apmadsen/sqlcompose
@@ -29,6 +29,7 @@ License-File: LICENSE
29
29
  Provides-Extra: test
30
30
  Requires-Dist: pytest>=8.3.0; extra == "test"
31
31
  Requires-Dist: pytest-cov>=6.1.0; extra == "test"
32
+ Requires-Dist: pytest-mock>=3.15; extra == "test"
32
33
  Dynamic: license-file
33
34
 
34
35
  [![Test](https://github.com/apmadsen/sqlcompose/actions/workflows/python-test.yml/badge.svg)](https://github.com/apmadsen/sqlcompose/actions/workflows/python-test.yml)
@@ -38,19 +39,33 @@ Dynamic: license-file
38
39
  ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/sqlcompose)
39
40
  [![PyPI Downloads](https://static.pepy.tech/badge/sqlcompose/week)](https://pepy.tech/projects/sqlcompose)
40
41
 
41
- # sqlcompose: Composition of linked SQL files
42
- sqlcompose allows you to compose sql files from multiple files by introducing `INCLUDE` keywords. The SQL output is composed as CTE's or Common Table Expressions.
42
+ # sqlcompose: Composition of SQL files
43
+ sqlcompose lets you to compose sql files from multiple files by introducing `$INCLUDE` keywords. The SQL output is composed as CTE's or Common Table Expressions.
44
+
45
+ Using composition, you reduce both complexity and duplication of code thus adhering to the DRY principle.
46
+
47
+ ### SQL Dialect
48
+ sqlcompose outputs SQL as standard ANSI SQL. Note though, that no validation is done on either the input or the output.
43
49
 
44
50
  ## Examples
45
- __Execute the script directly:__
46
- ```console
51
+
52
+ ### 1. Execute the script with the filename as an argument and output to the console:
53
+ ```bash
47
54
  sqlcompose query.sql
48
55
  ```
56
+
57
+ ### 2. Pipe data into application and output to a file
58
+ ```bash
59
+ cat query.sql | sqlcompose > output.sql
60
+ ```
61
+
62
+ ### 3. Execute the script with SQL string as argument
49
63
  ```bash
50
64
  sqlcompose 'select * from $INCLUDE(included-query1.sql)'
51
65
  ```
66
+ > NOTE: Different consoles have different limitations, so you may have to switch from single to double quotes to allow for using the dollar sign.
52
67
 
53
- __Import it in another script:__
68
+ ### 4. Import it in another python application or package
54
69
  ```python
55
70
  from sqlcompose import load, loads
56
71
  # method 1 : loading from a file
@@ -5,19 +5,33 @@
5
5
  ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/sqlcompose)
6
6
  [![PyPI Downloads](https://static.pepy.tech/badge/sqlcompose/week)](https://pepy.tech/projects/sqlcompose)
7
7
 
8
- # sqlcompose: Composition of linked SQL files
9
- sqlcompose allows you to compose sql files from multiple files by introducing `INCLUDE` keywords. The SQL output is composed as CTE's or Common Table Expressions.
8
+ # sqlcompose: Composition of SQL files
9
+ sqlcompose lets you to compose sql files from multiple files by introducing `$INCLUDE` keywords. The SQL output is composed as CTE's or Common Table Expressions.
10
+
11
+ Using composition, you reduce both complexity and duplication of code thus adhering to the DRY principle.
12
+
13
+ ### SQL Dialect
14
+ sqlcompose outputs SQL as standard ANSI SQL. Note though, that no validation is done on either the input or the output.
10
15
 
11
16
  ## Examples
12
- __Execute the script directly:__
13
- ```console
17
+
18
+ ### 1. Execute the script with the filename as an argument and output to the console:
19
+ ```bash
14
20
  sqlcompose query.sql
15
21
  ```
22
+
23
+ ### 2. Pipe data into application and output to a file
24
+ ```bash
25
+ cat query.sql | sqlcompose > output.sql
26
+ ```
27
+
28
+ ### 3. Execute the script with SQL string as argument
16
29
  ```bash
17
30
  sqlcompose 'select * from $INCLUDE(included-query1.sql)'
18
31
  ```
32
+ > NOTE: Different consoles have different limitations, so you may have to switch from single to double quotes to allow for using the dollar sign.
19
33
 
20
- __Import it in another script:__
34
+ ### 4. Import it in another python application or package
21
35
  ```python
22
36
  from sqlcompose import load, loads
23
37
  # method 1 : loading from a file
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "sqlcompose"
3
3
  dynamic = ["version"]
4
- description = "Composition of linked SQL files"
4
+ description = "Composition of SQL files"
5
5
  keywords = ["sql", "composition", "windows", "linux"]
6
6
  readme = "README.md"
7
7
  authors = [
@@ -28,7 +28,9 @@ classifiers = [
28
28
  "Topic :: Software Development :: Libraries",
29
29
  "Typing :: Typed"
30
30
  ]
31
- dependencies = []
31
+ dependencies = [
32
+
33
+ ]
32
34
  requires-python = ">= 3.10, < 3.15"
33
35
 
34
36
  [project.urls]
@@ -41,6 +43,7 @@ repository = "https://github.com/apmadsen/sqlcompose"
41
43
  test = [
42
44
  "pytest>=8.3.0",
43
45
  "pytest-cov>=6.1.0",
46
+ "pytest-mock>=3.15"
44
47
  ]
45
48
 
46
49
  [tool.setuptools-git-versioning]
@@ -48,4 +51,4 @@ enabled = true
48
51
 
49
52
  [build-system]
50
53
  requires = ["setuptools >= 77.0.3", "setuptools-git-versioning >= 2.1.0"]
51
- build-backend = "setuptools.build_meta"
54
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,30 @@
1
+ from argparse import ArgumentParser
2
+
3
+ from sqlcompose.core.functions import load, loads
4
+ from sqlcompose.core.compat import is_file, get_piped_input
5
+ from sqlcompose.core.file_not_found_err import FileNotFoundErr
6
+
7
+
8
+ def app(args: list[str]) -> tuple[str, int]:
9
+ try:
10
+ from sys import stdin # iport must be done here to allow for test patching
11
+
12
+ if not stdin.isatty() and ( piped := get_piped_input(stdin) ):
13
+ sql = loads(piped)
14
+ else:
15
+ parser = ArgumentParser(prog = "sqlcompose")
16
+ parser.add_argument("input", type=str, help = "SQL expression or location of an SQL file")
17
+ pargs = parser.parse_args(args)
18
+
19
+ if is_file(pargs.input):
20
+ sql = load(pargs.input)
21
+ else:
22
+ sql = loads(pargs.input)
23
+
24
+ return sql, 0
25
+ except SystemExit as ex:
26
+ return str(ex), 2
27
+ except (FileNotFoundErr, FileNotFoundError) as ex:
28
+ return str(ex), 3
29
+ except Exception as ex: # pragma: no cover
30
+ return f"Unexpected error: {ex}", 1
@@ -1,5 +1,7 @@
1
1
  from os import path, sep
2
+ from typing import TextIO
2
3
  from re import compile
4
+ from threading import Thread, Event
3
5
 
4
6
  RX_FILE = compile(r"^[\w,\s-]+\.[A-Za-z]{3}$")
5
7
  WINDOWS_PATH_SEP = "\\"
@@ -42,3 +44,32 @@ def is_file(text: str) -> bool:
42
44
  return True
43
45
 
44
46
  return False
47
+
48
+ def get_piped_input(pipe: TextIO) -> str:
49
+ """Reads input from pipe (usually sys.stdin) without blocking.
50
+ """
51
+ output: list[str] = []
52
+ ev_started = Event()
53
+ ev_done = Event()
54
+
55
+ def fn(output: list[str]):
56
+ try:
57
+ ev_started.set()
58
+ output.append(pipe.read())
59
+ except OSError:
60
+ pass
61
+ finally:
62
+ ev_done.set()
63
+
64
+ thread = Thread(target = fn, args = (output,))
65
+ thread.start()
66
+
67
+ ev_started.wait()
68
+
69
+ if ev_done.wait(0.1): # if there is in fact anything in the pipe, we expect it to be read within 0.1 second
70
+ thread.join()
71
+ else:
72
+ pass # pragma: no cover
73
+ # the thread will block indefinitely, nothing to do about it
74
+
75
+ return output[0] if any(output) else ""
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlcompose
3
- Version: 0.0.4a1
4
- Summary: Composition of linked SQL files
3
+ Version: 0.0.4a2
4
+ Summary: Composition of SQL files
5
5
  Author-email: Anders Madsen <anders.madsen@alphavue.com>
6
6
  License-Expression: MIT
7
7
  Project-URL: repository, https://github.com/apmadsen/sqlcompose
@@ -29,6 +29,7 @@ License-File: LICENSE
29
29
  Provides-Extra: test
30
30
  Requires-Dist: pytest>=8.3.0; extra == "test"
31
31
  Requires-Dist: pytest-cov>=6.1.0; extra == "test"
32
+ Requires-Dist: pytest-mock>=3.15; extra == "test"
32
33
  Dynamic: license-file
33
34
 
34
35
  [![Test](https://github.com/apmadsen/sqlcompose/actions/workflows/python-test.yml/badge.svg)](https://github.com/apmadsen/sqlcompose/actions/workflows/python-test.yml)
@@ -38,19 +39,33 @@ Dynamic: license-file
38
39
  ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/sqlcompose)
39
40
  [![PyPI Downloads](https://static.pepy.tech/badge/sqlcompose/week)](https://pepy.tech/projects/sqlcompose)
40
41
 
41
- # sqlcompose: Composition of linked SQL files
42
- sqlcompose allows you to compose sql files from multiple files by introducing `INCLUDE` keywords. The SQL output is composed as CTE's or Common Table Expressions.
42
+ # sqlcompose: Composition of SQL files
43
+ sqlcompose lets you to compose sql files from multiple files by introducing `$INCLUDE` keywords. The SQL output is composed as CTE's or Common Table Expressions.
44
+
45
+ Using composition, you reduce both complexity and duplication of code thus adhering to the DRY principle.
46
+
47
+ ### SQL Dialect
48
+ sqlcompose outputs SQL as standard ANSI SQL. Note though, that no validation is done on either the input or the output.
43
49
 
44
50
  ## Examples
45
- __Execute the script directly:__
46
- ```console
51
+
52
+ ### 1. Execute the script with the filename as an argument and output to the console:
53
+ ```bash
47
54
  sqlcompose query.sql
48
55
  ```
56
+
57
+ ### 2. Pipe data into application and output to a file
58
+ ```bash
59
+ cat query.sql | sqlcompose > output.sql
60
+ ```
61
+
62
+ ### 3. Execute the script with SQL string as argument
49
63
  ```bash
50
64
  sqlcompose 'select * from $INCLUDE(included-query1.sql)'
51
65
  ```
66
+ > NOTE: Different consoles have different limitations, so you may have to switch from single to double quotes to allow for using the dollar sign.
52
67
 
53
- __Import it in another script:__
68
+ ### 4. Import it in another python application or package
54
69
  ```python
55
70
  from sqlcompose import load, loads
56
71
  # method 1 : loading from a file
@@ -2,3 +2,4 @@
2
2
  [test]
3
3
  pytest>=8.3.0
4
4
  pytest-cov>=6.1.0
5
+ pytest-mock>=3.15
@@ -1,7 +1,10 @@
1
1
  # ruff: noqa
2
2
  # pyright: basic
3
- from os import path
3
+ from os import path, chdir, curdir
4
+ from sys import stdin
5
+ from io import StringIO
4
6
  from pytest import fixture, raises as assert_raises
7
+ from pytest_mock import MockerFixture
5
8
 
6
9
  from sqlcompose.core.app import app
7
10
 
@@ -29,3 +32,17 @@ def test_sql():
29
32
  result, code = app([f"SELECT * FROM $INCLUDE({path.join('tests', 'main-query.sql')})"])
30
33
  assert len(result) > 0
31
34
  assert code == 0
35
+
36
+ def test_pipe(mocker: MockerFixture):
37
+ chdir("tests")
38
+ try:
39
+ with open("main-query.sql", "rt", encoding="utf8") as input:
40
+ mocker.patch(f"sys.stdin", input)
41
+ try:
42
+ result, code = app([])
43
+ assert len(result) > 0
44
+ assert code == 0
45
+ finally:
46
+ mocker.resetall()
47
+ finally:
48
+ chdir("..")
@@ -1,25 +0,0 @@
1
- from argparse import ArgumentParser
2
-
3
- from sqlcompose.core.functions import load, loads
4
- from sqlcompose.core.compat import is_file
5
- from sqlcompose.core.file_not_found_err import FileNotFoundErr
6
-
7
-
8
- def app(args: list[str]) -> tuple[str, int]:
9
- try:
10
- parser = ArgumentParser(prog = "sqlcompose")
11
- parser.add_argument("input", type=str, help = "SQL expression or location of an SQL file")
12
- pargs = parser.parse_args(args)
13
-
14
- if is_file(pargs.input):
15
- sql = load(pargs.input)
16
- else:
17
- sql = loads(pargs.input)
18
-
19
- return sql, 0
20
- except SystemExit as ex:
21
- return str(ex), 2
22
- except (FileNotFoundErr, FileNotFoundError) as ex:
23
- return str(ex), 3
24
- except Exception as ex: # pragma: no cover
25
- return f"Unexpected error: {ex}", 1
File without changes
File without changes