Having a go at what was suggested in this previous post by @AlanRynne and @jonathon I’ve managed to load SpecklePy in PyRevit using CPython3 to start transporting things around.
The first error that I encounter was that path.mkdir(exist_ok=True, parents=True) would not allow arguments in speckle_path_provider.py which I (questionably) bypass by simply commenting a couple of lines and returning path directly in the _ensure_folder_exists function.
However, once I try to connect to the client following the instructions in the docs I get the following error from PyRevit:
CPython Traceback:
SpeckleException : SpeckleException: Failed to execute the GraphQL active_user request. Inner exception: Transport is already connected
File "C:\Users\janx\Documents\MyExtensions\MyFirstExtension.extension\MyTools.tab\MyTools.panel\MyFirstCommand.pushbutton\script.py", line 45, in <module>
client.authenticate_with_account(account)
File "C:\Users\jan\AppData\Local\Programs\Python\Python39\Lib\site-packages\specklepy\api\client.py", line 146, in authenticate_with_account
self._set_up_client()
File "C:\Users\jan\AppData\Local\Programs\Python\Python39\Lib\site-packages\specklepy\api\client.py", line 174, in _set_up_client
raise user_or_error
pyRevitLabs.PythonNet
at Python.Runtime.Runtime.CheckExceptionOccurred()
at Python.Runtime.PyScope.Exec(String code, IntPtr _globals, IntPtr _locals)
at Python.Runtime.PyScope.Exec(String code, PyDict locals)
at PyRevitLabs.PyRevit.Runtime.CPythonEngine.Execute(ScriptRuntime& runtime)
The error happens when I try to authenticate : client = SpeckleClient(host="http://XXX.XX.XX.XXX/", use_ssl=False)
I have deployed my own server which is currently http not using any SSL certificates. Also, if it helps, this error only happens within PyRevit which uses python 3.8.5. When I run the example in outside in plain python 3.9 everything works smoothly.
Looking forward to your kind advice on how to bypass this one!
@AlanRynne sorry, I guess I didn’t explained myself well enough. I have already loaded the C# SDK to use the converter in order to convert Revit geometry to Base, that part is OK (btw thanks for the tip ) My goal is then to send those converted Speckle objects using SpecklePy within PyRevit, which is what is producing this error.
Forget about the other post which was just for context, and just consider that my I’m trying to run SpecklePy to send a base geometry from PyRevit as ilustrated here . Is there a reason why this error would be produced when I try to authenticate?
Not sure why you’d be getting that error, afaik SpecklePy was never designed to run in IronPython (the same way you can’t run NumPy or other librarires on a Grasshopper python script)
But what you’re trying to do is not going to work (even if you get SpeckleClient to initialise correctly). I’ll explain:
You cannot use specklepy + speckle-sharp in the same context as they’re 2 completely different libraries in 2 different languages. IronPython may allow you to load both, but you’ll never be able to send some C# objects with the Python library.
If you start off with SpeckleCore to convert your objects, then those objects are C# classes specklepy has no way of interpreting.
You have to use the methods and functionality in SpeckleCore (the C# one you loaded) which does include every single function specklepy does, but the syntax and inputs may vary slightly.
i.e. SpeckleCore has no SpeckleClient, it has a Speckle.Core.Api.Client… and so on.
So, in the case of pyRevit, I would forget that SpecklePy even exists, and go for SpeckleCore instead all the way.
@AlanRynne I think you are not considering that in pyrevit (and dynamo and Rhino 8) it’s now possible to use CPython3 (not IronPython) through pythonnet. It’s perfectly possible to load the good old numpys and scipys with this trick, so as far as SpecklePy is concern I am within a pure python environment. Indeed I have no issues so far on loading SpeckleCore2.dll, using it to convert Revit Geometries to Base Objects, so no problem on the object conversion part. That is not the problem. You might as well consider that I start with a python custom created Base object already.
The real issue is comes in the request part from PyRevit, so not to get too sidetracked with interop issues, back to the problem:
Is it possible that you expand on the error: SpeckleException : SpeckleException: Failed to execute the GraphQL active_user request. Inner exception: Transport is already connected so to get an insight of what could possibly be happening with the autheticaion request? Perhaps there is some version incompatiblity with one of the libraries that Python 3.8.5 uses to do so? I saw a similar post by @jonathonhere but could not make much sense of what the issue was.
Are there any examples of how to send geometries to the server using Speckle.Core.Api.Client (alla SpecklePy) just to check if the issue lies there?
Just asked our python expert and it seems specklepy only supports python 3.9->3.11, so I’m guessing this may be the reason for the issue, although we’ve never tested specklepy in CPython3/IronPython before…
This may be the case “theoretically”, but for your particular use-case this is never going to work when sending, as the converted objects from SpeckleCore.dll will not be compatible with the objects specklepy is expecting to be given for sending. The objects coming from Revit (or SpeckleCore.dll) are not pure python objects, but C# objects loaded into CPython
To that end, @janx you are doing us a service , as this is unexplored territory; we will investigate doing so when we have the bandwidth. I’ve added it to my to-do list. We could generally do with more csharp examples, but this combination of the sharp library under CPython is certainly not covered.
That seems on the face of it to be an entirely separate issue as the exception you quote is not related to missing libraries (which the default runtime inside FME had by a version mismatch)
All of our CSharp connectors do so, and you could explore the Sharp - speckle-sharp repo, but that’s a large code base.
In particular, that might be helpful to look at the StreamWrapper class, which mirrors the specklepy StreamWrapper (unsurprisingly), so some examples in the guide should translate.
This is a helper class to take a lot of complication out of the process, as it will start by hardcoding your server authentication (for now)
I remain curious as to why specifically this error is taking place, as it doesn´t even get to the point of sending anything, it´s only when validating the account that the error arises. This is all the code needed to reproduce this error:
#! python3
from specklepy.api.client import SpeckleClient
from specklepy.api.credentials import get_default_account
client = SpeckleClient(host="http://XXX.XX.XXX.XXX/", use_ssl=False)
account = get_default_account()
client.authenticate_with_account(account)
In any case, taking from your answer, I will try the SpeckleCore way. Thanks for the example also.
a lot of the fluff, why this doesn’t work, has to do with account management sqlite etc
if we had a way to supply a token with an argument and send with maybe an inmemory cache, things would most probably work in these sorts of environments
So our untested theory is that account management (i.e getDefaultAccount and authenticate_with_account) are problematic in these environments.
We never designed this to work on CPython/IronPython so I can’t give you an ETA on when we’ll get to look into this.