Skip to content

Commit 34a6853

Browse files
authored
Merge pull request #992 from htm-community/Python311
python 3.11 compatability
2 parents 098b285 + ff8d5ad commit 34a6853

File tree

12 files changed

+88
-93
lines changed

12 files changed

+88
-93
lines changed

README.md

Lines changed: 25 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -40,44 +40,39 @@ in C++ library.
4040

4141
## Installation
4242

43-
### Binary releases
4443

45-
NOTE: The Binary releases are not being maintained. Suggest building from Sources instead.
46-
47-
If you want to use `htm.core` from Python, the easiest method is to install from [PyPI](https://test.pypi.org/project/htm.core/)
48-
- Note: to install from `pip` you'll need Python 3.7 only(does not work with older or newer versions)
49-
50-
```
51-
python -m pip install -i https://test.pypi.org/simple/ htm.core
52-
```
53-
Note: to run all examples with visualizations, install including extra requirements:
54-
`pip install -i https://test.pypi.org/simple/ htm.core[examples]`
55-
56-
If you intend to use `htm.core` as a library that provides you Python \& C++ HTM,
57-
you can use our [binary releases](https://github.com/htm-community/htm.core/releases).
58-
59-
#### Prerequisites
44+
### Prerequisites
6045

6146
For running C++ apps/examples/tests from binary release: none.
6247
If you want to use python, then obviously:
6348

6449
- [Python](https://python.org/downloads/)
65-
- Standard Python 3.7+ (Recommended)
50+
- Standard Python 3.7+ (Recommend using the latest) [Tested with 3.8, 3.11.1]
6651
- Standard Python 2.7
6752
+ We recommend the latest version of 2.7 where possible, but the system version should be fine.
6853
+ Python 2 is Not Supported on Windows, use Python 3 instead.
6954
+ Python 2 is not tested by our CI anomore. It may still work but we don't test it. We expect to drop support for Python2 around 2020.
7055
- [Anaconda Python](https://www.anaconda.com/products/individual#Downloads) 3.7+
7156
+ On windows you must run from within 'Anaconda Prompt' not 'Command Prompt'.
72-
+ The pre-built binary releases only work with Standard Python so you must build from sources.
7357
+ Anaconda Python is not tested in our CI.
7458

7559
Be sure that your Python executable is in the Path environment variable.
7660
The Python that is in your default path is the one that will determine which
7761
version of Python the extension library will be built for.
7862
- Other implementations of Python may not work.
7963
- Only the standard python from python.org have been tested.
64+
- On Linux you will need both the Python install and the Python-dev install
65+
'$ sudo apt install python3.11'
66+
'$ sudo apt install python3.11-dev'
67+
- You will probably also want to setup a [https://docs.python.org/3/library/venv.html(venv environment).
68+
69+
- **C\+\+ compiler**: c\+\+11/17 compatible (ie. g++, clang\+\+).
70+
- boost library (if not a C\+\+17 or greater compiler that supports filesystem.)
71+
If the build needs boost, it will automatically download and install boost with the options it needs.
72+
- CMake 3.7+ (MSVC 2019 needs CMake 3.14+, MSVC 2022 needs CMake 3.21+).
73+
Install the latest using [https://cmake.org/download/](https://cmake.org/download/)
8074

75+
Note: Windows MSVC 2019 runs as C\+\+17 by default so boost is not needed. On linux use -std=c++17 compile option to avoid needing boost.
8176

8277
### Building from Source
8378

@@ -91,29 +86,21 @@ To fork the repo with `git`:
9186
git clone https://github.com/htm-community/htm.core
9287
```
9388

94-
#### Prerequisites
95-
96-
- same as for Binary releases, plus:
97-
- **C\+\+ compiler**: c\+\+11/17 compatible (ie. g++, clang\+\+).
98-
- boost library (if not a C\+\+17 or greater compiler that supports filesystem.)
99-
If the build needs boost, it will automatically download and install boost with the options it needs.
100-
- CMake 3.7+ (MSVC 2019 needs CMake 3.14+, MSVC 2022 needs CMake 3.21+).
101-
Install the latest using [https://cmake.org/download/](https://cmake.org/download/)
102-
103-
Note: Windows MSVC 2019 runs as C\+\+17 by default so boost is not needed. On linux use -std=c++17 compile option to avoid needing boost.
104-
10589

10690
#### Simple Python build (any platform)
10791

108-
1) Prerequisites: install the following python packages: `pip install setuptools packaging`
92+
1) Prerequisites: install the following python packages:
93+
`python -m ensurepip --upgrade`
94+
`python -m pip install setuptools packaging`
95+
`pip -r install requirements.txt`
10996

11097
2) At a command prompt, `cd` to the root directory of this repository.
11198

11299
3) Run: `python setup.py install --user --force`
113100

114101
This will build and install a release version of htm.core. The `--user` option prevents the system installed site-packages folder from being changed and avoids the need for admin privileges. The `--force` option forces the package to be replaced if it already exists from a previous build. Alternatively you can type `pip uninstall htm.core` to remove a previous package before performing a build.
115102

116-
* If you are using `virtualenv` you do not need the --user or --force options.
103+
* If you are using `virtualenv` you may not need the --user or --force options.
117104
* If you are using Anaconda Python you must run within the `Anaconda Prompt` on Windows. Do not use --user or --force options.
118105

119106
* If you run into problems due to caching of arguments in CMake, delete the
@@ -305,10 +292,11 @@ Generate IDE solution & build.
305292
* Specify the build system folder (`$HTM_CORE/build/scripts`), i.e. where IDE solution will be created.
306293
* Click `Generate`.
307294

308-
#### For MS Visual Studio 2017 or 2019 as the IDE
295+
#### For MS Visual Studio 2017, 2019 or 2022 as the IDE
309296

310297
After downloading the repository, do the following:
311298
* NOTE: Visual Studio 2019 requires CMake version 3.14 or higher.
299+
* Visual Studio 2022 requires CMake version 3.21 or higher.
312300
* CD to the top of repository.
313301
* Double click on `startupMSVC.bat`
314302
- This will setup the build, create the solution file (build/scripts/htm.cpp.sln), and start MS Visual Studio.
@@ -404,7 +392,7 @@ Note2: It is obvious, but anyway - do not use `--user` option while using python
404392
The installation scripts will automatically download and build the dependencies it needs.
405393

406394
* [Boost](https://www.boost.org/) (Not needed by C++17 compilers that support the filesystem module)
407-
* [LibYaml](https://pyyaml.org/wiki/LibYAML) or [Yaml-cpp](https://github.com/jbeder/yaml-cpp)
395+
* [LibYaml](https://pyyaml.org/wiki/LibYAML)
408396
* [Eigen](https://eigen.tuxfamily.org/index.php?title=Main_Page)
409397
* [PyBind11](https://github.com/pybind/pybind11)
410398
* [gtest](https://github.com/google/googletest)
@@ -425,18 +413,17 @@ distribution packages as listed and rename them as indicated. Copy these to
425413

426414
| Name to give it | Where to obtain it |
427415
| :--------------------- | :----------------- |
428-
| libyaml.zip (*note1) | https://github.com/yaml/libyaml/archive/refs/tags/0.2.5.tar.gz |
416+
| libyaml.zip | https://github.com/yaml/libyaml/archive/refs/tags/0.2.5.tar.gz |
429417
| boost.tar.gz (*note3) | https://dl.bintray.com/boostorg/release/1.72.0/source/boost_1_72_0.tar.gz |
430-
| googletest.tar.gz | https://github.com/google/googletest/archive/refs/tags/release-1.11.0.tar.gz |
418+
| googletest.tar.gz | https://github.com/google/googletest/archive/refs/tags/release-1.12.1.tar.gz |
431419
| eigen.tar.bz2 | https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz |
432420
| mnist.zip (*note4) | https://github.com/wichtounet/mnist/archive/3b65c35ede53b687376c4302eeb44fdf76e0129b.zip |
433-
| pybind11.tar.gz | https://github.com/pybind/pybind11/archive/refs/tags/v2.6.2.tar.gz |
421+
| pybind11.tar.gz | https://github.com/pybind/pybind11/archive/refs/tags/v2.10.1.tar.gz |
434422
| cereal.tar.gz | https://github.com/USCiLab/cereal/archive/refs/tags/v1.3.2.tar.gz |
435423
| sqlite3.tar.gz | https://www.sqlite.org/2022/sqlite-autoconf-3380200.tar.gz |
436424
| digestpp.zip | https://github.com/kerukuro/digestpp/archive/34ff2eeae397ed744d972d86b5a20f603b029fbd.zip |
437-
| cpp-httplib.zip(*note4)| https://github.com/yhirose/cpp-httplib/archive/refs/tags/v0.10.4.zip |
425+
| cpp-httplib.zip(*note4)| https://github.com/yhirose/cpp-httplib/archive/refs/tags/v0.11.3.zip |
438426

439-
* note1: Version 0.2.2 of libyaml is broken so use the master for the repository.
440427
* note3: Boost is not required for any compiler that supports C++17 with `std::filesystem` (MSVC2017, gcc-8, clang-9).
441428
* note4: Used for examples. Not required to run but the build expects it.
442429

bindings/py/cpp_src/plugin/PyBindRegion.cpp

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -308,43 +308,46 @@ namespace py = pybind11;
308308
// 2. call class method to serialize external state
309309

310310
// Serialize main state of the Python module
311-
// We want this to end up in a string that we pass back to Cereal.
312-
// a. We first pickle the python into an in-memory byte stream.
313-
// b. We then convert that to a Base64 std::string that is returned.
311+
// We want this to end up in a string that we pass back to Cereal.
312+
// a. We first pickle the python into an in-memory byte stream.
313+
// b. We then convert that to a Base64 std::string that is returned.
314314
//
315315
// Basicly, we are executing the following Python code:
316316
// import io
317317
// import base64
318318
// import pickle
319319
// f = io.BytesIO()
320-
// pickle.dump(node, f, 3)
320+
// pickle.dump(node, f, HIGHEST_PROTOCOL)
321321
// b = f.getvalue()
322322
// content = str(base64.b64encode(b))
323323
// f.close()
324324

325-
py::tuple args;
326-
auto f = py::module::import("io").attr("BytesIO")();
325+
py::tuple args;
326+
auto f = py::module::import("io").attr("BytesIO")();
327327

328328
#if PY_MAJOR_VERSION >= 3
329-
auto pickle = py::module::import("pickle");
330-
args = py::make_tuple(node_, f, 3); // use type 3 protocol
329+
auto pickle = py::module::import("pickle");
330+
auto highest = pickle.attr("HIGHEST_PROTOCOL");
331+
args = py::make_tuple(node_, f, highest); // use type 3,4, or 5 protocol
331332
#else
332-
auto pickle = py::module::import("cPickle");
333-
args = py::make_tuple(node_, f, 2); // use type 2 protocol
333+
auto pickle = py::module::import("cPickle");
334+
args = py::make_tuple(node_, f, 2); // use type 2 protocol
334335
#endif
335-
pickle.attr("dump")(*args);
336+
pickle.attr("dump")(*args);
336337

337-
// copy the pickle stream into the content as a base64 encoded utf8 string
338+
// copy the pickle stream into the content as a base64 encoded utf8 string
338339
py::bytes b = f.attr("getvalue")();
339340
args = py::make_tuple(b);
340-
std::string content = py::str(py::module::import("base64").attr("b64encode")(*args));
341-
342-
f.attr("close")();
343-
return content;
341+
std::string content = py::str(py::module::import("base64").attr("b64encode")(*args));
342+
if (content[1] == '\'') { // strip off leading "b'" and trailing "'"
343+
content = content.substr(2, content.length() - 3);
344+
}
345+
f.attr("close")();
346+
return content;
344347
}
345348
std::string PyBindRegion::extraSerialize() const
346349
{
347-
std::string tmp_extra = "extra.tmp";
350+
std::string tmp_extra = "extra.tmp";
348351

349352
// 2. External state
350353
// Call the Python serializeExtraData() method to write additional data.
@@ -353,21 +356,21 @@ namespace py = pybind11;
353356
// Need to put the None result in py::Ptr to decrement the ref count
354357
node_.attr("serializeExtraData")(*args);
355358

356-
// copy the extra data into the extra string
357-
std::ifstream efile(tmp_extra.c_str(), std::ios::binary);
358-
std::string extra((std::istreambuf_iterator<char>(efile)),
359-
std::istreambuf_iterator<char>());
360-
efile.close();
361-
Path::remove(tmp_extra);
362-
return extra;
359+
// copy the extra data into the extra string
360+
std::ifstream efile(tmp_extra.c_str(), std::ios::binary);
361+
std::string extra((std::istreambuf_iterator<char>(efile)),
362+
std::istreambuf_iterator<char>());
363+
efile.close();
364+
Path::remove(tmp_extra);
365+
return extra;
363366

364367
}
365368

366369
void PyBindRegion::pickleDeserialize(std::string p) {
367370
// 1. deserialize main state using pickle
368371
// 2. call class method to deserialize external state
369372
//
370-
// Tell Python to un-pickle using what is in the string p.
373+
// Tell Python to un-pickle using what is in the string p.
371374
// but first we need to convert the base64 string into bytes.
372375
//
373376
// Basically we are executing the following Python code:
@@ -383,7 +386,7 @@ namespace py = pybind11;
383386
args = py::make_tuple(py::bytes(p));
384387
py::bytes b = py::module::import("base64").attr("b64decode")(*args);
385388
args = py::make_tuple(b);
386-
auto f = py::module::import("io").attr("BytesIO")(*args);
389+
auto f = py::module::import("io").attr("BytesIO")(*args);
387390

388391
#if PY_MAJOR_VERSION >= 3
389392
auto pickle = py::module::import("pickle");
@@ -394,19 +397,19 @@ namespace py = pybind11;
394397
node_ = pickle.attr("load")(*args);
395398

396399
f.attr("close")();
397-
}
400+
}
398401

399-
void PyBindRegion::extraDeserialize(std::string e) {
402+
void PyBindRegion::extraDeserialize(std::string e) {
400403
// 2. External state
401-
std::string tmp_extra = "extra.tmp";
402-
std::ofstream efile(tmp_extra.c_str(), std::ios::binary);
403-
efile.write(e.c_str(), e.size());
404-
efile.close();
404+
std::string tmp_extra = "extra.tmp";
405+
std::ofstream efile(tmp_extra.c_str(), std::ios::binary);
406+
efile.write(e.c_str(), e.size());
407+
efile.close();
405408

406409
// Call the Python deSerializeExtraData() method
407410
py::tuple args = py::make_tuple(tmp_extra);
408411
node_.attr("deSerializeExtraData")(*args);
409-
Path::remove(tmp_extra);
412+
Path::remove(tmp_extra);
410413
}
411414

412415

bindings/py/tests/regions/network_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ def testNetworkPickle(self):
369369
network.initialize()
370370

371371
if sys.version_info[0] >= 3:
372-
proto = 3
372+
proto = pickle.HIGHEST_PROTOCOL
373373
else:
374374
proto = 2
375375

bindings/py/tests/sparse_link_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
TEST_DATA_SPARSE = np.array([4, 7])
2626
MAX_ACTIVE = TEST_DATA_SPARSE.size
2727
OUTPUT_WIDTH = 10
28-
TEST_DATA_DENSE = np.zeros(OUTPUT_WIDTH, dtype=np.bool)
28+
TEST_DATA_DENSE = np.zeros(OUTPUT_WIDTH, dtype=np.bool_)
2929
TEST_DATA_DENSE[TEST_DATA_SPARSE] = True
3030

3131

external/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ integrated into the cmake-based build of htm.core. The code that does this are
88
- Boost.cmake - If needed, finds the boost installation 1.69.0. Boost needs to be built with -fPIC so cannot use externally installed.
99
- digestpp.cmake - Download/install digestpp @ 36fa6ca : Hash digest lib (header only)
1010
- eigen.cmake - Downloads eigen 3.4.0 (header only)
11-
- gtest.cmake - Downloads and installs googletest 1.11.0
11+
- gtest.cmake - Downloads and installs googletest 1.12.1
1212
- mnist_data.cmake - Downloads the mnist data set from repository master.
13-
- pybind11.cmake - Downloads and installs pybind11 2.6.2 (header only)
13+
- pybind11.cmake - Downloads and installs pybind11 2.10.1 (header only)
1414
- libayml.cmake - Downloads and installs libyaml 0.2.5 which is an alternative to yaml-cpp (default)
1515
- cpp-httplib.cmake- Downloads and installs cpp-httplib 0.10.4, a REST server (header only)
1616
- cerial.cmake - Downloads and installs cerial 1.3.2, a serialization package (header only)

external/cpp-httplib.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
if(EXISTS "${REPOSITORY_DIR}/build/ThirdParty/share/cpp-httplib.zip")
2626
set(URL "${REPOSITORY_DIR}/build/ThirdParty/share/cpp-httplib.zip")
2727
else()
28-
set(URL https://github.com/yhirose/cpp-httplib/archive/refs/tags/v0.10.4.zip)
28+
set(URL https://github.com/yhirose/cpp-httplib/archive/refs/tags/v0.11.3.zip)
2929
endif()
3030

3131
message(STATUS "obtaining cpp-httplib")

external/gtest.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
if(EXISTS "${REPOSITORY_DIR}/build/ThirdParty/share/googletest.tar.gz")
3636
set(URL "${REPOSITORY_DIR}/build/ThirdParty/share/googletest.tar.gz")
3737
else()
38-
set(URL https://github.com/google/googletest/archive/refs/tags/release-1.11.0.tar.gz)
38+
set(URL https://github.com/google/googletest/archive/refs/tags/release-1.12.1.tar.gz)
3939
endif()
4040

4141
#

external/pybind11.cmake

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@
2121
if(EXISTS "${REPOSITORY_DIR}/build/ThirdParty/share/pybind11.tar.gz")
2222
set(URL "${REPOSITORY_DIR}/build/ThirdParty/share/pybind11.tar.gz")
2323
else()
24-
set(URL https://github.com/pybind/pybind11/archive/v2.6.2.tar.gz)
25-
# set(URL "https://github.com/pybind/pybind11/archive/refs/tags/v2.9.2.tar.gz")
26-
# This caused an error regarding Base64 someplace inside pickle load. Reverting to 2.6.2
24+
set(URL https://github.com/pybind/pybind11/archive/v2.10.1.tar.gz)
2725
endif()
2826

2927
message(STATUS "obtaining PyBind11")

py/tests/advanced/algorithms/apical_tiebreak_temporal_memory/shared_tests/sequence_memory_test_base.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -892,9 +892,16 @@ def noisy(pattern, wFlip, n):
892892
A noisy set of active indices
893893
"""
894894

895+
"""
896+
keeney, 12/2022
897+
The random.sample() method requires the first argument to be sorted.
898+
The apical_tiebreak_temporal_memory_test_base:897 was failing with an error saying
899+
it was not a sequence. So I added a sorted(). I would have thought that a set
900+
would already be sorted. I do not know if this affects the algorithm logic.
901+
"""
895902
noised = set(pattern)
896903

897-
noised.difference_update(random.sample(noised, wFlip))
904+
noised.difference_update(random.sample(sorted(noised), wFlip))
898905

899906
for _ in range(wFlip):
900907
while True:

requirements.txt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
#See http://www.pip-installer.org/en/latest/requirements.html for details
22
setuptools>=34.4.0 # needed for Windows with MSVC
3-
pip>=19.3.1
4-
wheel>=0.33.6
5-
cmake>=3.14 #>=3.7, >=3.14 needed for MSVC 2019
3+
pip>=22.3.1
4+
wheel>=0.38.4
5+
cmake>=3.14 #>=3.7, >=3.14 needed for MSVC 2019, >=3.21 needed for MSVC 2022
66
## for python bindings (in /bindings/py/)
7-
numpy>=1.15
7+
numpy>=1.23
88
pytest>=4.6.5 #4.6.x series is last to support python2, once py2 dropped, we can switch to 5.x
99
## for python code (in /py/)
10-
hexy>=1.4.3 # for grid cell encoder
11-
mock>=1.0.1 # for anomaly likelihood test
12-
prettytable>=0.7.2 # for monitor-mixin in htm.advanced (+its tests)
10+
hexy>=1.4.4 # for grid cell encoder
11+
mock>=3.3 # for anomaly likelihood test
12+
prettytable>=3.5.0 # for monitor-mixin in htm.advanced (+its tests)
1313
## optional dependencies, such as for visualizations, running examples
1414
# should be placed in setup.py section extras_require. Install those by
1515
# pip install htm.core[examples]

0 commit comments

Comments
 (0)