agriql 3.10.1__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.
- agriql-3.10.1/LICENSE +17 -0
- agriql-3.10.1/PKG-INFO +64 -0
- agriql-3.10.1/README.md +36 -0
- agriql-3.10.1/agriql/__init__.py +7 -0
- agriql-3.10.1/agriql/__main__.py +13 -0
- agriql-3.10.1/agriql/_ffi.py +52 -0
- agriql-3.10.1/agriql/connection.py +105 -0
- agriql-3.10.1/agriql/result.py +37 -0
- agriql-3.10.1/agriql.egg-info/PKG-INFO +64 -0
- agriql-3.10.1/agriql.egg-info/SOURCES.txt +15 -0
- agriql-3.10.1/agriql.egg-info/dependency_links.txt +1 -0
- agriql-3.10.1/agriql.egg-info/entry_points.txt +2 -0
- agriql-3.10.1/agriql.egg-info/requires.txt +21 -0
- agriql-3.10.1/agriql.egg-info/top_level.txt +1 -0
- agriql-3.10.1/pyproject.toml +32 -0
- agriql-3.10.1/setup.cfg +4 -0
- agriql-3.10.1/tests/test_client.py +44 -0
agriql-3.10.1/LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Copyright 2026 Sbruice Singh, Agricultural Service of Product Farm (ASPF)
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
agriql-3.10.1/PKG-INFO
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agriql
|
|
3
|
+
Version: 3.10.1
|
|
4
|
+
Summary: Client for the AgriQL engine. This package is not a database.
|
|
5
|
+
Author-email: Sbruice Singh <sbruicesingh@haclon.in>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/SbruiceS/agriql-python
|
|
8
|
+
Project-URL: Issues, https://github.com/SbruiceS/agriql-python/issues
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Provides-Extra: pandas
|
|
13
|
+
Requires-Dist: pandas; extra == "pandas"
|
|
14
|
+
Provides-Extra: polars
|
|
15
|
+
Requires-Dist: polars; extra == "polars"
|
|
16
|
+
Provides-Extra: arrow
|
|
17
|
+
Requires-Dist: pyarrow; extra == "arrow"
|
|
18
|
+
Provides-Extra: geo
|
|
19
|
+
Requires-Dist: geopandas; extra == "geo"
|
|
20
|
+
Provides-Extra: ml
|
|
21
|
+
Requires-Dist: numpy; extra == "ml"
|
|
22
|
+
Provides-Extra: all
|
|
23
|
+
Requires-Dist: pandas; extra == "all"
|
|
24
|
+
Requires-Dist: polars; extra == "all"
|
|
25
|
+
Requires-Dist: pyarrow; extra == "all"
|
|
26
|
+
Requires-Dist: numpy; extra == "all"
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# agriql
|
|
30
|
+
|
|
31
|
+
Python client for the AgriQL engine. `import agriql` does not start a second database.
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
import agriql
|
|
35
|
+
|
|
36
|
+
db = agriql.connect("farm.aqdb")
|
|
37
|
+
result = db.query("SELECT plant_id, soil_moisture FROM agriculture.soil")
|
|
38
|
+
result.to_records()
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`to_pandas()`, `to_polars()`, and `to_arrow()` import those libraries only when called. Arrow IPC is not produced by the engine. `to_arrow()` builds a `pyarrow` table from the result grid.
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
`libagriql_ffi` must already be on the library path. Build it from [AgriQL](https://github.com/SbruiceS/AgriQL):
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
git clone https://github.com/SbruiceS/AgriQL.git
|
|
49
|
+
cd AgriQL
|
|
50
|
+
cargo build -p agriql-ffi --release
|
|
51
|
+
sudo cp target/release/libagriql_ffi.so /usr/local/lib
|
|
52
|
+
sudo ldconfig
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Then:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install git+https://github.com/SbruiceS/agriql-python.git
|
|
59
|
+
pip install "agriql[pandas] @ git+https://github.com/SbruiceS/agriql-python.git"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
If the library is not in a default directory, set `AGRIQL_FFI` to the full path of `libagriql_ffi.so`.
|
|
63
|
+
|
|
64
|
+
`agriql.connect("agriql://127.0.0.1:5471/farm")` uses the server port instead of the library. This package is not published on PyPI.
|
agriql-3.10.1/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# agriql
|
|
2
|
+
|
|
3
|
+
Python client for the AgriQL engine. `import agriql` does not start a second database.
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
import agriql
|
|
7
|
+
|
|
8
|
+
db = agriql.connect("farm.aqdb")
|
|
9
|
+
result = db.query("SELECT plant_id, soil_moisture FROM agriculture.soil")
|
|
10
|
+
result.to_records()
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`to_pandas()`, `to_polars()`, and `to_arrow()` import those libraries only when called. Arrow IPC is not produced by the engine. `to_arrow()` builds a `pyarrow` table from the result grid.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
`libagriql_ffi` must already be on the library path. Build it from [AgriQL](https://github.com/SbruiceS/AgriQL):
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
git clone https://github.com/SbruiceS/AgriQL.git
|
|
21
|
+
cd AgriQL
|
|
22
|
+
cargo build -p agriql-ffi --release
|
|
23
|
+
sudo cp target/release/libagriql_ffi.so /usr/local/lib
|
|
24
|
+
sudo ldconfig
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Then:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install git+https://github.com/SbruiceS/agriql-python.git
|
|
31
|
+
pip install "agriql[pandas] @ git+https://github.com/SbruiceS/agriql-python.git"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
If the library is not in a default directory, set `AGRIQL_FFI` to the full path of `libagriql_ffi.so`.
|
|
35
|
+
|
|
36
|
+
`agriql.connect("agriql://127.0.0.1:5471/farm")` uses the server port instead of the library. This package is not published on PyPI.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
from agriql import connect
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def main():
|
|
7
|
+
target = sys.argv[1] if len(sys.argv) > 1 else ":memory:"
|
|
8
|
+
sql = sys.argv[2] if len(sys.argv) > 2 else "SHOW VERSION;"
|
|
9
|
+
print(connect(target).query(sql).text)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
if __name__ == "__main__":
|
|
13
|
+
main()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""ctypes bindings for libagriql_ffi. The library owns the engine."""
|
|
2
|
+
|
|
3
|
+
import ctypes
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def load():
|
|
9
|
+
requested = os.environ.get("AGRIQL_FFI")
|
|
10
|
+
names = [
|
|
11
|
+
requested,
|
|
12
|
+
"libagriql_ffi.so",
|
|
13
|
+
"libagriql_ffi.dylib",
|
|
14
|
+
"agriql_ffi.dll",
|
|
15
|
+
]
|
|
16
|
+
roots = [
|
|
17
|
+
Path.cwd(),
|
|
18
|
+
Path(__file__).resolve().parents[3] / "target" / "debug",
|
|
19
|
+
Path(__file__).resolve().parents[3] / "target" / "release",
|
|
20
|
+
]
|
|
21
|
+
candidates = []
|
|
22
|
+
for name in names:
|
|
23
|
+
if not name:
|
|
24
|
+
continue
|
|
25
|
+
path = Path(name)
|
|
26
|
+
if path.is_file():
|
|
27
|
+
candidates.append(path)
|
|
28
|
+
for root in roots:
|
|
29
|
+
found = root / name
|
|
30
|
+
if found.is_file():
|
|
31
|
+
candidates.append(found)
|
|
32
|
+
if not candidates:
|
|
33
|
+
raise FileNotFoundError(
|
|
34
|
+
"libagriql_ffi was not found. Build it with `cargo build -p agriql-ffi` "
|
|
35
|
+
"or set AGRIQL_FFI to the library path."
|
|
36
|
+
)
|
|
37
|
+
chosen = max(candidates, key=lambda path: path.stat().st_mtime)
|
|
38
|
+
lib = ctypes.CDLL(str(chosen))
|
|
39
|
+
lib.agriql_open.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_void_p)]
|
|
40
|
+
lib.agriql_open.restype = ctypes.c_int
|
|
41
|
+
lib.agriql_close.argtypes = [ctypes.c_void_p]
|
|
42
|
+
lib.agriql_close.restype = ctypes.c_int
|
|
43
|
+
lib.agriql_execute.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
|
|
44
|
+
lib.agriql_execute.restype = ctypes.c_void_p
|
|
45
|
+
lib.agriql_result_text.argtypes = [ctypes.c_void_p]
|
|
46
|
+
lib.agriql_result_text.restype = ctypes.c_char_p
|
|
47
|
+
lib.agriql_result_status.argtypes = [ctypes.c_void_p]
|
|
48
|
+
lib.agriql_result_status.restype = ctypes.c_int
|
|
49
|
+
lib.agriql_free_result.argtypes = [ctypes.c_void_p]
|
|
50
|
+
lib.agriql_thread_error.argtypes = []
|
|
51
|
+
lib.agriql_thread_error.restype = ctypes.c_char_p
|
|
52
|
+
return lib
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Connections. A file path uses the C ABI. agriql:// uses the server port."""
|
|
2
|
+
|
|
3
|
+
import socket
|
|
4
|
+
|
|
5
|
+
from agriql._ffi import load
|
|
6
|
+
from agriql.result import Result
|
|
7
|
+
|
|
8
|
+
_lib = None
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def connect(target=":memory:"):
|
|
12
|
+
if str(target).startswith("agriql://"):
|
|
13
|
+
return PortConnection(str(target))
|
|
14
|
+
return EngineConnection(str(target))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class EngineConnection:
|
|
18
|
+
def __init__(self, path):
|
|
19
|
+
global _lib
|
|
20
|
+
if _lib is None:
|
|
21
|
+
_lib = load()
|
|
22
|
+
self._lib = _lib
|
|
23
|
+
self._db = ctypes_open(self._lib, path)
|
|
24
|
+
|
|
25
|
+
def query(self, sql):
|
|
26
|
+
result = self._lib.agriql_execute(self._db, sql.encode())
|
|
27
|
+
if not result:
|
|
28
|
+
raise RuntimeError(_error(self._lib))
|
|
29
|
+
status = self._lib.agriql_result_status(result)
|
|
30
|
+
raw = self._lib.agriql_result_text(result)
|
|
31
|
+
text = raw.decode() if raw else ""
|
|
32
|
+
self._lib.agriql_free_result(result)
|
|
33
|
+
if status != 0:
|
|
34
|
+
raise RuntimeError(text or _error(self._lib))
|
|
35
|
+
return Result(text)
|
|
36
|
+
|
|
37
|
+
def close(self):
|
|
38
|
+
if self._db:
|
|
39
|
+
self._lib.agriql_close(self._db)
|
|
40
|
+
self._db = None
|
|
41
|
+
|
|
42
|
+
def __enter__(self):
|
|
43
|
+
return self
|
|
44
|
+
|
|
45
|
+
def __exit__(self, *_args):
|
|
46
|
+
self.close()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class PortConnection:
|
|
50
|
+
def __init__(self, url):
|
|
51
|
+
raw = url.replace("agriql://", "", 1)
|
|
52
|
+
database = None
|
|
53
|
+
if "/" in raw:
|
|
54
|
+
raw, database = raw.split("/", 1)
|
|
55
|
+
host, port = raw.rsplit(":", 1)
|
|
56
|
+
self.host = host
|
|
57
|
+
self.port = int(port)
|
|
58
|
+
self.database = database
|
|
59
|
+
|
|
60
|
+
def query(self, sql):
|
|
61
|
+
sock = socket.create_connection((self.host, self.port), timeout=5)
|
|
62
|
+
try:
|
|
63
|
+
payload = ""
|
|
64
|
+
if self.database:
|
|
65
|
+
payload += f"USE DATABASE {self.database};\n"
|
|
66
|
+
payload += sql.strip() + "\n.quit\n"
|
|
67
|
+
sock.sendall(payload.encode())
|
|
68
|
+
data = b""
|
|
69
|
+
while True:
|
|
70
|
+
chunk = sock.recv(65536)
|
|
71
|
+
if not chunk:
|
|
72
|
+
break
|
|
73
|
+
data += chunk
|
|
74
|
+
finally:
|
|
75
|
+
sock.close()
|
|
76
|
+
if not data:
|
|
77
|
+
raise ConnectionError(f"agriql://{self.host}:{self.port} closed without a reply")
|
|
78
|
+
return Result(data.decode())
|
|
79
|
+
|
|
80
|
+
def close(self):
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
def __enter__(self):
|
|
84
|
+
return self
|
|
85
|
+
|
|
86
|
+
def __exit__(self, *_args):
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def ctypes_open(lib, path):
|
|
91
|
+
import ctypes
|
|
92
|
+
|
|
93
|
+
out = ctypes.c_void_p()
|
|
94
|
+
encoded = None if path in ("", ":memory:") else path.encode()
|
|
95
|
+
status = lib.agriql_open(encoded, ctypes.byref(out))
|
|
96
|
+
if status != 0 or not out.value:
|
|
97
|
+
raise RuntimeError(_error(lib))
|
|
98
|
+
return out.value
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _error(lib):
|
|
102
|
+
raw = lib.agriql_thread_error()
|
|
103
|
+
if not raw:
|
|
104
|
+
return "AGRIQL-2701: the engine returned no message"
|
|
105
|
+
return raw.decode()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""A query result is a grid from the engine. pandas, Polars, and Arrow are optional views."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Result:
|
|
5
|
+
def __init__(self, text):
|
|
6
|
+
self.text = text
|
|
7
|
+
|
|
8
|
+
def to_records(self):
|
|
9
|
+
lines = [line for line in self.text.splitlines() if line]
|
|
10
|
+
if len(lines) < 2 or "\t" not in lines[0]:
|
|
11
|
+
return [{"text": line} for line in lines]
|
|
12
|
+
header = lines[0].split("\t")
|
|
13
|
+
return [dict(zip(header, line.split("\t"))) for line in lines[1:]]
|
|
14
|
+
|
|
15
|
+
def to_pandas(self):
|
|
16
|
+
try:
|
|
17
|
+
import pandas as pd
|
|
18
|
+
except ImportError as exc:
|
|
19
|
+
raise ImportError("pandas is not installed. Use pip install 'agriql[pandas]'.") from exc
|
|
20
|
+
return pd.DataFrame(self.to_records())
|
|
21
|
+
|
|
22
|
+
def to_polars(self):
|
|
23
|
+
try:
|
|
24
|
+
import polars as pl
|
|
25
|
+
except ImportError as exc:
|
|
26
|
+
raise ImportError("polars is not installed. Use pip install 'agriql[polars]'.") from exc
|
|
27
|
+
return pl.DataFrame(self.to_records())
|
|
28
|
+
|
|
29
|
+
def to_arrow(self):
|
|
30
|
+
try:
|
|
31
|
+
import pyarrow as pa
|
|
32
|
+
except ImportError as exc:
|
|
33
|
+
raise ImportError(
|
|
34
|
+
"pyarrow is not installed. The engine does not emit Arrow IPC yet. "
|
|
35
|
+
"Use pip install 'agriql[arrow]' to build a table from the result grid."
|
|
36
|
+
) from exc
|
|
37
|
+
return pa.Table.from_pylist(self.to_records())
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agriql
|
|
3
|
+
Version: 3.10.1
|
|
4
|
+
Summary: Client for the AgriQL engine. This package is not a database.
|
|
5
|
+
Author-email: Sbruice Singh <sbruicesingh@haclon.in>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/SbruiceS/agriql-python
|
|
8
|
+
Project-URL: Issues, https://github.com/SbruiceS/agriql-python/issues
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Provides-Extra: pandas
|
|
13
|
+
Requires-Dist: pandas; extra == "pandas"
|
|
14
|
+
Provides-Extra: polars
|
|
15
|
+
Requires-Dist: polars; extra == "polars"
|
|
16
|
+
Provides-Extra: arrow
|
|
17
|
+
Requires-Dist: pyarrow; extra == "arrow"
|
|
18
|
+
Provides-Extra: geo
|
|
19
|
+
Requires-Dist: geopandas; extra == "geo"
|
|
20
|
+
Provides-Extra: ml
|
|
21
|
+
Requires-Dist: numpy; extra == "ml"
|
|
22
|
+
Provides-Extra: all
|
|
23
|
+
Requires-Dist: pandas; extra == "all"
|
|
24
|
+
Requires-Dist: polars; extra == "all"
|
|
25
|
+
Requires-Dist: pyarrow; extra == "all"
|
|
26
|
+
Requires-Dist: numpy; extra == "all"
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# agriql
|
|
30
|
+
|
|
31
|
+
Python client for the AgriQL engine. `import agriql` does not start a second database.
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
import agriql
|
|
35
|
+
|
|
36
|
+
db = agriql.connect("farm.aqdb")
|
|
37
|
+
result = db.query("SELECT plant_id, soil_moisture FROM agriculture.soil")
|
|
38
|
+
result.to_records()
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`to_pandas()`, `to_polars()`, and `to_arrow()` import those libraries only when called. Arrow IPC is not produced by the engine. `to_arrow()` builds a `pyarrow` table from the result grid.
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
`libagriql_ffi` must already be on the library path. Build it from [AgriQL](https://github.com/SbruiceS/AgriQL):
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
git clone https://github.com/SbruiceS/AgriQL.git
|
|
49
|
+
cd AgriQL
|
|
50
|
+
cargo build -p agriql-ffi --release
|
|
51
|
+
sudo cp target/release/libagriql_ffi.so /usr/local/lib
|
|
52
|
+
sudo ldconfig
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Then:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install git+https://github.com/SbruiceS/agriql-python.git
|
|
59
|
+
pip install "agriql[pandas] @ git+https://github.com/SbruiceS/agriql-python.git"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
If the library is not in a default directory, set `AGRIQL_FFI` to the full path of `libagriql_ffi.so`.
|
|
63
|
+
|
|
64
|
+
`agriql.connect("agriql://127.0.0.1:5471/farm")` uses the server port instead of the library. This package is not published on PyPI.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
agriql/__init__.py
|
|
5
|
+
agriql/__main__.py
|
|
6
|
+
agriql/_ffi.py
|
|
7
|
+
agriql/connection.py
|
|
8
|
+
agriql/result.py
|
|
9
|
+
agriql.egg-info/PKG-INFO
|
|
10
|
+
agriql.egg-info/SOURCES.txt
|
|
11
|
+
agriql.egg-info/dependency_links.txt
|
|
12
|
+
agriql.egg-info/entry_points.txt
|
|
13
|
+
agriql.egg-info/requires.txt
|
|
14
|
+
agriql.egg-info/top_level.txt
|
|
15
|
+
tests/test_client.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
agriql
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "agriql"
|
|
3
|
+
version = "3.10.1"
|
|
4
|
+
description = "Client for the AgriQL engine. This package is not a database."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.9"
|
|
7
|
+
license = "Apache-2.0"
|
|
8
|
+
authors = [{ name = "Sbruice Singh", email = "sbruicesingh@haclon.in" }]
|
|
9
|
+
dependencies = []
|
|
10
|
+
|
|
11
|
+
[project.urls]
|
|
12
|
+
Homepage = "https://github.com/SbruiceS/agriql-python"
|
|
13
|
+
Issues = "https://github.com/SbruiceS/agriql-python/issues"
|
|
14
|
+
|
|
15
|
+
[project.optional-dependencies]
|
|
16
|
+
pandas = ["pandas"]
|
|
17
|
+
polars = ["polars"]
|
|
18
|
+
arrow = ["pyarrow"]
|
|
19
|
+
geo = ["geopandas"]
|
|
20
|
+
ml = ["numpy"]
|
|
21
|
+
all = ["pandas", "polars", "pyarrow", "numpy"]
|
|
22
|
+
|
|
23
|
+
[project.scripts]
|
|
24
|
+
agriql = "agriql.__main__:main"
|
|
25
|
+
|
|
26
|
+
[build-system]
|
|
27
|
+
requires = ["setuptools>=68"]
|
|
28
|
+
build-backend = "setuptools.build_meta"
|
|
29
|
+
|
|
30
|
+
[tool.setuptools.packages.find]
|
|
31
|
+
where = ["."]
|
|
32
|
+
include = ["agriql*"]
|
agriql-3.10.1/setup.cfg
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import tempfile
|
|
3
|
+
import unittest
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from agriql import connect
|
|
7
|
+
from agriql.result import Result
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ClientTest(unittest.TestCase):
|
|
11
|
+
def test_memory_query_uses_the_engine(self):
|
|
12
|
+
db = connect(":memory:")
|
|
13
|
+
text = db.query("SHOW VERSION;").text
|
|
14
|
+
self.assertIn("engine=3.10.1", text)
|
|
15
|
+
db.close()
|
|
16
|
+
|
|
17
|
+
def test_aqdb_file_round_trip(self):
|
|
18
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
19
|
+
os.environ["AGRIQL_DATA_DIR"] = tmp
|
|
20
|
+
created = connect(":memory:")
|
|
21
|
+
created.query("CREATE DATABASE farm;")
|
|
22
|
+
created.close()
|
|
23
|
+
path = Path(tmp) / "databases" / "farm.aqdb"
|
|
24
|
+
self.assertTrue(path.is_file(), path)
|
|
25
|
+
db = connect(str(path))
|
|
26
|
+
db.query("CREATE SCHEMA fields;")
|
|
27
|
+
db.close()
|
|
28
|
+
again = connect(str(path))
|
|
29
|
+
self.assertIn("fields", again.query("SHOW SCHEMAS;").text)
|
|
30
|
+
again.close()
|
|
31
|
+
|
|
32
|
+
def test_records_and_missing_optional_libraries(self):
|
|
33
|
+
result = Result("plant_id\tsoil_moisture\na\t10\n")
|
|
34
|
+
self.assertEqual(result.to_records(), [{"plant_id": "a", "soil_moisture": "10"}])
|
|
35
|
+
with self.assertRaises(ImportError):
|
|
36
|
+
result.to_pandas()
|
|
37
|
+
with self.assertRaises(ImportError):
|
|
38
|
+
result.to_polars()
|
|
39
|
+
with self.assertRaises(ImportError):
|
|
40
|
+
result.to_arrow()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == "__main__":
|
|
44
|
+
unittest.main()
|