pglib 5.10.0__tar.gz → 5.12.0__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 (56) hide show
  1. {pglib-5.10.0 → pglib-5.12.0}/MANIFEST.in +0 -2
  2. pglib-5.12.0/PKG-INFO +34 -0
  3. {pglib-5.10.0 → pglib-5.12.0}/README.rst +2 -2
  4. pglib-5.12.0/pglib.egg-info/PKG-INFO +34 -0
  5. {pglib-5.10.0 → pglib-5.12.0}/pglib.egg-info/SOURCES.txt +2 -18
  6. pglib-5.12.0/pglib.egg-info/requires.txt +3 -0
  7. pglib-5.12.0/pyproject.toml +40 -0
  8. pglib-5.12.0/setup.cfg +4 -0
  9. {pglib-5.10.0 → pglib-5.12.0}/setup.py +11 -63
  10. {pglib-5.10.0 → pglib-5.12.0}/src/connection.cpp +108 -0
  11. {pglib-5.10.0 → pglib-5.12.0}/test/test_async.py +10 -15
  12. {pglib-5.10.0 → pglib-5.12.0}/test/test_sync.py +33 -0
  13. {pglib-5.10.0 → pglib-5.12.0}/test/testutils.py +18 -16
  14. pglib-5.10.0/PKG-INFO +0 -25
  15. pglib-5.10.0/pglib.egg-info/PKG-INFO +0 -25
  16. pglib-5.10.0/setup.cfg +0 -10
  17. {pglib-5.10.0 → pglib-5.12.0}/LICENSE +0 -0
  18. {pglib-5.10.0 → pglib-5.12.0}/pglib/__init__.py +0 -0
  19. {pglib-5.10.0 → pglib-5.12.0}/pglib/asyncpglib.py +0 -0
  20. {pglib-5.10.0 → pglib-5.12.0}/pglib.egg-info/dependency_links.txt +0 -0
  21. {pglib-5.10.0 → pglib-5.12.0}/pglib.egg-info/top_level.txt +0 -0
  22. {pglib-5.10.0 → pglib-5.12.0}/src/byteswap.h +0 -0
  23. {pglib-5.10.0 → pglib-5.12.0}/src/connection.h +0 -0
  24. {pglib-5.10.0 → pglib-5.12.0}/src/conninfoopt.cpp +0 -0
  25. {pglib-5.10.0 → pglib-5.12.0}/src/conninfoopt.h +0 -0
  26. {pglib-5.10.0 → pglib-5.12.0}/src/datatypes.cpp +0 -0
  27. {pglib-5.10.0 → pglib-5.12.0}/src/datatypes.h +0 -0
  28. {pglib-5.10.0 → pglib-5.12.0}/src/debug.cpp +0 -0
  29. {pglib-5.10.0 → pglib-5.12.0}/src/debug.h +0 -0
  30. {pglib-5.10.0 → pglib-5.12.0}/src/enums.cpp +0 -0
  31. {pglib-5.10.0 → pglib-5.12.0}/src/enums.h +0 -0
  32. {pglib-5.10.0 → pglib-5.12.0}/src/errors.cpp +0 -0
  33. {pglib-5.10.0 → pglib-5.12.0}/src/errors.h +0 -0
  34. {pglib-5.10.0 → pglib-5.12.0}/src/getdata.cpp +0 -0
  35. {pglib-5.10.0 → pglib-5.12.0}/src/getdata.h +0 -0
  36. {pglib-5.10.0 → pglib-5.12.0}/src/juliandate.cpp +0 -0
  37. {pglib-5.10.0 → pglib-5.12.0}/src/juliandate.h +0 -0
  38. {pglib-5.10.0 → pglib-5.12.0}/src/params.cpp +0 -0
  39. {pglib-5.10.0 → pglib-5.12.0}/src/params.h +0 -0
  40. {pglib-5.10.0 → pglib-5.12.0}/src/pgarrays.cpp +0 -0
  41. {pglib-5.10.0 → pglib-5.12.0}/src/pgarrays.h +0 -0
  42. {pglib-5.10.0 → pglib-5.12.0}/src/pglib.cpp +0 -0
  43. {pglib-5.10.0 → pglib-5.12.0}/src/pglib.h +0 -0
  44. {pglib-5.10.0 → pglib-5.12.0}/src/pgtypes.h +0 -0
  45. {pglib-5.10.0 → pglib-5.12.0}/src/resultset.cpp +0 -0
  46. {pglib-5.10.0 → pglib-5.12.0}/src/resultset.h +0 -0
  47. {pglib-5.10.0 → pglib-5.12.0}/src/row.cpp +0 -0
  48. {pglib-5.10.0 → pglib-5.12.0}/src/row.h +0 -0
  49. {pglib-5.10.0 → pglib-5.12.0}/src/runtime.cpp +0 -0
  50. {pglib-5.10.0 → pglib-5.12.0}/src/runtime.h +0 -0
  51. {pglib-5.10.0 → pglib-5.12.0}/src/type_hstore.cpp +0 -0
  52. {pglib-5.10.0 → pglib-5.12.0}/src/type_hstore.h +0 -0
  53. {pglib-5.10.0 → pglib-5.12.0}/src/type_json.cpp +0 -0
  54. {pglib-5.10.0 → pglib-5.12.0}/src/type_json.h +0 -0
  55. {pglib-5.10.0 → pglib-5.12.0}/src/type_ltree.cpp +0 -0
  56. {pglib-5.10.0 → pglib-5.12.0}/src/type_ltree.h +0 -0
