From 3af6a30df298d41a7752e2b61336c77c2c649792 Mon Sep 17 00:00:00 2001 From: PyQ Team Date: Thu, 12 Oct 2017 13:36:32 -0400 Subject: [PATCH] PyQ Release 4.1.2 --- CHANGES.rst | 2 +- INSTALL.rst | 2 +- LICENSE.rst | 2 +- README.md | 2 +- doc/conf.py | 2 +- doc/index.rst | 6 +-- doc/install/centos32on64.rst | 2 +- doc/install/install.rst | 10 ++-- doc/install/macos.rst | 4 +- doc/install/ubuntu.rst | 4 +- doc/install/update.rst | 2 +- doc/install/windows.rst | 100 +++++++++++++++++++++++++++++++++++ doc/manual/pyq.rst | 10 ++-- doc/pyq-2017.ipynb | 2 +- doc/whatsnew/changelog.rst | 25 +++++++++ doc/words.txt | 1 + setup.py | 24 ++++++++- src/pyq/__init__.py | 3 +- src/pyq/_k.c | 40 ++++++-------- src/pyq/_pt_run.py | 2 +- src/pyq/cmd.py | 12 +++-- src/pyq/tests/test_k.py | 3 +- src/pyq/tests/test_p.py | 4 +- 23 files changed, 204 insertions(+), 60 deletions(-) create mode 100644 doc/install/windows.rst diff --git a/CHANGES.rst b/CHANGES.rst index 10bd0a9..14ae3c4 120000 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1 +1 @@ -doc/CHANGES.rst \ No newline at end of file +doc/whatsnew/changelog.rst \ No newline at end of file diff --git a/INSTALL.rst b/INSTALL.rst index 4846ad4..95fcc60 120000 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -1 +1 @@ -doc/install.rst \ No newline at end of file +doc/install/install.rst \ No newline at end of file diff --git a/LICENSE.rst b/LICENSE.rst index 49f4789..c426f0d 120000 --- a/LICENSE.rst +++ b/LICENSE.rst @@ -1 +1 @@ -doc/license.rst \ No newline at end of file +doc/license/license.rst \ No newline at end of file diff --git a/README.md b/README.md index 3c6a223..9a192c6 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ data. ## Installation ```bash -pip install -i https://pypi.enlnt.com -U --no-binary pyq pyq +pip install pyq ``` For detailed installation instructions see [installation instructions][1]. diff --git a/doc/conf.py b/doc/conf.py index 653d49e..99235e2 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -18,7 +18,7 @@ try: from pyq import __version__ except ImportError: - __version__ = '4.1.1' + __version__ = '4.1.2' # If extensions (or modules to document with autodoc) are in another directory, diff --git a/doc/index.rst b/doc/index.rst index c63006a..1b94b0d 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -27,9 +27,7 @@ Quick start .. code-block:: bash - $ pip install \ - -i https://pyq.enlnt.com \ - --no-binary pyq pyq + $ pip install pyq First, make sure that PyQ is :ref:`installed ` and :ref:`up-to-date `. Start an interactive session:: @@ -71,7 +69,7 @@ Define a function in ``q``:: Call the ``q`` function from python and pretty-print the result:: - >>> x = f('IBM', date(2006,10,6)) + >>> x = q.f('IBM', date(2006,10,6)) >>> x.show() date sym qty ------------------ diff --git a/doc/install/centos32on64.rst b/doc/install/centos32on64.rst index 907edc5..0d81ca8 100644 --- a/doc/install/centos32on64.rst +++ b/doc/install/centos32on64.rst @@ -102,7 +102,7 @@ Install PyQ (note, PyQ 3.8.2 or newer required): .. code-block:: bash - (pyq3) $ pip install -i https://pyq.enlnt.com --no-binary pyq pyq>=3.8.2 + (pyq3) $ pip install pyq>=3.8.2 6. Use PyQ diff --git a/doc/install/install.rst b/doc/install/install.rst index a06ae33..2d9c432 100644 --- a/doc/install/install.rst +++ b/doc/install/install.rst @@ -9,7 +9,7 @@ To install the latest version, run the following command :: - $ pip install -i https://pyq.enlnt.com --no-binary pyq pyq + $ pip install pyq .. _pre: @@ -40,13 +40,13 @@ Use following pip command to install the latest version of PyQ into your environ :: - $ pip install -i https://pyq.enlnt.com --no-binary pyq pyq + $ pip install pyq To install another version, specify which version you would like to install: :: - $ pip install -i https://pyq.enlnt.com --no-binary pyq pyq==3.8 + $ pip install pyq==4.1.2 Installing from source code @@ -112,7 +112,7 @@ Install PyQ: :: - $ pip install -i https://pyq.enlnt.com --no-binary pyq pyq + $ pip install pyq .. _update: @@ -124,3 +124,5 @@ Install PyQ: .. include:: ubuntu.rst .. include:: macos.rst + +.. include:: windows.rst diff --git a/doc/install/macos.rst b/doc/install/macos.rst index 1913b31..a30c497 100644 --- a/doc/install/macos.rst +++ b/doc/install/macos.rst @@ -29,7 +29,7 @@ Install kdb+ and PyQ: .. code-block:: bash (pyq2) $ unzip ${HOME}/Downloads/macosx.zip -d ${VIRTUAL_ENV} - (pyq2) $ pip install -i https://pyq.enlnt.com --no-binary pyq pyq + (pyq2) $ pip install pyq PyQ is ready and can be launched: @@ -72,7 +72,7 @@ using package manager `Homebrew `_. .. code-block:: bash (pyq) $ unzip ${HOME}/Downloads/macosx.zip -d ${VIRTUAL_ENV} - (pyq) $ pip install -i https://pyq.enlnt.com --no-binary pyq pyq + (pyq) $ pip install pyq PyQ is ready and can be launched: diff --git a/doc/install/ubuntu.rst b/doc/install/ubuntu.rst index 6c76c20..087f10a 100644 --- a/doc/install/ubuntu.rst +++ b/doc/install/ubuntu.rst @@ -25,7 +25,7 @@ Install PyQ: .. code-block:: bash - (py2) $ pip install -i https://pyq.enlnt.com --no-binary pyq pyq + (py2) $ pip install pyq Python 3 @@ -50,5 +50,5 @@ Install PyQ: .. code-block:: bash - (py3) $ pip3 install -i https://pyq.enlnt.com --no-binary pyq pyq + (py3) $ pip3 install pyq diff --git a/doc/install/update.rst b/doc/install/update.rst index dda6113..e6ba571 100644 --- a/doc/install/update.rst +++ b/doc/install/update.rst @@ -5,4 +5,4 @@ You can upgrade PyQ to the latest version by running: :: - pip install -i https://pyq.enlnt.com --no-binary pyq -U pyq + pip install -U pyq diff --git a/doc/install/windows.rst b/doc/install/windows.rst new file mode 100644 index 0000000..4555c10 --- /dev/null +++ b/doc/install/windows.rst @@ -0,0 +1,100 @@ +Experimental support for Windows +-------------------------------- + +PyQ 4.1.0 introduced experimental support for Windows. + +Requirements are: + +- Installation should be started using Windows Command Prompt. +- `Visual Studio 9 for Python`_, if using Python 2.7.x. +- `Microsoft Build Tools for Visual Studio 2017`_, if using Python 3.6.x +- Ensure kdb+ is installed under ``C:\q`` or the ``QHOME`` environment variable is set to the location of the kdb+ executable. + +.. _Visual Studio 9 for Python: http://aka.ms/vcpython27 +.. _Microsoft Build Tools for Visual Studio 2017: https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2017 + +Install PyQ: + +.. code-block:: batch + + pip install -U pyq + +You can start PyQ by running + +.. code-block:: text + + c:\q\w32\q.exe python.q + +.. note:: + + You will have to press ``^Z`` and then ``Enter`` key in order to get into Python REPL. This is known limitation of this version. + +You can run tests too: first install required packages: + +.. code-block:: batch + + pip install pytest pytest-pyq + +Then run: + +.. code-block:: text + + set QBIN=c:\q\w32\q.exe + %QBIN% python.q -mpytest --pyargs pyq < nul + +You can follow latest updates on Windows support on `issue gh#1`_. + + .. _issue gh#1: https://github.com/enlnt/pyq/issues/1 + + + +Installing Jupyter kernel +......................... + + +Since we have not ported the ``pyq`` executable to the Windows platform yet, setting up a working PyQ environment +on Windows requires several manual steps. + +First, it is strongly recommended to use a dedicated Python virtual environment and install ``q`` in ``%VIRTUAL_ENV%``. +Assuming that you have downloaded ``windows.zip`` from ``_ in your ``Downloads`` folder, enter the following commands: + +.. code-block:: batch + + python -mvenv py36 + py36\Scripts\activate.bat + set QHOME=%VIRTUAL_ENV%\q + "C:\Program Files\7-Zip\7z.exe" x -y -o%VIRTUAL_ENV% %HOMEPATH%\Downloads\windows.zip + del %QHOME%\q.q + set PYTHONPATH=%VIRTUAL_ENV%\lib\site-packages + set QBIN=%QHOME%\w32\q.exe + +Now you should be able to install jupyter, pyq and pyq-kernel in one command + +.. code-block:: batch + + pip install jupyter pyq pyq-kernel + +Finally, to install pyq kernel specs, run + +.. code-block:: batch + + %QBIN% python.q -mpyq.kernel install + +If everything is successful, you should see pyq_3 listed in the kernelspec list: + +.. code-block:: text + + >jupyter kernelspec list + Available kernels: + pyq_3 C:\Users\a\AppData\Roaming\jupyter\kernels\pyq_3 + python3 c:\users\a\py36\share\jupyter\kernels\python3 + +Now, start the notebook server + +.. code-block:: batch + + jupyter-notebook + +and select "PyQ 3" from the "New" menu. + +For examples of what can be done in a PyQ notebook, please see `presentation `_. diff --git a/doc/manual/pyq.rst b/doc/manual/pyq.rst index b4ea431..79f4b2c 100644 --- a/doc/manual/pyq.rst +++ b/doc/manual/pyq.rst @@ -310,13 +310,13 @@ k('0 1 3 6 10 15 21 28 36 45') * - q - Return - * - :func:`pyq.q.sums` + * - :func:`~pyq.q.sums` - the cumulative sums of the elements - * - :func:`pyq.q.prds` + * - :func:`~pyq.q.prds` - the cumulative products of the elements - * - :func:`pyq.q.maxs` + * - :func:`~pyq.q.maxs` - the maximums of the prefixes of the argument - * - :func:`pyq.q.mins` + * - :func:`~pyq.q.mins` - the minimums of the prefixes of the argument @@ -329,7 +329,7 @@ functionality: Passing :func:`operator.mul`, :func:`max` or :func:`min` as the second optional argument to :func:`itertools.accumulate`, one can get -analogues of :func:`pyq.q.prds`, :func:`pyq.q.maxs` and :func:`pyq.q.mins`. +analogues of :func:`~pyq.q.prds`, :func:`~pyq.q.maxs` and :func:`~pyq.q.mins`. Sliding window statistics diff --git a/doc/pyq-2017.ipynb b/doc/pyq-2017.ipynb index 3299a53..bddec05 100644 --- a/doc/pyq-2017.ipynb +++ b/doc/pyq-2017.ipynb @@ -2303,7 +2303,7 @@ "(free for use with kdb+ personal edition)\n", "\n", "```\n", - "pip install -i https://pyq.enlnt.com --no-binary pyq pyq\n", + "pip install pyq\n", "```\n", "\n", "## PyQ kernel for Jupyter \n", diff --git a/doc/whatsnew/changelog.rst b/doc/whatsnew/changelog.rst index fc1b766..2e4e1d0 100644 --- a/doc/whatsnew/changelog.rst +++ b/doc/whatsnew/changelog.rst @@ -4,6 +4,29 @@ Version History =============== +`PyQ 4.1.2 `_ +------------------------------------------------------ + +Released on 2017-10-12 + +Bug fixes and enhancements + + - !589 - BUG #955 Check for negative values (including 0Ni) in enums. + - !590 - BUG #956 Do not use clr. + - !591 - ENH #958 Support for building wheels. + - !594 - BUG #960 Do not colorize the q) prompt on Windows. + - !597 - BUG #962 Removed 'collections' from lazy_converters. + - !598 - MNT #963 Fixed issue identified by lgtm.com. + + +Documentation + + - !588 - DOC #954 Windows documentation. + - !595 - DOC #961 Fixed a typo in an introductory example. + - !599 - DOC #964 Updated documentation in preparation for 4.1.2 release. + + + `PyQ 4.1.1 `_ ------------------------------------------------------ @@ -707,3 +730,5 @@ implemented K._ja ln guid aN + clr + lgtm diff --git a/doc/words.txt b/doc/words.txt index 7f57114..3989fec 100644 --- a/doc/words.txt +++ b/doc/words.txt @@ -135,3 +135,4 @@ ktd Gitlab Centos ubuntu +kernelspec diff --git a/setup.py b/setup.py index 823c106..38951c0 100644 --- a/setup.py +++ b/setup.py @@ -38,7 +38,7 @@ else: from distutils.core import Command, Distribution, Extension, setup -VERSION = '4.1.1' +VERSION = '4.1.2' IS_RELEASE = True VERSION_FILE = 'src/pyq/version.py' VERSION_PY = """\ @@ -84,6 +84,11 @@ 'src/scripts/pq', 'src/scripts/qp', ], + data_files=[ + ('q', ['src/pyq/p.k', + 'src/pyq/pyq-operators.q', + 'src/pyq/python.q']), + ], url='http://pyq.enlnt.com', author='Enlightenment Research, LLC', author_email='pyq@enlnt.com', @@ -106,11 +111,23 @@ 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: Implementation :: CPython', 'Topic :: Database', - 'Topic :: Software Development :: Libraries' + 'Topic :: Software Development :: Libraries' + ' :: Python Modules'], ) +def add_data_file(data_files, target, source): + """Add an entry to data_files""" + for t, f in data_files: + if t == target: + break + else: + data_files.append((target, [])) + f = data_files[-1][1] + if source not in f: + f.append(source) + + def get_version(): write_version_file = True if IS_RELEASE: @@ -330,6 +347,7 @@ def write_pyq_config(self): pyq_config_file = os.path.join(self.build_lib, 'pyq-config.q') with open(pyq_config_file, 'w') as f: f.write(PYQ_CONFIG.format(**vars(self))) + add_data_file(self.distribution.data_files, 'q', pyq_config_file) class BuildQExt(Command): @@ -418,6 +436,8 @@ def run(self): compiler.link_shared_object(objects, ext_path, extra_postargs=extra_args) + add_data_file(self.distribution.data_files, + os.path.join('q', self.q_arch), ext_path) class BuildPyExt(build_ext): diff --git a/src/pyq/__init__.py b/src/pyq/__init__.py index a1ea93f..200b633 100755 --- a/src/pyq/__init__.py +++ b/src/pyq/__init__.py @@ -737,13 +737,12 @@ def _tupletok(x): converters[buffer] = K._kp except NameError: buffer = str - pass + ############################################################################### # Lazy addition of converters ############################################################################### lazy_converters = {'uuid': [('UUID', lambda u: K._kguid(u.int))], - 'collections': [('OrderedDict', converters[dict])], 'py._path.local': [('LocalPath', lambda p: q.hsym(p.strpath))], 'pathlib': [('PurePath', lambda p: K(':' + str(p)))], diff --git a/src/pyq/_k.c b/src/pyq/_k.c index b8a272a..fee9703 100755 --- a/src/pyq/_k.c +++ b/src/pyq/_k.c @@ -148,20 +148,12 @@ PY_STR_AsStringAndSize(PyObject *obj, char **pstr, Py_ssize_t *psize) #endif /* PY_MAJOR_VERSION >= 3 */ /* ^^^ Py3K compatibility ^^^ */ -/* these should be in k.h */ -#if KXVER >= 3 && KXVER2 >= 5 +#define HAVE_EE (KXVER >= 3 && KXVER2 >= 5) + +#if HAVE_EE K ee(K); -#elif !defined (WIN32) && !defined(_WIN32) -V clr(V); -K1(ee) -{ - P(x, x); - x = ka(-128); - xs = "n/a"; - clr(); - R x; -} -#endif /* ver >= 3.5 */ +#endif /* have ee() */ + ZK km(I i) { @@ -324,13 +316,13 @@ K_dot(KObject * self, KObject *args) if (K_Check(args)) { K x; Py_BEGIN_ALLOW_THREADS -#if KXVER >= 3 && KXVER2 >= 5 +#if HAVE_EE x = dot(self->x, args->x); if (!x) x = ee(x); #else x = k(0, ".", r1(self->x), r1(args->x), (K)0); -#endif /* ver >= 3.5 */ +#endif /* have ee() */ Py_END_ALLOW_THREADS return KObject_FromK(Py_TYPE(self), x); } @@ -387,13 +379,13 @@ K_a0(KObject * self) return (PyObject *)self; } Py_BEGIN_ALLOW_THREADS -#if KXVER >= 3 && KXVER2 >= 5 +#if HAVE_EE x = dot(x, k_noargs); if (!x) x = ee(x); #else x = k(0, "@", r1(x), r1(k_none), (K) 0); -#endif /* ver >= 3.5 */ +#endif /* have ee() */ Py_END_ALLOW_THREADS return KObject_FromK(Py_TYPE(self), x); } @@ -404,7 +396,7 @@ K_a1(KObject * self, KObject *arg) if (K_Check(arg)) { K x, y; Py_BEGIN_ALLOW_THREADS -#if KXVER >= 3 && KXVER2 >= 5 +#if HAVE_EE y = knk(1, r1(arg->x)); x = dot(self->x, y); r0(y); @@ -413,7 +405,7 @@ K_a1(KObject * self, KObject *arg) #else y = arg->x; x = k(0, "@", r1(self->x), r1(y), (K)0); -#endif /* ver >= 3.5 */ +#endif /* have ee() */ Py_END_ALLOW_THREADS return KObject_FromK(Py_TYPE(self), x); } @@ -1369,11 +1361,11 @@ K_ktd(PyTypeObject * type, PyObject *args) since 2011-01-27, ktd always decrements ref count of input. */ -#if defined (WIN32) || defined(_WIN32) - return KObject_FromK(type, k(0, "0!", r1(x), (K)0)); -#else +#if HAVE_EE return KObject_FromK(type, ee(ktd(r1(x)))); -#endif +#else + return KObject_FromK(type, k(0, "0!", r1(x), (K)0)); +#endif /* have ee() */ } PyDoc_STRVAR(K_err_doc, "sets a K error\n\n>>> K.err('test')\n"); @@ -4235,7 +4227,7 @@ getitem(PyTypeObject * ktype, K x, Py_ssize_t i) if (xt >= 20 && xt < ENUMS_END) { I j = xI[i]; K key = k(0, "{value key x}", r1(x), (K)0); - ret = PY_STR_InternFromString(j < key->n ? kS(key)[j] : ""); + ret = PY_STR_InternFromString(j < key->n && j >= 0 ? kS(key)[j] : ""); r0(key); } else { diff --git a/src/pyq/_pt_run.py b/src/pyq/_pt_run.py index 69a5f94..94d3496 100644 --- a/src/pyq/_pt_run.py +++ b/src/pyq/_pt_run.py @@ -35,7 +35,7 @@ def run(q_prompt=False): q(r'\l %s' % sys.argv[1]) except kerr as e: print(e) - exit(1) + raise SystemExit(1) else: del sys.argv[1] if q_prompt: diff --git a/src/pyq/cmd.py b/src/pyq/cmd.py index 0ad4e2c..a952e2f 100644 --- a/src/pyq/cmd.py +++ b/src/pyq/cmd.py @@ -3,7 +3,7 @@ import cmd as _cmd -from . import q, kerr +from . import q, kerr, Q_OS try: from . import ptk @@ -13,16 +13,22 @@ q('.py.pcc:`s#0 5 20f!32 33 31') _prompt_color = q('{.py.pcc 100*(%)over system["w"]1 5}') _prompt_namespace = q('{?[ns~`.;`;ns:system"d"]}') +if Q_OS.startswith('w'): + def _colorize(_, prompt): + return prompt +else: + def _colorize(code, prompt): + return "\001\033[%d;1m\002%s\001\033[0m\002" % (code, prompt) -class Cmd(_cmd.Cmd): +class Cmd(_cmd.Cmd, object): _prompt = 'q{ns})' @property def prompt(self): code = _prompt_color() prompt = self._prompt.format(ns=_prompt_namespace()) - return "\001\033[%d;1m\002%s\001\033[0m\002" % (code, prompt) + return _colorize(code, prompt) def precmd(self, line): if line.startswith('help'): diff --git a/src/pyq/tests/test_k.py b/src/pyq/tests/test_k.py index b0fbedb..034e75e 100644 --- a/src/pyq/tests/test_k.py +++ b/src/pyq/tests/test_k.py @@ -1170,8 +1170,9 @@ def test_k_bool_of_enum(): def test_enum_getitem(): q("sym:`a`b`c") - x = q('`sym$`a`b') + x = q('`sym$`a`') assert x[0] == 'a' + assert x[1] == '' with pytest.raises(IndexError): x[2] # Test short enum domain vector diff --git a/src/pyq/tests/test_p.py b/src/pyq/tests/test_p.py index 6978755..277f0b8 100644 --- a/src/pyq/tests/test_p.py +++ b/src/pyq/tests/test_p.py @@ -23,7 +23,7 @@ def test_test_p0(tmpdir): test_p.write(TEST_P) with open(os.devnull) as null: out = subprocess.check_output([os.environ['QBIN'], str(test_p)], - stdin=null) + stderr=subprocess.PIPE, stdin=null) assert b'ok' in out @@ -64,5 +64,5 @@ def test_p__file__qbin(tmpdir): p.write("import sys\nprint(__file__)\nsys.exit(0)") with open(os.devnull) as null: out = subprocess.check_output([os.environ['QBIN'], str(p)], - stdin=null) + stderr=subprocess.PIPE, stdin=null) assert out.strip().endswith(str(p).encode())