Closed ShadowJonathan closed 1 month ago
(Converting to draft while I try to figure out Windows builds)
This is very exciting! Thank you so much for looking into this. I would love for users to be able to simply pip install soar-cog-arch==9.6.3
to get Soar (seriously, "snakes on a robot" took the soar name?! 🤣).
$SOAR_HOME
). This is important when, for example, using Soar with Java, where you have to run with -Djava.library.path="$SOAR_HOME"
. Or maybe it's not necessary after the wheel is installed? 🤔 For future work (it's a bigger change), we may want this to be usable for general users that want to run VisualSoar, the debugger, etc. from the launch scripts. We would need to include the scripts/jars for running these into the wheel, and we would need to notify the user of where Soar was installed (previous point). Right now the final Soar distribution is built using a separate project: https://github.com/SoarGroup/Release-Support.
Regarding more Pythonic access for Soar, there is a popular (in our tiny community) project that does something similar called pysoarlib
. I have a PR open for making it pip-installable: https://github.com/amininger/pysoarlib/pull/7. I actually ended up forking it for our current internal project because I wanted to make a lot of changes to it. I don't want to discourage you from working on a new Python library, as a fresh take would probably be very nice, but I wanted to let you know that it's there. The design pattern with SoarClient using AgentConnector implementations and exposing only the input, output and init events has been especially useful.
I would like the package version to match Soar's version
Already intending to, so that soar-sml
can have its versioning decoupled, and simply define a range of soar versions for which it supports its python/sml interface.
Or maybe it's not necessary after the wheel is installed?
Not necessary, as Soar gets built and statically linked against the SML interface library (or at the very least, included in the wheel), meaning that its essentially bundling a distribution of Soar with the wheel itself as well.
Was there a technical reason you needed to change it, or was it just that the name is ugly?
Well, multiple reasons;
Python_sml_ClientInterface.py
and _ Python_sml_ClientInterface.so
sitting at the root of site-packages
is not considered very "clean", and possibly may cause problems even (when some tools try to look up packages/directories and/or when importing/auto-importing)So part technical reason and social/cleanliness reason.
There could possibly be an extra package which installs that Python_sml_ClientInterface.py
at site-packages
root and just does from soar_raw import *
, maybe call it soar-compat
(installable via soar-raw[compat]
), but I'm really against having it there by default.
we may want this to be usable for general users that want to run VisualSoar, the debugger, etc. from the launch scripts
I... would have to take a closer look at that, at the moment I'm really just focusing on getting the SML part up and ready. I don't have any thoughts on this at the moment, and the decision on wether to bundle the VisualSoar parts (if in includes java; no), making it easy to make VisualSoar/debugger connectable (probably), or something else, is something I don't have enough info for.
This library is just intended to start the soar kernel, load agent code, and setup the IO link via python. Debugging and whatnot should then be pluggable similar to how someone who usually runs Soar would expect it to work, imo.
For visualsoar or the debugger to connect, the programmer would have to first fire off python with a script that loads the soar agent (with its connector), and only then they could connect to it, methinks. This would miss out the connector part of debugging, which would need to be done on the python side in the IDE's native debugger.
(pysoarlib) [...] but I wanted to let you know that it's there.
I saw, though thanks for mentioning it for if I hadn't :)
I'm going to take a look at it for inspiration, but largely the reason I want to make an independent library is because I then both learn the internals of SML while thinking of a pythonic interface, hopefully with that fresh perspective not being bogged down by rigidity to conform to something similar to Soar's internals, etc.
Taking a look again, the sub-classable connector interface does strike a fancy; I think I'd like more parts of that to be as modular, such as entire input or output trees, "interpreters", so that data gets transformed into WM elements efficiently, and such interpreters/trees can be modularised and shared around, iterated.
(plus having nice formatted value trees on repr()
and the likes)
That library design looks poll-based instead of push-based; I want to play around with that as well, where instead of the WM being polled for every update, the programmer can opt to instead explicitly push data at "off" intervals (decoupled from the decision cycle). But I have to think how such a library design would work.
One nice thing about decoupling this from the "raw" library is that I can do alpha/beta versioning while I experiment with this :)
Edit: An additional thought; I can make it work with asyncio, instead of requiring synchronous code, which would then help introduce tons of libraries which do asynchronous IO off the device (such as driving motors, or APIs)
the wheel would have to package a python file "at root"
What do you mean by this? Do you mean that you plan for the import to be from something more nested, like from soargroup.soar import soar_raw
or something?
BTW I think calling it soar_sml
instead of soar_raw
would suffice for clarity; the SML API is as raw as it gets from the Python side. Then for your pythonic wrapper you'd be free to be as creative as you want, from the mundane "soar_pythonic" to the more fun "glider" or "eagle" (or whatever else soars).
I think we can punt the question of more general usage down the road for now. Having any form of pip-installable Soar would already be very cool. This is also related to the point where you say Not necessary, as Soar gets built and statically linked against the SML interface library
; a general installation of Soar has SML bindings for Python, Java, Tcl, C++ and C#. It's a lot to manage.
the programmer can opt to instead explicitly push data at "off" intervals
A nice role-reversal! Give highest-level control to the external application instead of to Soar. This programming pattern is less common for Soar because it is more complex, but I would love to see it done. I could be mistaken, but I think you'd want to create the kernel in the current thread using sml::Kernel::CreateKernelInCurrentThread
, and you'll need to take note of the usage comment here: https://github.com/SoarGroup/Soar/blob/development/Core/ClientSML/src/sml_ClientKernel.h#L318. You have to call CheckForIncomingCommands()
periodically if you want the kernel to be reactive to any other clients (such as the debugger). (If I recall correctly this doesn't apply to the client in the thread that created the kernel, just other clients remotely connecting to it).
I think your ideas for a Pythonic Soar package sound really cool, so I'm excited to see what you come up with!
What do you mean by this? Do you mean that you plan for the import to be from something more nested, like from soargroup.soar import soar_raw or something?
Currently, the import would be import soar_raw
, soar_raw
would be installed as a directory under python's site-packages
folder, and putting anything but a namespace directory there (or installing to someone else's namespace directory) is frowned upon.
BTW I think calling it soar_sml instead of soar_raw would suffice for clarity
That's fair, then I think I'll indeed swap it around for that (making soar-raw
into soar-sml
; I'll update this PR with that at some point), and find a good name for my pythonic package :)
A general installation of Soar has SML bindings for Python, Java, Tcl, C++ and C#. It's a lot to manage.
To be honest, I think pivoting to packaging the python binding for soar to a wheel file for users to install would be more user-friendly in the long-term, since instructing them to manually pivot $PATH
to that directory is awkward at best, and fragile and non-portable at worst.
(wrt
CreateKernelInCurrentThread
)
I'll have to see what is most optimal, what I'm seeing here is that doing CreateKernelInCurrentThread
basically defers a lot of housekeeping to the developer, right? If so, that'd have more control (and could play nicely with asynchronous IO), but would be a bit more complexity. I'll play around with that later :)
All sounds good :) One last note on concurrency: core Soar does not support it. It is not thread-safe. The SML client library uses locking to ensure that only one command can get sent at a time, and on the kernel side there is a queue for receiving commands over the network socket (as when the debugger connects).
So there are a couple safety measures in place, but if you're not careful you can run into issues like #430. This is also related to the actions one might take in a handler; when control returns to Soar after a handler is complete, it doesn't do any checking to make sure that, e.g. the agent list hasn't changed. Unfortunately these edge cases aren't well-documented, but if you stick to actions that were definitely intended and designed for, such as creating WME's on the input link in the input handler and reading command WME's on the output link in the output handler, everything will work fine.
Felt a bit inspired and started drawing up the different ways that soar and the environment could asynchronously run alongside eachother, apologies for the digression. (Click to open) I thought about how
soar-sml
would do asynchronous IO for a second, and I figured there'd at least be three configurations possible;Here's a simple loop; Soar (grey) runs one decision cycle, and then waits before the output (red) has been completed on the connector, then waits before the input (blue) is completed on the connector, and then runs another cycle.
However, due to asyncio, it is possible to say "Hey, run the output code together with the input code, and only wait for the input to complete";
This would have the input and output code fight for the state of the world, but this may be possible in some scenarios (or some sub-connectors), and a programmer might want to enable this for optimisation purposes.
Then there's a final method, which runs the input collector every time, and then feeds soar the last result (encircled), while also asynchronously running the output;
Again, this would have implications, but could be something the programmer wants to weigh off.
All of these have tradeoffs, but supporting all of them is possible, and its good to provide options.
O
A little bit off topic: I am currently working on a Soar ROS2 integration and I implemented something similar to your first idea but I instantly push the elements to a consumer thread via queues so Soar remains responsive for output link wmes. For the input I read all queues and attach the data to the input link.
I did not publish the code (cop) yet.
So far this approach works great and I did not experience any weird behaviour. I hope this helps!
CI builds properly now, so there are a few outstanding tasks, and some notes:
authors
, keywords
, classifiers
, urls
, and probably another few fields in the pyproject.toml
file needs to be updated/added with the right data.soar-compat
project that exposes a Python_sml_ClientInterface
namespace, which just re-exports all the contents of soar_sml
(a simple one-liner file from soar_sml import *
), able to be easily installed with pip install soar-sml[compat]
[compat]
bit is an "extra", which'd simply add a dependency to soar-compat
, installing that "package" as well.pyproject.toml
and a single python file that can then be "compiled" with cibuildwheel and uploaded, and never needs to be updated), so just say 'alright' to that if I should do so in this PR :)Notes:
pip install soar-sml
, then import soar_sml
from anywhere)
Soar.lib
and Soar.dll
, while I'm fairly sure it only requires the latter one. This is due to how scons handles aliases and shared library files internally.imp
on 3.12 (which has been deprecated since 3.4, and finally removed in 3.12), which then failed and crashed the build script. I don't know how I can instruct cibuildwheel to run a specific version of python for the build system, but seeing as how the SConstruct
/SConscript
scripts pull out details from the currently-running interpreter for the build environment, I don't think that'll help.
pip install soar-sml
needs to happen on a supported platform, or else it will refuse to install.
pip install
is a source of headaches, as target systems are often entirely unequipped for building sources, and Soar's *cough* particular build system will likely break in all sorts of ways on an unprepared system. (This is why building in CI is a preferred way of doing it: it keeps hell contained)You've given us a lot here. We need to review a few of these things (I haven't caught up on all the stuff that's happened here), but I like this so far. Thanks!
You say "Installing this would instantly recover all compatibility with all the existing projects, and make them properly portable as a result :)" "so just say 'alright' to that if I should do so in this PR"
Alright.
"I've uploaded the current build artifacts to pypi.org/project/soar-sml, this is to prevent someone else nicking and squatting it (I've had that happen a few times before)" --Thanks for that, too!
Alright, I added soar-compat
and uploaded this small library to pypi as well, together with a new version of build artifacts on an alpha version.
It is now possible to do pip install "soar-sml[compat]"
, and receive full and simple backwards compatibility with all existing scripts for soar :)
Just tag me with a organisation or maintainer username on pypi that I can transfer ownership of the pypi project to, this is just a safety measure.
I created a garfieldnate account and a SoarGroup organization on pypi today; the organization has to be approved by someone before it exists, so I'll let you know when that comes through.
PyPy does "compile", but it doesn't seem to do it correctly...
Most of the actual running code is going to be compiled C++, and I'm not worried about the speed of the wrapper code. Do you think I should be? Soar does a lot of work, and I would hope that by comparison a simple method call in Python would be no big deal.
We should maybe also decide on how many past versions we want to upload to pypi
I think starting with 9.6.2 is fine. Going back and building earlier versions of Soar is a big pain.
Building for 32-bit windows has also been disabled
That's fine, we don't support it anymore.
Windows wheels also currently have a quirk where they contain both Soar.lib and Soar.dll
Definitely only need the latter, but I wouldn't say it's a show-stopper for now.
Python 3.12 isn't currently being built for.
How does this work? The shard library that Python loads only works with 3.12, which is the version of Python that we build with. This would mean that the wheel wouldn't work at all, since it can only be used with versions of Python that the lib won't work with, but you said it's working fine, and I don't understand how.
The current pypi upload and setup does NOT package source installs
I would have thought it were complete magic if this worked for everyone :D It takes a bit of work to set up the environment to build Soar. I think it's fine to go without this.
Most of the actual running code is going to be compiled C++, and I'm not worried about the speed of the wrapper code. Do you think I should be? Soar does a lot of work, and I would hope that by comparison a simple method call in Python would be no big deal.
When dealing with real-time data streams, speed might be a factor in shifting that data around (think the raw bytes of a visual interface).
That, or other miscellaneous operations; Python is single-threaded, any thread simply preemptively shares time on a single lock with any other, so speed of code is important when there is priority and deadlines.
Soar can run without the lock, but asynchronous Python code needing to fetch, update, and shift data around for Soar to feed on might have a huge boost by using PyPy.
Python 3.12 isn't currently being built for.
How does this work?
this is due to a limitation with the build system, enscons, though as I said in review; I'm very tempted to fork it and add a simple few fixes which make it work for Python 3.12; there's nothing on soar's side preventing compilation, just an incompatibility of the build system.
Two general questions I thought of:
Does this make the build take significantly longer? Should we maybe only do the cibuildwheel stuff once a week and on any tags or something?
The entire build takes about 15 minutes now. I can recommend just running cibuildwheel on tags, and/or also adding a step which automatically uploads them on pypi on any tagging. (There needs to be a step that checks if the version in pyproject.toml matches the tag though, or else it'll maybe upload wheels of the wrong version)
How much more does this couple us with SCons, which we've been considering moving away from for a while?
Not much, this specific approach (enscons
) is a way for the python build system to adapt itself to scons. Any other build system could be used, a more common one (like cmake), and there'll be more options for adapting the python build system against whatever option you'll choose. So in essence: It wouldn't couple y'all at all more to scons. When changing it around, it would just require a (hopefully less laborious) dance again to make it fit with python, but if in end end its just a script that needs to be ran, there is a build system adapter for it.
That, or other miscellaneous operations; Python is single-threaded, any thread simply preemptively shares time on a single lock with any other, so speed of code is important when there is priority and deadlines.
(I should follow-up, which is what I'm currently devising ways to get around this restriction by leveraging and studying python's multiprocessing
library, and applying that to the wrapper library I'm thinking of.)
The entire build takes about 15 minutes now. I can recommend just running cibuildwheel on tags, and/or also adding a step which automatically uploads them on pypi on any tagging. (There needs to be a step that checks if the version in pyproject.toml matches the tag though, or else it'll maybe upload wheels of the wrong version)
Ideally we would run the cibuildwheel step whenever something has changed just so that we know we haven't broken it, but the upload to pypi step should obviously only occur when we have something to release.
I've just now created a fork of enscons
: https://github.com/ShadowJonathan/enscons-soar
The current pyproject.toml file will install from that git repository, locked to a specific commit, to enable reproducibility.
I'm not sure if this is a good setup for the future, but;
Honestly, seeing as how @garfieldnate has stated the intent to move away from Scons in the future, I think that this is fine for now (or at least this PR), a permanent temporary fix, unless it needs to be a little less temporary :)
This fork enables:
Moving away from SCons would be a big effort and is thus only a pipe dream for now 🤦
Are you enscons changes interesting generally so that you could try to upstream them? I often link against PR branches.
Possibly, but the state of upstream development is very uncertain, the last substantial commit was in 2022, and with only 3 more commits inbetween then and now updating some documentation, and a single commit last week doing some more minor documentation updates: https://github.com/dholth/enscons/
It'll have to happen async, I think.
I've addressed all the conversations and uploaded the current artefacts to pypi under a .dev1
version. I've also added this marker in the source code, to be removed when the final version gets uploaded.
The last piece from my side is to fill out the pyproject.toml
file, though of course if there are other concerns, please do let me know :)
Thank you so much for all of this! Do you need any extra information for the pyproject.toml?
(For the URLs I can imagine https://soargroup.github.io/ at the very least.
and for the keywords I can imagine "sml", "soar", "cognitive architecture", "cognitive", and "soar-sml")
git shortlog -s
:
Thanks! That was the last todo item. If this was formatted correctly (and cibuildwheel would pick up on it properly), I think this is now ready to be reviewed for merging.
With the next release, the .devX
suffix should be removed and, and the version upped to the tagged version.
Currently it builds on every commit, this includes testing if the code will import a basic hello world. This can be changed to build on every tag only, though I'm not sure if doing that in this PR is necessary, since it can be fixed after the fact.
Depending on what author means, we should have special consideration for John Laird, Allen Newell, and Paul Rosenbloom.
As for maintainers, any scraping of contributions back some amount of time from now seems reasonable. Though, I'd consider the Center for Integrated Cognition at IQM Research Institute as a whole to be the de facto "current active maintainer".
$ cd Soar
$ python3 -m venv venv
$ source venv/bin/activate
$ pip install -e Core/ClientSMLSWIG/Python
$ python
>>> import soar_sml
>>> kernel = soar_sml.Kernel.CreateKernelInNewThread()
>>> agent = kernel.CreateAgent("hello")
>>> agent.ExecuteCommandLine("p s1")
'(S1 ^epmem E1 ^io I1 ^reward-link R1 ^smem L1 ^superstate nil\n ^type state)\n'
Holy smokes I can't believe this just works! 🪄
I'm also not able to pip install anything locally for testing yet; pypi says that Intel Mac is uploaded, but I don't have one for testing.
😬
Ai... that was exactly what I was hoping wouldn't happen. Did you do pip install soar-sml==9.6.2
specifically? Since pip install soar-sml
should "just work"
If it doesn't, that means I'll have to yank/delete that version (and then .3 is the next "full" version that'll work on pip), or I'll have to take a look at supplementing that version with more binary distributions (wheels).
Currently, 9.6.2.dev1
is uploaded as a "pre-release", pip foregoes prereleases if it sees a final release, which in this case could get it "stuck". My own local pip seems to not have this problem, I'd recommend running pip install -U pip
before trying again, and see if it works then.
Edit: I'm currently testing old versions of pip
, and on python3.9, installing pip~=19
seems to have problems picking up on the fact that it is ARM64; try running pip install -U pip
first? If that doesn't work, please give me the output of pip debug --verbose
, so I can figure out which of the tags it is (trying) to grab.
So I guess I'm just wondering if there's any uncertainty that that part won't work once everything is built and ready to upload there.
As I poked over email: that bit was a mistake on my end.
On pypi, for version 9.6.2, there only exists a wheel (binary distribution) for python 3.8 on Intel (x86) Mac, while for the .dev releases, there exists wheels for a bunch of other platforms and Python versions, which pip will resolve properly.
You can test this by manually doing pip install soar-sml==9.6.2.dev1
, if you get any errors, please do forward them to me, together with the OS and Python version you're using.
We can remedy this by just uploading wheels for the other platforms and Python versions for 9.6.2 (which is easily done, though it means the metadata of one wheel is off), or removing/yanking that version and releasing "proper" only for .3, though with the way things are going, I think I'll upload the other wheels for .2 after this PR is finished, so that pip install
will work properly in all cases, and there'll be no confusion.
One odd "hole" I just found in releases; Python 3.8 for ARM64 isn't built and uploaded.
I remember this being an issue on cibuildwheel, where they don't have access (?) or can't install a (proper) ARM64 installer for python3.8 on macos, which means that wheel cant be built.
pip install soar-sml==9.6.2.dev1
yields this error for me:
ERROR: Could not find a version that satisfies the requirement soar-sml==9.6.2.dev1 (from versions: none)
ERROR: No matching distribution found for soar-sml==9.6.2.dev1
The error looks exactly the same (except the version string) when I do pip install soar-sml==9.6.2
or pip install soar-sml
.
FYI I'm on an ARM64 Mac.
Here's the pip debug --verbose
output, as requested.
pip version: pip 24.0 from /Users/nathanglenn/dev/workspaces/python_workspace/venv/lib/python3.12/site-packages/pip (python 3.12)
sys.version: 3.12.3 (main, Apr 9 2024, 08:09:14) [Clang 15.0.0 (clang-1500.1.0.2.5)]
sys.executable: /Users/nathanglenn/dev/workspaces/python_workspace/venv/bin/python3.12
sys.getdefaultencoding: utf-8
sys.getfilesystemencoding: utf-8
locale.getpreferredencoding: UTF-8
sys.platform: darwin
sys.implementation:
name: cpython
'cert' config value: Not specified
REQUESTS_CA_BUNDLE: None
CURL_CA_BUNDLE: None
pip._vendor.certifi.where(): /Users/nathanglenn/dev/workspaces/python_workspace/venv/lib/python3.12/site-packages/pip/_vendor/certifi/cacert.pem
pip._vendor.DEBUNDLED: False
vendored library versions:
CacheControl==0.13.1
colorama==0.4.6
distlib==0.3.8
distro==1.8.0
msgpack==1.0.5
packaging==21.3
platformdirs==3.8.1
pyparsing==3.1.0
pyproject-hooks==1.0.0
requests==2.31.0
certifi==2023.07.22
chardet==5.1.0
idna==3.4
urllib3==1.26.17
rich==13.4.2 (Unable to locate actual module version, using vendor.txt specified version)
pygments==2.15.1
typing_extensions==4.7.1 (Unable to locate actual module version, using vendor.txt specified version)
resolvelib==1.0.1
setuptools==68.0.0 (Unable to locate actual module version, using vendor.txt specified version)
six==1.16.0
tenacity==8.2.2 (Unable to locate actual module version, using vendor.txt specified version)
tomli==2.0.1
truststore==0.8.0
webencodings==0.5.1 (Unable to locate actual module version, using vendor.txt specified version)
Compatible tags: 528
cp312-cp312-macosx_13_0_arm64
cp312-cp312-macosx_13_0_universal2
cp312-cp312-macosx_12_0_arm64
cp312-cp312-macosx_12_0_universal2
cp312-cp312-macosx_11_0_arm64
cp312-cp312-macosx_11_0_universal2
cp312-cp312-macosx_10_16_universal2
cp312-cp312-macosx_10_15_universal2
cp312-cp312-macosx_10_14_universal2
cp312-cp312-macosx_10_13_universal2
cp312-cp312-macosx_10_12_universal2
cp312-cp312-macosx_10_11_universal2
cp312-cp312-macosx_10_10_universal2
cp312-cp312-macosx_10_9_universal2
cp312-cp312-macosx_10_8_universal2
cp312-cp312-macosx_10_7_universal2
cp312-cp312-macosx_10_6_universal2
cp312-cp312-macosx_10_5_universal2
cp312-cp312-macosx_10_4_universal2
cp312-abi3-macosx_13_0_arm64
cp312-abi3-macosx_13_0_universal2
cp312-abi3-macosx_12_0_arm64
cp312-abi3-macosx_12_0_universal2
cp312-abi3-macosx_11_0_arm64
cp312-abi3-macosx_11_0_universal2
cp312-abi3-macosx_10_16_universal2
cp312-abi3-macosx_10_15_universal2
cp312-abi3-macosx_10_14_universal2
cp312-abi3-macosx_10_13_universal2
cp312-abi3-macosx_10_12_universal2
cp312-abi3-macosx_10_11_universal2
cp312-abi3-macosx_10_10_universal2
cp312-abi3-macosx_10_9_universal2
cp312-abi3-macosx_10_8_universal2
cp312-abi3-macosx_10_7_universal2
cp312-abi3-macosx_10_6_universal2
cp312-abi3-macosx_10_5_universal2
cp312-abi3-macosx_10_4_universal2
cp312-none-macosx_13_0_arm64
cp312-none-macosx_13_0_universal2
cp312-none-macosx_12_0_arm64
cp312-none-macosx_12_0_universal2
cp312-none-macosx_11_0_arm64
cp312-none-macosx_11_0_universal2
cp312-none-macosx_10_16_universal2
cp312-none-macosx_10_15_universal2
cp312-none-macosx_10_14_universal2
cp312-none-macosx_10_13_universal2
cp312-none-macosx_10_12_universal2
cp312-none-macosx_10_11_universal2
cp312-none-macosx_10_10_universal2
cp312-none-macosx_10_9_universal2
cp312-none-macosx_10_8_universal2
cp312-none-macosx_10_7_universal2
cp312-none-macosx_10_6_universal2
cp312-none-macosx_10_5_universal2
cp312-none-macosx_10_4_universal2
cp311-abi3-macosx_13_0_arm64
cp311-abi3-macosx_13_0_universal2
cp311-abi3-macosx_12_0_arm64
cp311-abi3-macosx_12_0_universal2
cp311-abi3-macosx_11_0_arm64
cp311-abi3-macosx_11_0_universal2
cp311-abi3-macosx_10_16_universal2
cp311-abi3-macosx_10_15_universal2
cp311-abi3-macosx_10_14_universal2
cp311-abi3-macosx_10_13_universal2
cp311-abi3-macosx_10_12_universal2
cp311-abi3-macosx_10_11_universal2
cp311-abi3-macosx_10_10_universal2
cp311-abi3-macosx_10_9_universal2
cp311-abi3-macosx_10_8_universal2
cp311-abi3-macosx_10_7_universal2
cp311-abi3-macosx_10_6_universal2
cp311-abi3-macosx_10_5_universal2
cp311-abi3-macosx_10_4_universal2
cp310-abi3-macosx_13_0_arm64
cp310-abi3-macosx_13_0_universal2
cp310-abi3-macosx_12_0_arm64
cp310-abi3-macosx_12_0_universal2
cp310-abi3-macosx_11_0_arm64
cp310-abi3-macosx_11_0_universal2
cp310-abi3-macosx_10_16_universal2
cp310-abi3-macosx_10_15_universal2
cp310-abi3-macosx_10_14_universal2
cp310-abi3-macosx_10_13_universal2
cp310-abi3-macosx_10_12_universal2
cp310-abi3-macosx_10_11_universal2
cp310-abi3-macosx_10_10_universal2
cp310-abi3-macosx_10_9_universal2
cp310-abi3-macosx_10_8_universal2
cp310-abi3-macosx_10_7_universal2
cp310-abi3-macosx_10_6_universal2
cp310-abi3-macosx_10_5_universal2
cp310-abi3-macosx_10_4_universal2
cp39-abi3-macosx_13_0_arm64
cp39-abi3-macosx_13_0_universal2
cp39-abi3-macosx_12_0_arm64
cp39-abi3-macosx_12_0_universal2
cp39-abi3-macosx_11_0_arm64
cp39-abi3-macosx_11_0_universal2
cp39-abi3-macosx_10_16_universal2
cp39-abi3-macosx_10_15_universal2
cp39-abi3-macosx_10_14_universal2
cp39-abi3-macosx_10_13_universal2
cp39-abi3-macosx_10_12_universal2
cp39-abi3-macosx_10_11_universal2
cp39-abi3-macosx_10_10_universal2
cp39-abi3-macosx_10_9_universal2
cp39-abi3-macosx_10_8_universal2
cp39-abi3-macosx_10_7_universal2
cp39-abi3-macosx_10_6_universal2
cp39-abi3-macosx_10_5_universal2
cp39-abi3-macosx_10_4_universal2
cp38-abi3-macosx_13_0_arm64
cp38-abi3-macosx_13_0_universal2
cp38-abi3-macosx_12_0_arm64
cp38-abi3-macosx_12_0_universal2
cp38-abi3-macosx_11_0_arm64
cp38-abi3-macosx_11_0_universal2
cp38-abi3-macosx_10_16_universal2
cp38-abi3-macosx_10_15_universal2
cp38-abi3-macosx_10_14_universal2
cp38-abi3-macosx_10_13_universal2
cp38-abi3-macosx_10_12_universal2
cp38-abi3-macosx_10_11_universal2
cp38-abi3-macosx_10_10_universal2
cp38-abi3-macosx_10_9_universal2
cp38-abi3-macosx_10_8_universal2
cp38-abi3-macosx_10_7_universal2
cp38-abi3-macosx_10_6_universal2
cp38-abi3-macosx_10_5_universal2
cp38-abi3-macosx_10_4_universal2
cp37-abi3-macosx_13_0_arm64
cp37-abi3-macosx_13_0_universal2
cp37-abi3-macosx_12_0_arm64
cp37-abi3-macosx_12_0_universal2
cp37-abi3-macosx_11_0_arm64
cp37-abi3-macosx_11_0_universal2
cp37-abi3-macosx_10_16_universal2
cp37-abi3-macosx_10_15_universal2
cp37-abi3-macosx_10_14_universal2
cp37-abi3-macosx_10_13_universal2
cp37-abi3-macosx_10_12_universal2
cp37-abi3-macosx_10_11_universal2
cp37-abi3-macosx_10_10_universal2
cp37-abi3-macosx_10_9_universal2
cp37-abi3-macosx_10_8_universal2
cp37-abi3-macosx_10_7_universal2
cp37-abi3-macosx_10_6_universal2
cp37-abi3-macosx_10_5_universal2
cp37-abi3-macosx_10_4_universal2
cp36-abi3-macosx_13_0_arm64
cp36-abi3-macosx_13_0_universal2
cp36-abi3-macosx_12_0_arm64
cp36-abi3-macosx_12_0_universal2
cp36-abi3-macosx_11_0_arm64
cp36-abi3-macosx_11_0_universal2
cp36-abi3-macosx_10_16_universal2
cp36-abi3-macosx_10_15_universal2
cp36-abi3-macosx_10_14_universal2
cp36-abi3-macosx_10_13_universal2
cp36-abi3-macosx_10_12_universal2
cp36-abi3-macosx_10_11_universal2
cp36-abi3-macosx_10_10_universal2
cp36-abi3-macosx_10_9_universal2
cp36-abi3-macosx_10_8_universal2
cp36-abi3-macosx_10_7_universal2
cp36-abi3-macosx_10_6_universal2
cp36-abi3-macosx_10_5_universal2
cp36-abi3-macosx_10_4_universal2
cp35-abi3-macosx_13_0_arm64
cp35-abi3-macosx_13_0_universal2
cp35-abi3-macosx_12_0_arm64
cp35-abi3-macosx_12_0_universal2
cp35-abi3-macosx_11_0_arm64
cp35-abi3-macosx_11_0_universal2
cp35-abi3-macosx_10_16_universal2
cp35-abi3-macosx_10_15_universal2
cp35-abi3-macosx_10_14_universal2
cp35-abi3-macosx_10_13_universal2
cp35-abi3-macosx_10_12_universal2
cp35-abi3-macosx_10_11_universal2
cp35-abi3-macosx_10_10_universal2
cp35-abi3-macosx_10_9_universal2
cp35-abi3-macosx_10_8_universal2
cp35-abi3-macosx_10_7_universal2
cp35-abi3-macosx_10_6_universal2
cp35-abi3-macosx_10_5_universal2
cp35-abi3-macosx_10_4_universal2
cp34-abi3-macosx_13_0_arm64
cp34-abi3-macosx_13_0_universal2
cp34-abi3-macosx_12_0_arm64
cp34-abi3-macosx_12_0_universal2
cp34-abi3-macosx_11_0_arm64
cp34-abi3-macosx_11_0_universal2
cp34-abi3-macosx_10_16_universal2
cp34-abi3-macosx_10_15_universal2
cp34-abi3-macosx_10_14_universal2
cp34-abi3-macosx_10_13_universal2
cp34-abi3-macosx_10_12_universal2
cp34-abi3-macosx_10_11_universal2
cp34-abi3-macosx_10_10_universal2
cp34-abi3-macosx_10_9_universal2
cp34-abi3-macosx_10_8_universal2
cp34-abi3-macosx_10_7_universal2
cp34-abi3-macosx_10_6_universal2
cp34-abi3-macosx_10_5_universal2
cp34-abi3-macosx_10_4_universal2
cp33-abi3-macosx_13_0_arm64
cp33-abi3-macosx_13_0_universal2
cp33-abi3-macosx_12_0_arm64
cp33-abi3-macosx_12_0_universal2
cp33-abi3-macosx_11_0_arm64
cp33-abi3-macosx_11_0_universal2
cp33-abi3-macosx_10_16_universal2
cp33-abi3-macosx_10_15_universal2
cp33-abi3-macosx_10_14_universal2
cp33-abi3-macosx_10_13_universal2
cp33-abi3-macosx_10_12_universal2
cp33-abi3-macosx_10_11_universal2
cp33-abi3-macosx_10_10_universal2
cp33-abi3-macosx_10_9_universal2
cp33-abi3-macosx_10_8_universal2
cp33-abi3-macosx_10_7_universal2
cp33-abi3-macosx_10_6_universal2
cp33-abi3-macosx_10_5_universal2
cp33-abi3-macosx_10_4_universal2
cp32-abi3-macosx_13_0_arm64
cp32-abi3-macosx_13_0_universal2
cp32-abi3-macosx_12_0_arm64
cp32-abi3-macosx_12_0_universal2
cp32-abi3-macosx_11_0_arm64
cp32-abi3-macosx_11_0_universal2
cp32-abi3-macosx_10_16_universal2
cp32-abi3-macosx_10_15_universal2
cp32-abi3-macosx_10_14_universal2
cp32-abi3-macosx_10_13_universal2
cp32-abi3-macosx_10_12_universal2
cp32-abi3-macosx_10_11_universal2
cp32-abi3-macosx_10_10_universal2
cp32-abi3-macosx_10_9_universal2
cp32-abi3-macosx_10_8_universal2
cp32-abi3-macosx_10_7_universal2
cp32-abi3-macosx_10_6_universal2
cp32-abi3-macosx_10_5_universal2
cp32-abi3-macosx_10_4_universal2
py312-none-macosx_13_0_arm64
py312-none-macosx_13_0_universal2
py312-none-macosx_12_0_arm64
py312-none-macosx_12_0_universal2
py312-none-macosx_11_0_arm64
py312-none-macosx_11_0_universal2
py312-none-macosx_10_16_universal2
py312-none-macosx_10_15_universal2
py312-none-macosx_10_14_universal2
py312-none-macosx_10_13_universal2
py312-none-macosx_10_12_universal2
py312-none-macosx_10_11_universal2
py312-none-macosx_10_10_universal2
py312-none-macosx_10_9_universal2
py312-none-macosx_10_8_universal2
py312-none-macosx_10_7_universal2
py312-none-macosx_10_6_universal2
py312-none-macosx_10_5_universal2
py312-none-macosx_10_4_universal2
py3-none-macosx_13_0_arm64
py3-none-macosx_13_0_universal2
py3-none-macosx_12_0_arm64
py3-none-macosx_12_0_universal2
py3-none-macosx_11_0_arm64
py3-none-macosx_11_0_universal2
py3-none-macosx_10_16_universal2
py3-none-macosx_10_15_universal2
py3-none-macosx_10_14_universal2
py3-none-macosx_10_13_universal2
py3-none-macosx_10_12_universal2
py3-none-macosx_10_11_universal2
py3-none-macosx_10_10_universal2
py3-none-macosx_10_9_universal2
py3-none-macosx_10_8_universal2
py3-none-macosx_10_7_universal2
py3-none-macosx_10_6_universal2
py3-none-macosx_10_5_universal2
py3-none-macosx_10_4_universal2
py311-none-macosx_13_0_arm64
py311-none-macosx_13_0_universal2
py311-none-macosx_12_0_arm64
py311-none-macosx_12_0_universal2
py311-none-macosx_11_0_arm64
py311-none-macosx_11_0_universal2
py311-none-macosx_10_16_universal2
py311-none-macosx_10_15_universal2
py311-none-macosx_10_14_universal2
py311-none-macosx_10_13_universal2
py311-none-macosx_10_12_universal2
py311-none-macosx_10_11_universal2
py311-none-macosx_10_10_universal2
py311-none-macosx_10_9_universal2
py311-none-macosx_10_8_universal2
py311-none-macosx_10_7_universal2
py311-none-macosx_10_6_universal2
py311-none-macosx_10_5_universal2
py311-none-macosx_10_4_universal2
py310-none-macosx_13_0_arm64
py310-none-macosx_13_0_universal2
py310-none-macosx_12_0_arm64
py310-none-macosx_12_0_universal2
py310-none-macosx_11_0_arm64
py310-none-macosx_11_0_universal2
py310-none-macosx_10_16_universal2
py310-none-macosx_10_15_universal2
py310-none-macosx_10_14_universal2
py310-none-macosx_10_13_universal2
py310-none-macosx_10_12_universal2
py310-none-macosx_10_11_universal2
py310-none-macosx_10_10_universal2
py310-none-macosx_10_9_universal2
py310-none-macosx_10_8_universal2
py310-none-macosx_10_7_universal2
py310-none-macosx_10_6_universal2
py310-none-macosx_10_5_universal2
py310-none-macosx_10_4_universal2
py39-none-macosx_13_0_arm64
py39-none-macosx_13_0_universal2
py39-none-macosx_12_0_arm64
py39-none-macosx_12_0_universal2
py39-none-macosx_11_0_arm64
py39-none-macosx_11_0_universal2
py39-none-macosx_10_16_universal2
py39-none-macosx_10_15_universal2
py39-none-macosx_10_14_universal2
py39-none-macosx_10_13_universal2
py39-none-macosx_10_12_universal2
py39-none-macosx_10_11_universal2
py39-none-macosx_10_10_universal2
py39-none-macosx_10_9_universal2
py39-none-macosx_10_8_universal2
py39-none-macosx_10_7_universal2
py39-none-macosx_10_6_universal2
py39-none-macosx_10_5_universal2
py39-none-macosx_10_4_universal2
py38-none-macosx_13_0_arm64
py38-none-macosx_13_0_universal2
py38-none-macosx_12_0_arm64
py38-none-macosx_12_0_universal2
py38-none-macosx_11_0_arm64
py38-none-macosx_11_0_universal2
py38-none-macosx_10_16_universal2
py38-none-macosx_10_15_universal2
py38-none-macosx_10_14_universal2
py38-none-macosx_10_13_universal2
py38-none-macosx_10_12_universal2
py38-none-macosx_10_11_universal2
py38-none-macosx_10_10_universal2
py38-none-macosx_10_9_universal2
py38-none-macosx_10_8_universal2
py38-none-macosx_10_7_universal2
py38-none-macosx_10_6_universal2
py38-none-macosx_10_5_universal2
py38-none-macosx_10_4_universal2
py37-none-macosx_13_0_arm64
py37-none-macosx_13_0_universal2
py37-none-macosx_12_0_arm64
py37-none-macosx_12_0_universal2
py37-none-macosx_11_0_arm64
py37-none-macosx_11_0_universal2
py37-none-macosx_10_16_universal2
py37-none-macosx_10_15_universal2
py37-none-macosx_10_14_universal2
py37-none-macosx_10_13_universal2
py37-none-macosx_10_12_universal2
py37-none-macosx_10_11_universal2
py37-none-macosx_10_10_universal2
py37-none-macosx_10_9_universal2
py37-none-macosx_10_8_universal2
py37-none-macosx_10_7_universal2
py37-none-macosx_10_6_universal2
py37-none-macosx_10_5_universal2
py37-none-macosx_10_4_universal2
py36-none-macosx_13_0_arm64
py36-none-macosx_13_0_universal2
py36-none-macosx_12_0_arm64
py36-none-macosx_12_0_universal2
py36-none-macosx_11_0_arm64
py36-none-macosx_11_0_universal2
py36-none-macosx_10_16_universal2
py36-none-macosx_10_15_universal2
py36-none-macosx_10_14_universal2
py36-none-macosx_10_13_universal2
py36-none-macosx_10_12_universal2
py36-none-macosx_10_11_universal2
py36-none-macosx_10_10_universal2
py36-none-macosx_10_9_universal2
py36-none-macosx_10_8_universal2
py36-none-macosx_10_7_universal2
py36-none-macosx_10_6_universal2
py36-none-macosx_10_5_universal2
py36-none-macosx_10_4_universal2
py35-none-macosx_13_0_arm64
py35-none-macosx_13_0_universal2
py35-none-macosx_12_0_arm64
py35-none-macosx_12_0_universal2
py35-none-macosx_11_0_arm64
py35-none-macosx_11_0_universal2
py35-none-macosx_10_16_universal2
py35-none-macosx_10_15_universal2
py35-none-macosx_10_14_universal2
py35-none-macosx_10_13_universal2
py35-none-macosx_10_12_universal2
py35-none-macosx_10_11_universal2
py35-none-macosx_10_10_universal2
py35-none-macosx_10_9_universal2
py35-none-macosx_10_8_universal2
py35-none-macosx_10_7_universal2
py35-none-macosx_10_6_universal2
py35-none-macosx_10_5_universal2
py35-none-macosx_10_4_universal2
py34-none-macosx_13_0_arm64
py34-none-macosx_13_0_universal2
py34-none-macosx_12_0_arm64
py34-none-macosx_12_0_universal2
py34-none-macosx_11_0_arm64
py34-none-macosx_11_0_universal2
py34-none-macosx_10_16_universal2
py34-none-macosx_10_15_universal2
py34-none-macosx_10_14_universal2
py34-none-macosx_10_13_universal2
py34-none-macosx_10_12_universal2
py34-none-macosx_10_11_universal2
py34-none-macosx_10_10_universal2
py34-none-macosx_10_9_universal2
py34-none-macosx_10_8_universal2
py34-none-macosx_10_7_universal2
py34-none-macosx_10_6_universal2
py34-none-macosx_10_5_universal2
py34-none-macosx_10_4_universal2
py33-none-macosx_13_0_arm64
py33-none-macosx_13_0_universal2
py33-none-macosx_12_0_arm64
py33-none-macosx_12_0_universal2
py33-none-macosx_11_0_arm64
py33-none-macosx_11_0_universal2
py33-none-macosx_10_16_universal2
py33-none-macosx_10_15_universal2
py33-none-macosx_10_14_universal2
py33-none-macosx_10_13_universal2
py33-none-macosx_10_12_universal2
py33-none-macosx_10_11_universal2
py33-none-macosx_10_10_universal2
py33-none-macosx_10_9_universal2
py33-none-macosx_10_8_universal2
py33-none-macosx_10_7_universal2
py33-none-macosx_10_6_universal2
py33-none-macosx_10_5_universal2
py33-none-macosx_10_4_universal2
py32-none-macosx_13_0_arm64
py32-none-macosx_13_0_universal2
py32-none-macosx_12_0_arm64
py32-none-macosx_12_0_universal2
py32-none-macosx_11_0_arm64
py32-none-macosx_11_0_universal2
py32-none-macosx_10_16_universal2
py32-none-macosx_10_15_universal2
py32-none-macosx_10_14_universal2
py32-none-macosx_10_13_universal2
py32-none-macosx_10_12_universal2
py32-none-macosx_10_11_universal2
py32-none-macosx_10_10_universal2
py32-none-macosx_10_9_universal2
py32-none-macosx_10_8_universal2
py32-none-macosx_10_7_universal2
py32-none-macosx_10_6_universal2
py32-none-macosx_10_5_universal2
py32-none-macosx_10_4_universal2
py31-none-macosx_13_0_arm64
py31-none-macosx_13_0_universal2
py31-none-macosx_12_0_arm64
py31-none-macosx_12_0_universal2
py31-none-macosx_11_0_arm64
py31-none-macosx_11_0_universal2
py31-none-macosx_10_16_universal2
py31-none-macosx_10_15_universal2
py31-none-macosx_10_14_universal2
py31-none-macosx_10_13_universal2
py31-none-macosx_10_12_universal2
py31-none-macosx_10_11_universal2
py31-none-macosx_10_10_universal2
py31-none-macosx_10_9_universal2
py31-none-macosx_10_8_universal2
py31-none-macosx_10_7_universal2
py31-none-macosx_10_6_universal2
py31-none-macosx_10_5_universal2
py31-none-macosx_10_4_universal2
py30-none-macosx_13_0_arm64
py30-none-macosx_13_0_universal2
py30-none-macosx_12_0_arm64
py30-none-macosx_12_0_universal2
py30-none-macosx_11_0_arm64
py30-none-macosx_11_0_universal2
py30-none-macosx_10_16_universal2
py30-none-macosx_10_15_universal2
py30-none-macosx_10_14_universal2
py30-none-macosx_10_13_universal2
py30-none-macosx_10_12_universal2
py30-none-macosx_10_11_universal2
py30-none-macosx_10_10_universal2
py30-none-macosx_10_9_universal2
py30-none-macosx_10_8_universal2
py30-none-macosx_10_7_universal2
py30-none-macosx_10_6_universal2
py30-none-macosx_10_5_universal2
py30-none-macosx_10_4_universal2
cp312-none-any
py312-none-any
py3-none-any
py311-none-any
py310-none-any
py39-none-any
py38-none-any
py37-none-any
py36-none-any
py35-none-any
py34-none-any
py33-none-any
py32-none-any
py31-none-any
py30-none-any
Thanks for all of the comments and changes. Everything looks really good!
...right, I see what's wrong, you're on MacOS 13, while the builder aims for MacOS 14, and so there are no wheels it can download.
This should be configurable, and I'll attempt to get it down to MacOS 12 or lower, to maximise compatibility with old MacOS versions.
@garfieldnate I've fixed the problem with the latest commit, this should now properly "downversion" the built-for mac wheels, so that it tags itself by the minimum mac version it can get downloaded by, and as a result we got Intel Mac compatibility for Mavericks (10.9!), and all Apple Silicon Macs :)
I've uploaded the new build artifacts that tag these correctly under .dev2
, I suspect that the next wheels I'll upload will have that dynamic versioning mechanism I talked about, but for now, soar-sml
should be installable on (realistically) all Macs :)
(Excluding python 3.8 on Apple Silicon (ARM64) macs, for reasons I poked earlier, and in the file comments)
I tried it just now and it just worked! Tested on my ARM Mac, then x86_64 Ubuntu and Windows 11.
build.yml
, as I've already began working on it, and it seems to be easy enough.The way I'll be doing it (by splitting the jobs) will make CI faster, too.
I'll add a CI job that'll publish the build versions to test.pypi.org, and I'll add a CI job that'll publish them to regular pypi if the CI run gets triggered by a tag push / release.
I'm having some trouble understanding the GitHub UI, but as far as I can tell, the one question I just posted is the last unresolved conversation, correct? And then it's ready to merge, right?
One other question 😅 Do we need to upload soar-compat to test.pypi.org?
I'm having some trouble understanding the GitHub UI, but as far as I can tell, the one question I just posted is the last unresolved conversation, correct?
Yes
And then it's ready to merge, right?
If you feel like it is, yes :)
Do we need to upload soar-compat to test.pypi.org?
...Yes, actually, I just tested it, and it can't find soar-compat, so I'll upload it right now ^^;
Edit: done :)
Thank you a lot! 💚
This PR adds cibuildwheel support for python wheels: allowing for CI-powered reproducible python builds into self-contained wheels.
(Python wheels are distribution packages containing everything a python library needs to run, including shared libraries. They're tagged with compatibility markers (OS, Architecture, and for linux: GLIB version), so that
pip
can download the correct variant from a package index like https://pypi.org)This is achieved with
enscons
, which puppetsscons
to achieve the right builds and environments.This names the output library as
soar-sml
, and renamesPython_sml_ClientInterface.py
to__init__.py
, so thatimport soar_sml
will have the same effect asimport Python_sml_ClientInterface
.As this then becomes a
pip
-installable library,sys.path.append
is not required anymore,import soar_sml
will do the trick from anywhere on the system.TODOs
.github/workflows
file for doingcibuildwheel
pyproject.toml
authors
,keywords
,classifiers
,urls
, and probably another few fields in thepyproject.toml
file needs to be updated/added with the right data.My goal with this is to make Soar ready to be packaged for https://pypi.org distribution (likely in a future PR, with proper discussion), and to then create a library that will make accessing soar even more pythonic. (Name pending, also, soar was taken,
*shakes fist*)I hope that both of these efforts will lower the barrier for entry and experimentation with Soar, especially as SML allows anyone to create a "body" for Soar agents to "interact" with the world.