@@ -1,5 +1,3 @@
1
1
  include README.rst
2
2
  include src/*.h
3
3
  include src/*.cpp
4
- include versioneer.py
5
- include pglib/_version.py
pglib-5.12.0/PKG-INFO ADDED
@@ -0,0 +1,34 @@
1
+ Metadata-Version: 2.4
2
+ Name: pglib
3
+ Version: 5.12.0
4
+ Summary: A PostgreSQL interface
5
+ Author-email: Michael Kleehammer <michael@kleehammer.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://gitlab.com/mkleehammer/pglib
8
+ Project-URL: Repository, https://gitlab.com/mkleehammer/pglib
9
+ Keywords: postgresql,postgres
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Topic :: Database
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/x-rst
20
+ License-File: LICENSE
21
+ Provides-Extra: test
22
+ Requires-Dist: pytest; extra == "test"
23
+ Dynamic: license-file
24
+
25
+
26
+ pglib is a Python 3.10+ module for working with PostgreSQL databases. It is a C extension that
27
+ exposes the `libpq <http://www.postgresql.org/docs/current/static/libpq.html>`_ API. It is
28
+ designed to be small, fast, and as convenient as possible. It provides both synchronous and
29
+ asynchronous APIs.
30
+
31
+ Unlike some libraries, it never modifies the SQL you pass. Parameters are passed using the
32
+ official libpq protocol for parameters.
33
+
34
+ Documentation is available in /docs and online at http://pglib.readthedocs.org
@@ -1,6 +1,6 @@
1
1
 
2
- pglib is a Python 3.6+ module for working with PostgreSQL databases. It is a C extension that
3
- exposes the `libpq <http://www.postgresql.org/docs/9.3/static/libpq.html>`_ API. It is
2
+ pglib is a Python 3.10+ module for working with PostgreSQL databases. It is a C extension that
3
+ exposes the `libpq <http://www.postgresql.org/docs/current/static/libpq.html>`_ API. It is
4
4
  designed to be small, fast, and as convenient as possible. It provides both synchronous and
5
5
  asynchronous APIs.
6
6
 
@@ -0,0 +1,34 @@
1
+ Metadata-Version: 2.4
2
+ Name: pglib
3
+ Version: 5.12.0
4
+ Summary: A PostgreSQL interface
5
+ Author-email: Michael Kleehammer <michael@kleehammer.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://gitlab.com/mkleehammer/pglib
8
+ Project-URL: Repository, https://gitlab.com/mkleehammer/pglib
9
+ Keywords: postgresql,postgres
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Topic :: Database
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/x-rst
20
+ License-File: LICENSE
21
+ Provides-Extra: test
22
+ Requires-Dist: pytest; extra == "test"
23
+ Dynamic: license-file
24
+
25
+
26
+ pglib is a Python 3.10+ module for working with PostgreSQL databases. It is a C extension that
27
+ exposes the `libpq <http://www.postgresql.org/docs/current/static/libpq.html>`_ API. It is
28
+ designed to be small, fast, and as convenient as possible. It provides both synchronous and
29
+ asynchronous APIs.
30
+
31
+ Unlike some libraries, it never modifies the SQL you pass. Parameters are passed using the
32
+ official libpq protocol for parameters.
33
+
34
+ Documentation is available in /docs and online at http://pglib.readthedocs.org
@@ -1,30 +1,14 @@
1
1
  LICENSE
2
2
  MANIFEST.in
3
3
  README.rst
4
- setup.cfg
4
+ pyproject.toml
5
5
  setup.py
6
- /home/mkleehammer/dev/pglib/src/connection.cpp
7
- /home/mkleehammer/dev/pglib/src/conninfoopt.cpp
8
- /home/mkleehammer/dev/pglib/src/datatypes.cpp
9
- /home/mkleehammer/dev/pglib/src/debug.cpp
10
- /home/mkleehammer/dev/pglib/src/enums.cpp
11
- /home/mkleehammer/dev/pglib/src/errors.cpp
12
- /home/mkleehammer/dev/pglib/src/getdata.cpp
13
- /home/mkleehammer/dev/pglib/src/juliandate.cpp
14
- /home/mkleehammer/dev/pglib/src/params.cpp
15
- /home/mkleehammer/dev/pglib/src/pgarrays.cpp
16
- /home/mkleehammer/dev/pglib/src/pglib.cpp
17
- /home/mkleehammer/dev/pglib/src/resultset.cpp
18
- /home/mkleehammer/dev/pglib/src/row.cpp
19
- /home/mkleehammer/dev/pglib/src/runtime.cpp
20
- /home/mkleehammer/dev/pglib/src/type_hstore.cpp
21
- /home/mkleehammer/dev/pglib/src/type_json.cpp
22
- /home/mkleehammer/dev/pglib/src/type_ltree.cpp
23
6
  pglib/__init__.py
24
7
  pglib/asyncpglib.py
25
8
  pglib.egg-info/PKG-INFO
26
9
  pglib.egg-info/SOURCES.txt
27
10
  pglib.egg-info/dependency_links.txt
11
+ pglib.egg-info/requires.txt
28
12
  pglib.egg-info/top_level.txt
29
13
  src/byteswap.h
30
14
  src/connection.cpp
@@ -0,0 +1,3 @@
1
+
2
+ [test]
3
+ pytest
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pglib"
7
+ version = "5.12.0"
8
+ description = "A PostgreSQL interface"
9
+ readme = "README.rst"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.10"
13
+ authors = [
14
+ {name = "Michael Kleehammer", email = "michael@kleehammer.com"}
15
+ ]
16
+ keywords = ["postgresql", "postgres"]
17
+ classifiers = [
18
+ "Development Status :: 5 - Production/Stable",
19
+ "Intended Audience :: Developers",
20
+ "Topic :: Database",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3 :: Only",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.14",
26
+ ]
27
+
28
+ [project.urls]
29
+ Homepage = "https://gitlab.com/mkleehammer/pglib"
30
+ Repository = "https://gitlab.com/mkleehammer/pglib"
31
+
32
+ [project.optional-dependencies]
33
+ test = ["pytest"]
34
+
35
+ [tool.setuptools.packages.find]
36
+ where = ["."]
37
+ include = ["pglib*"]
38
+
39
+ [tool.pytest.ini_options]
40
+ testpaths = ["test"]
pglib-5.12.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -1,36 +1,24 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
- import sys, os, re
4
- import subprocess, sysconfig
3
+ import sys
4
+ import os
5
+ import re
6
+ import subprocess
7
+ import sysconfig
5
8
  from os.path import join, abspath, dirname
6
9
 
7
- try:
8
- from setuptools import setup, Extension
9
- except:
10
- from distutils.core import setup, Extension
11
-
12
- long_description = """\
13
- A PostgreSQL interface for Python.
14
-
15
- This provides an interface to the libpq library. It is not an DB API
16
- library, but is instead designed to match the interface PostgreSQL
17
- offers.
18
- """
10
+ from setuptools import setup, Extension
19
11
 
20
12
 
21
13
  def _get_osx_sdkpath():
22
14
  """
23
15
  Use xcodebuild to find the latest installed OS X SDK and return the path to it.
24
16
  """
25
- # The output is in blank line separated sections. Find the section for the latest OS/X SDK
26
- # and get the Path entry.
27
-
28
17
  output = subprocess.check_output(['xcodebuild', '-version', '-sdk']).strip().decode('utf-8')
29
18
 
30
19
  highest = (0, 0)
31
- path = None
20
+ path = None
32
21
 
33
- # MacOSX10.8.sdk - OS X 10.8 (macosx10.8)
34
22
  resection = re.compile(r'^.*- (?:OS X|macOS) (\d+)\.(\d+)')
35
23
  repath = re.compile('^Path: ([^\n]+)', re.MULTILINE)
36
24
 
@@ -50,27 +38,14 @@ def _get_osx_sdkpath():
50
38
  return path
51
39
 
52
40
 
53
- def getoutput(cmd):
54
- pipe = os.popen(cmd, 'r')
55
- text = pipe.read().rstrip('\n')
56
- status = pipe.close() or 0
57
- return status, text
58
-
59
-
60
41
  def _get_files():
61
- return [abspath(join('src', f)) for f in os.listdir('src') if f.endswith('.cpp')]
42
+ return [join('src', f) for f in os.listdir('src') if f.endswith('.cpp')]
62
43
 
63
44
 
64
45
  def _get_settings():
65
-
66
- # version = get_version()
67
- #
68
- # settings = { 'define_macros' : [ ('PGLIB_VERSION', version) ] }
69
-
70
46
  settings = {'define_macros': []}
71
47
 
72
- # This isn't the best or right way to do this, but I don't see how someone is supposed to sanely subclass the build
73
- # command.
48
+ # Custom build options
74
49
  for option in ['assert', 'trace', 'leak-check']:
75
50
  try:
76
51
  sys.argv.remove('--%s' % option)
@@ -90,17 +65,12 @@ def _get_settings():
90
65
  ]
91
66
 
92
67
  if '--debug' in sys.argv:
93
- # TODO: The build command already has debug. Pass it in.
94
68
  sys.argv.remove('--debug')
95
69
  settings['extra_compile_args'].extend('/Od /Ge /GS /GZ /RTC1 /Wp64 /Yd'.split())
96
70
 
97
71
  settings['libraries'] = ['libpq', 'Ws2_32']
98
72
 
99
73
  elif sys.platform == 'darwin':
100
- # Apple is not making it easy for non-Xcode builds. We'll always build with the latest
101
- # SDK we can find but we'll set the version we are targeting to the same one that
102
- # Python was built with.
103
-
104
74
  sdkpath = _get_osx_sdkpath()
105
75
 
106
76
  settings['include_dirs'] = [
@@ -109,7 +79,7 @@ def _get_settings():
109
79
  subprocess.check_output(['pg_config', '--includedir']).strip().decode('utf-8')
110
80
  ]
111
81
  settings['library_dirs'] = [subprocess.check_output(['pg_config', '--libdir']).strip().decode('utf-8')]
112
- settings['libraries'] = ['pq']
82
+ settings['libraries'] = ['pq']
113
83
 
114
84
  settings['define_macros'].append(('MAC_OS_X_VERSION_10_7',))
115
85
 
@@ -117,37 +87,15 @@ def _get_settings():
117
87
 
118
88
  else:
119
89
  # Other posix-like: Linux, Solaris, etc.
120
-
121
90
  settings['include_dirs'] = [subprocess.check_output(['pg_config', '--includedir']).strip().decode('utf-8')]
122
91
  settings['library_dirs'] = [subprocess.check_output(['pg_config', '--libdir']).strip().decode('utf-8')]
123
- settings['libraries'] = ['pq']
92
+ settings['libraries'] = ['pq']
124
93
 
125
- # Python functions take a lot of 'char *' that really should be const. gcc complains about this *a lot*
126
94
  settings['extra_compile_args'] = ['-Wno-write-strings']
127
95
 
128
96
  return settings
129
97
 
130
98
 
131
99
  setup(
132
- name='pglib',
133
- version='5.10.0',
134
- description='A PostgreSQL interface',
135
- long_description=long_description,
136
- maintainer='Michael Kleehammer',
137
- maintainer_email='michael@kleehammer.com',
138
- packages=['pglib'],
139
100
  ext_modules=[Extension('_pglib', _get_files(), **_get_settings())],
140
- keywords='postgresql postgres',
141
- tests_require=['pytest'],
142
- url='https://gitlab.com/mkleehammer/pglib',
143
- license='MIT',
144
- classifiers=[
145
- # https://pypi.python.org/pypi?%3Aaction=list_classifiers
146
- 'Development Status :: 5 - Production/Stable',
147
- 'Intended Audience :: Developers',
148
- 'Topic :: Database',
149
- 'License :: OSI Approved :: MIT License',
150
- 'Programming Language :: Python :: 3',
151
- 'Programming Language :: Python :: 3 :: Only'
152
- ]
153
101
  )
@@ -365,6 +365,113 @@ static PyObject* Connection_copy_from(PyObject* self, PyObject* args)
365
365
  }
366
366
 
367
367
 
368
+ const char* doc_copy_to =
369
+ "Connection.copy_to(command, dest) --> int\n"
370
+ "\n"
371
+ "Executes the given COPY TO command and returns the number of records copied.\n"
372
+ "\n"
373
+ "command\n"
374
+ " The copy command which must be 'to stdout'.\n"
375
+ "\n"
376
+ "dest\n"
377
+ " The file-like object to write to. Strings will be written, not bytes, so\n"
378
+ " open in text mode.\n"
379
+ "\n"
380
+ "Examples:\n"
381
+ " cnxn.copy_to('copy t1 to stdout csv header', open('test.csv', 'w'))\n"
382
+ " cnxn.copy_to('copy t1(a, b, c) to stdout csv header', open('test.csv', 'w'))\n"
383
+ " cnxn.copy_to('copy (select * from t1 where id > 10) to stdout csv', f)\n";
384
+
385
+ static PyObject* Connection_copy_to(PyObject* self, PyObject* args)
386
+ {
387
+ PyObject* command;
388
+ PyObject* dest;
389
+ if (!PyArg_ParseTuple(args, "UO", &command, &dest))
390
+ return 0;
391
+
392
+ Connection* cnxn = CastConnection(self, REQUIRE_OPEN);
393
+ if (!cnxn)
394
+ return 0;
395
+
396
+ if (!PyObject_HasAttrString(dest, "write"))
397
+ return PyErr_Format(Error, "Destination must be a file-like object.");
398
+ Object write_method(PyObject_GetAttrString(dest, "write"));
399
+
400
+ const char* szSQL = PyUnicode_AsUTF8(command);
401
+ if (!szSQL)
402
+ return 0;
403
+
404
+ ResultHolder result;
405
+ Py_BEGIN_ALLOW_THREADS
406
+ result = PQexec(cnxn->pgconn, szSQL);
407
+ Py_END_ALLOW_THREADS
408
+
409
+ if (result == 0)
410
+ return 0;
411
+
412
+ switch (PQresultStatus(result)) {
413
+ case PGRES_COPY_OUT:
414
+ // This is what we are expecting.
415
+ break;
416
+
417
+ case PGRES_BAD_RESPONSE:
418
+ case PGRES_NONFATAL_ERROR:
419
+ case PGRES_FATAL_ERROR:
420
+ return SetResultError(result.Detach());
421
+
422
+ default:
423
+ return PyErr_Format(Error, "Result was not PGRES_COPY_OUT: %d", (int)PQresultStatus(result));
424
+ }
425
+
426
+
427
+ for (;;) {
428
+ int cb = 0;
429
+ char* buffer;
430
+ Py_BEGIN_ALLOW_THREADS
431
+ cb = PQgetCopyData(cnxn->pgconn, &buffer, 0);
432
+ Py_END_ALLOW_THREADS
433
+
434
+ if (cb == -2) {
435
+ return SetResultError(result.Detach());
436
+ }
437
+
438
+ if (cb == -1) {
439
+ // The copy is complete.
440
+ break;
441
+ }
442
+
443
+ // We have a buffer of byte data. We have the length (`cb`), but the libpq docs say
444
+ // that the string is also zero terminated, so we're going to try not calling 'write'.
445
+
446
+ int err = PyFile_WriteString(buffer, dest);
447
+
448
+ PQfreemem(buffer);
449
+ if (err) {
450
+ return 0;
451
+ }
452
+ }
453
+
454
+ // After a copy, you have to get another result to know if it was successful.
455
+
456
+ ResultHolder final_result;
457
+ ExecStatusType status = PGRES_COMMAND_OK;
458
+ Py_BEGIN_ALLOW_THREADS
459
+ final_result = PQgetResult(cnxn->pgconn);
460
+ status = PQresultStatus(final_result);
461
+ Py_END_ALLOW_THREADS
462
+
463
+ if (status != PGRES_COMMAND_OK) {
464
+ // SetResultError will take ownership of `result`.
465
+ return SetResultError(final_result.Detach());
466
+ }
467
+
468
+ const char* sz = PQcmdTuples(final_result);
469
+ if (sz == 0 || *sz == 0)
470
+ Py_RETURN_NONE;
471
+ return PyLong_FromLong(atoi(sz));
472
+ }
473
+
474
+
368
475
  const char* doc_copy_to_csv =
369
476
  "Connection.copy_to_csv(table, dest, header=0, delimiter=',', quote='\"')\n"
370
477
  "\n"
@@ -1631,6 +1738,7 @@ static struct PyMethodDef Connection_methods[] =
1631
1738
  { "script", Connection_script, METH_VARARGS, doc_script },
1632
1739
  { "copy_from", (PyCFunction) Connection_copy_from, METH_VARARGS | METH_KEYWORDS, doc_copy_from },
1633
1740
  { "copy_from_csv", (PyCFunction) Connection_copy_from_csv, METH_VARARGS | METH_KEYWORDS, doc_copy_from_csv },
1741
+ { "copy_to", (PyCFunction) Connection_copy_to, METH_VARARGS, doc_copy_to },
1634
1742
  { "copy_to_csv", (PyCFunction) Connection_copy_to_csv, METH_VARARGS | METH_KEYWORDS, doc_copy_to_csv},
1635
1743
  { "begin", Connection_begin, METH_NOARGS, doc_begin },
1636
1744
  { "commit", Connection_commit, METH_NOARGS, doc_commit },
@@ -44,8 +44,7 @@ def test_async():
44
44
  assert row.b == 3
45
45
  assert row[1] == 3
46
46
 
47
- loop = asyncio.get_event_loop()
48
- loop.run_until_complete(_t())
47
+ asyncio.run(_t())
49
48
 
50
49
 
51
50
  def test_async_params():
@@ -60,8 +59,7 @@ def test_async_params():
60
59
  assert row.b == 2
61
60
  assert row[1] == 2
62
61
 
63
- loop = asyncio.get_event_loop()
64
- loop.run_until_complete(_t())
62
+ asyncio.run(_t())
65
63
 
66
64
 
67
65
  def test_async_notify():
@@ -84,8 +82,7 @@ def test_async_notify():
84
82
  assert item == sent[0]
85
83
  sent.pop(0)
86
84
 
87
- loop = asyncio.get_event_loop()
88
- loop.run_until_complete(_t())
85
+ asyncio.run(_t())
89
86
 
90
87
 
91
88
  def test_notify_and_command():
@@ -112,8 +109,7 @@ def test_notify_and_command():
112
109
  item = ns[0]
113
110
  assert item == ('test', 'both')
114
111
 
115
- loop = asyncio.get_event_loop()
116
- loop.run_until_complete(_t())
112
+ asyncio.run(_t())
117
113
 
118
114
 
119
115
  def test_notification_wait():
@@ -132,9 +128,10 @@ def test_notification_wait():
132
128
  cnxn = await pglib.connect_async(CONNINFO)
133
129
  await cnxn.notify('test')
134
130
 
135
- both = asyncio.gather(_listener(), _notifier())
136
- loop = asyncio.get_event_loop()
137
- loop.run_until_complete(both)
131
+ async def _run_both():
132
+ await asyncio.gather(_listener(), _notifier())
133
+
134
+ asyncio.run(_run_both())
138
135
 
139
136
 
140
137
  def test_notification_timeout():
@@ -144,8 +141,7 @@ def test_notification_timeout():
144
141
  ns = await cnxn.notifications(timeout=0.25)
145
142
  assert ns == []
146
143
 
147
- loop = asyncio.get_event_loop()
148
- loop.run_until_complete(_t())
144
+ asyncio.run(_t())
149
145
 
150
146
 
151
147
  def test_close():
@@ -156,5 +152,4 @@ def test_close():
156
152
  cnxn.close()
157
153
  cnxn = None
158
154
 
159
- loop = asyncio.get_event_loop()
160
- loop.run_until_complete(_t())
155
+ asyncio.run(_t())
@@ -176,6 +176,39 @@ def test_copytocsv(cnxn):
176
176
  assert rows == [['a', 'b'], ['1', 'one'], ['2', 'two'], ['3', 'three']]
177
177
 
178
178
 
179
+ def test_copy_to(cnxn):
180
+ # Test copy_to with a full command, including a subquery.
181
+ cnxn.execute("create table t1(a int, b text)")
182
+ cnxn.execute("insert into t1 values (1, 'one'), (2, 'two'), (3, 'three')")
183
+
184
+ with tempfile.NamedTemporaryFile(mode='w', encoding='utf8') as tf:
185
+ # Use a subquery to only copy rows where a > 1
186
+ count = cnxn.copy_to('copy (select * from t1 where a > 1 order by a) to stdout csv header', tf)
187
+ assert count == 2
188
+
189
+ tf.flush()
190
+ with open(tf.name, mode='r', encoding='utf8') as fd:
191
+ reader = csv.reader(fd)
192
+ rows = list(reader)
193
+ assert rows == [['a', 'b'], ['2', 'two'], ['3', 'three']]
194
+
195
+
196
+ def test_copy_to_table(cnxn):
197
+ # Test copy_to with a simple table copy (no subquery).
198
+ cnxn.execute("create table t1(a int, b text)")
199
+ cnxn.execute("insert into t1 values (1, 'one'), (2, 'two')")
200
+
201
+ with tempfile.NamedTemporaryFile(mode='w', encoding='utf8') as tf:
202
+ count = cnxn.copy_to('copy t1 to stdout csv', tf)
203
+ assert count == 2
204
+
205
+ tf.flush()
206
+ with open(tf.name, mode='r', encoding='utf8') as fd:
207
+ reader = csv.reader(fd)
208
+ rows = list(reader)
209
+ assert rows == [['1', 'one'], ['2', 'two']]
210
+
211
+
179
212
  #
180
213
  # copy from
181
214
  #
@@ -10,21 +10,22 @@ def add_to_path():
10
10
  it to be tested without installing it.
11
11
  """
12
12
  # Put the root directory into the path first so we pick up the Python code from the source
13
- # directories. It will also be in the build directory, so make sure build is 2nd!
13
+ # directories and any extension built via editable install.
14
14
 
15
15
  root = dirname(dirname(abspath(__file__)))
16
16
  sys.path.insert(0, root)
17
17
 
18
- # Put the build directory into the Python path so we pick up the version we just built.
19
- #
20
- # To make this cross platform, we'll search the directories until we find the .pyd file.
18
+ # Check if the extension is already importable (installed via pip or editable install)
19
+ try:
20
+ import _pglib
21
+ return
22
+ except ImportError:
23
+ pass
21
24
 
25
+ # Fall back to searching the build directory for legacy `python setup.py build` workflow.
22
26
  prefix = '_pglib'
23
-
24
27
  library_names = [prefix + ext for ext in EXTENSION_SUFFIXES]
25
28
 
26
- # Only go into directories that match the current Python's version number.
27
-
28
29
  dir_suffix = (
29
30
  '-%s.%s' % (sys.version_info[0], sys.version_info[1]),
30
31
  '-%s%s' % (sys.version_info[0], sys.version_info[1]),
@@ -33,17 +34,18 @@ def add_to_path():
33
34
 
34
35
  build = join(dirname(dirname(abspath(__file__))), 'build')
35
36
 
36
- for root, dirs, files in os.walk(build):
37
- for d in dirs[:]:
38
- if not d.endswith(dir_suffix):
39
- dirs.remove(d)
37
+ if os.path.isdir(build):
38
+ for root, dirs, files in os.walk(build):
39
+ for d in dirs[:]:
40
+ if not d.endswith(dir_suffix):
41
+ dirs.remove(d)
40
42
 
41
- for name in library_names:
42
- if name in files:
43
- sys.path.insert(1, root)
44
- return
43
+ for name in library_names:
44
+ if name in files:
45
+ sys.path.insert(1, root)
46
+ return
45
47
 
46
- sys.exit('Did not find the build directory')
48
+ sys.exit('Did not find _pglib extension. Run: pip install -e .')
47
49
 
48
50
 
49
51
  _TESTSTR = '0123456789-abcdefghijklmnopqrstuvwxyz-'
pglib-5.10.0/PKG-INFO DELETED
@@ -1,25 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: pglib
3
- Version: 5.10.0
4
- Summary: A PostgreSQL interface
5
- Home-page: https://gitlab.com/mkleehammer/pglib
6
- Maintainer: Michael Kleehammer
7
- Maintainer-email: michael@kleehammer.com
8
- License: MIT
9
- Keywords: postgresql postgres
10
- Platform: UNKNOWN
11
- Classifier: Development Status :: 5 - Production/Stable
12
- Classifier: Intended Audience :: Developers
13
- Classifier: Topic :: Database
14
- Classifier: License :: OSI Approved :: MIT License
15
- Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3 :: Only
17
- License-File: LICENSE
18
-
19
- A PostgreSQL interface for Python.
20
-
21
- This provides an interface to the libpq library. It is not an DB API
22
- library, but is instead designed to match the interface PostgreSQL
23
- offers.
24
-
25
-
@@ -1,25 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: pglib
3
- Version: 5.10.0
4
- Summary: A PostgreSQL interface
5
- Home-page: https://gitlab.com/mkleehammer/pglib
6
- Maintainer: Michael Kleehammer
7
- Maintainer-email: michael@kleehammer.com
8
- License: MIT
9
- Keywords: postgresql postgres
10
- Platform: UNKNOWN
11
- Classifier: Development Status :: 5 - Production/Stable
12
- Classifier: Intended Audience :: Developers
13
- Classifier: Topic :: Database
14
- Classifier: License :: OSI Approved :: MIT License
15
- Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3 :: Only
17
- License-File: LICENSE
18
-
19
- A PostgreSQL interface for Python.
20
-
21
- This provides an interface to the libpq library. It is not an DB API
22
- library, but is instead designed to match the interface PostgreSQL
23
- offers.
24
-
25
-
pglib-5.10.0/setup.cfg DELETED
@@ -1,10 +0,0 @@
1
- [tool:pytest]
2
- testpaths = test
3
-
4
- [aliases]
5
- test = pytest
6
-
7
- [egg_info]
8
- tag_build =
9
- tag_date = 0
10
-
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes