Python 3.4

85 views
Skip to first unread message

Dave Thomas

unread,
Jan 15, 2015, 10:27:54 AM1/15/15
to autob...@googlegroups.com
Tobias,

Crossbar runs on twisted that is partially ported to 3.4, what are your
plans/roadmap to update crossbar to run on 3.4 and/or switch to asyncio?

Additionally, a general question, does crossbar.io support loading
components written in 3.4 or later, how does that work, requirements?

Thanks for all of your hard work on this project, VERY cool stuff!

Dave Thomas

unread,
Jan 15, 2015, 11:40:36 AM1/15/15
to autob...@googlegroups.com

Looks like I answered my own question.... or is there another way to use an imported component that is written in 3.4 with asyncio?

2015-01-15 11:37:53-0500 [Container    5730] Entering event loop ..
2015-01-15 11:37:53-0500 [Container    5730] Warning: process utilities not available
2015-01-15 11:37:53-0500 [Controller   5718] Container with ID 'worker2' and PID 5730 started
2015-01-15 11:37:53-0500 [Controller   5718] Container 'worker2': PYTHONPATH extended
2015-01-15 11:37:54-0500 [Container    5730] ERROR: failed to import class hello.Main.MyBackendComponent ("invalid syntax (Main.py, line 36)")
2015-01-15 11:37:54-0500 [Controller   5718] Traceback (most recent call last):
2015-01-15 11:37:54-0500 [Controller   5718]   File "/usr/local/lib/python2.7/dist-packages/crossbar/controller/node.py", line 190, in run_node_config
2015-01-15 11:37:54-0500 [Controller   5718]     yield self._run_node_config(config)
2015-01-15 11:37:54-0500 [Controller   5718] ApplicationError: ApplicationError('crossbar.error.cannot_import', args = (u'ERROR: failed to import class hello.Main.MyBackendComponent ("invalid syntax (Main.py, line 36)")', u'Traceback (most recent call last):\n  File "/usr/local/lib/python2.7/dist-packages/crossbar/worker/container.py", line 214, in start_container_component\n    module = importlib.import_module(module_name)\n  File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module\n    __import__(name)\n  File "/home/dave/PycharmProjects/CrossbarDemos/HelloDemo/hello/Main.py", line 36\n    reg = yield from self.register(utcnow, \'com.timeservice.now\')\n                   ^\nSyntaxError: invalid syntax\n'), kwargs = {})
2015-01-15 11:37:54-0500 [Controller   5718] Main loop terminated.

Dave Thomas

unread,
Jan 15, 2015, 11:46:02 AM1/15/15
to autob...@googlegroups.com
And here is the backend component, pretty much straight from a demo, I am referring to (you can see the old application router code commented out):

import json
import datetime
import asyncio
from autobahn.asyncio import wamp, websocket

class DavesTestClass(object):
 
def __init__(self):
 
self.name = 'Dave'
 
self.age = 51

class MyBackendComponent(wamp.ApplicationSession):
 
"""
 Application code goes here. This is an example component that provides
 a simple procedure which can be called remotely from any WAMP peer.
 It also publishes an event every second to some topic.
 """

 
def onConnect(self):
 
self.join("realm1")

 
@asyncio.coroutine
 
def onJoin(self, details):

 
def jsonDefault(o): # https://freepythontips.wordpress.com/2013/08/08/storing-and-loading-data-with-json/
 
return o.__dict__

 
# Register a procedure for remote calling
 
def utcnow():
 now
= datetime.datetime.utcnow()
 time
= now.strftime("%Y-%m-%dT%H:%M:%SZ") # six.u()
 
print(time)
 
return time

 reg
= yield from self.register(utcnow, 'com.timeservice.now')
 
print("Registered procedure with ID {}".format(reg.id))

 
# Publish events to a topic
 dave
= DavesTestClass()
 
# print(dave)

 
while True:
 objToSend
= json.dumps(dave, default=jsonDefault, indent=4)
 
self.publish('com.myapp.topic1', objToSend)
 
print('Published: ', objToSend)
 
yield from asyncio.sleep(1)


# if __name__ == '__main__':
# # 1) create a WAMP router factory
# router_factory = wamp.RouterFactory()
#
# # 2) create a WAMP router session factory
# session_factory = wamp.RouterSessionFactory(router_factory)
#
# # 3) Optionally, add embedded WAMP application sessions to the router
# session_factory.add(MyBackendComponent())
#
# # 4) create a WAMP-over-WebSocket transport server factory
# transport_factory = websocket.WampWebSocketServerFactory(session_factory, debug=False, debug_wamp=False)
#
# # 5) start the server
# loop = asyncio.get_event_loop()
# coro = loop.create_server(transport_factory, '127.0.0.1', 8080)
# server = loop.run_until_complete(coro)
# try:
# # 6) now enter the asyncio event loop
# loop.run_forever()
# except KeyboardInterrupt:
# pass
# finally:
# server.close()
# loop.close()

My crossbar config, again straight from a demo with an adjusted import class:

{
   
"controller": {
   
},
   
"workers": [
     
{
         
"type": "router",
         
"options": {
           
"pythonpath": [".."]
         
},
         
"realms": [
           
{
               
"name": "realm1",
               
"roles": [
                 
{
                     
"name": "anonymous",
                     
"permissions": [
                       
{
                           
"uri": "*",
                           
"publish": true,
                           
"subscribe": true,
                           
"call": true,
                           
"register": true
                       
}
                     
]
                 
}
               
]
           
}
         
],
         
"transports": [
           
{
               
"type": "web",
               
"endpoint": {
                 
"type": "tcp",
                 
"port": 8080
               
},
               
"paths": {
                 
"/": {
                     
"type": "static",
                     
"directory": "../hello/web"
                 
},
                 
"ws": {
                     
"type": "websocket"
                 
}
               
}
           
}
         
]
     
},
     
{
         
"type": "container",
         
"options": {
           
"pythonpath": [".."]
         
},
         
"components": [
           
{
               
"type": "class",
               
"classname": "hello.Main.MyBackendComponent",
               
"realm": "realm1",
               
"transport": {
                 
"type": "websocket",
                 
"endpoint": {
                     
"type": "tcp",
                     
"host": "127.0.0.1",
                     
"port": 8080
                 
},
                 
"url": "ws://127.0.0.1:8080/ws"
               
}
           
}
         
]
     
}
   
]
}

Tobias Oberstein

unread,
Jan 15, 2015, 4:25:02 PM1/15/15
to autob...@googlegroups.com
Am 15.01.2015 um 17:40 schrieb Dave Thomas:
>
> Looks like I answered my own question.... or is there another way to
> use an imported component that is written in 3.4 with asyncio?

Sure. You need to run the component as a guest worker.

Python/asyncio components cannot be run inside native workers
(side-by-side in routers/containers)


Tobias Oberstein

unread,
Jan 15, 2015, 4:27:39 PM1/15/15
to autob...@googlegroups.com
Hi Dave,

Am 15.01.2015 um 16:27 schrieb Dave Thomas:
> Tobias,
>
> Crossbar runs on twisted that is partially ported to 3.4, what are your
> plans/roadmap to update crossbar to run on 3.4 and/or switch to asyncio?

We will support running Crossbar.io under Python 3 as soon as Twisted
has "sufficient" support for Python 3 (that is, for all the stuff we use
in Crossbar.io)

We have no plans, needs or reasons to port to asyncio (no gain, only pain).

>
> Additionally, a general question, does crossbar.io
> <http://crossbar.io/> support loading
> components written in 3.4 or later, how does that work, requirements?

Yes. These are run exactly as Node, Java or other components:
Crossbar.io can start and monitor so-called guest workers. These can be
anything ..

>
> Thanks for all of your hard work on this project, VERY cool stuff!

Great, thanks!

>
> --
> You received this message because you are subscribed to the Google
> Groups "Autobahn" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to autobahnws+...@googlegroups.com
> <mailto:autobahnws+...@googlegroups.com>.
> To post to this group, send email to autob...@googlegroups.com
> <mailto:autob...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/autobahnws/CAAPehXYRhfK%2BBStP%2BEOfv%2BxROXLFeDwUx2X%2BQUs7YUejV1pMnQ%40mail.gmail.com
> <https://groups.google.com/d/msgid/autobahnws/CAAPehXYRhfK%2BBStP%2BEOfv%2BxROXLFeDwUx2X%2BQUs7YUejV1pMnQ%40mail.gmail.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout.

Dave Thomas

unread,
Jan 15, 2015, 5:49:26 PM1/15/15
to autob...@googlegroups.com
Tobias,

I REALLY appreciate that you take the time to monitor these posts! I wasn't expecting a same day response! Thank you.

I ended up getting a python 3.4 file to run and will document it here for others.

Ok, so I know that this is all over the documents but it is REALLY important to remember that crossbar is truly decoupled as the router from application logic (yes, you can run a python 2.7 file from INSIDE the router process as far as I can tell as a component), but as Tobias says, it's a current requirement to run a python 3.4 file as a guest READ: Guest process, OR completely decoupled!

So what does this mean? Pay close attention to the router config. If you are referencing components in your router config section 

 "components": [
           
// WAMP app components running side-by-side with this router
         
],

or components in your container config section

{
         "type": "container",
         "options": {
            "pythonpath": [".."]
         },
         "components": [
            {
               "type": "class",
               "classname": "hello.hello.AppSession",
               "realm": "realm1",
               "transport": {
                  "type": "websocket",
                  "endpoint": {
                     "type": "tcp",
                     "host": "127.0.0.1",
                     "port": 8080
                  },
                  "url": "ws://127.0.0.1:8080/ws"
               }
            }
         ]
      }

and those components are python 3.4 files they will NOT run (take all this with a grain of salt as it is just my understanding, posting here to help others and save them time). See the first line in the docs which was a dead giveaway for me: 

Python Components are worker processes spawned by Crossbar.io which directly host application classes written in Python deriving from autobahn.twisted.wamp.ApplicationSession

Twisted as of right now is not fully ported to python 3 so it's not going to run your python 3!

Your worker process, again as of current, is running in python 2, and will therefore NOT understand python 3 syntax, you will get a traceback when trying to start crossbar.

Adding to what I said about decoupling, or the other option that Tobias mentioned as a guest process (not sure if there is any benefit to either option, haven't tried guest yet), think of your python 3 file running as a "client" to the router READ: "router black box appliance". You should not have any references to your application logic file in your config to completely decouple it! When running your python 3 file it should join the realm in the router DYNAMICALLY unless you are running it as a guest:  http://crossbar.io/docs/Guest-Configuration/

So how did I get this running? First, remove any components or container config if you don't need them. Here is my config for example:

{
"controller": {
},
"workers": [
{
"type": "router",
"options": {
            "title": "WAMP Router"
         },
"realms": [
{
"name": "realm1",
"roles": [
{
"name": "anonymous",
"permissions": [
{
"uri": "*",
"publish": true,
"subscribe": true,
"call": true,
"register": true
}
]
}
]
}
],
"transports": [
{
"type": "web",
"endpoint": {
"type": "tcp",
"port": 8080
},
"paths": {
"/": {
"type": "static",
                     "directory": "<Name of your front end project directory if you want to debug at the same time!>"
},
"ws": {
"type": "websocket"
}
}
}
]
}
]
}

When you run your python 3 add an application runner from autobahn (maybe there is a better way?) and it will JOIN the realm of your WAMP router, therefore you could run your python on one server and your WAMP router on a completely different server! Decoupled remember!

if __name__ == '__main__':
runner = ApplicationRunner(url="ws://localhost:8080/ws", realm="realm1")
runner.run(AppSession)

Just thought I would post for others, guess some of this might be obvious, but thought I would share!

Thanks again Tavendo for some awesome stuff!

Dave
Reply all
Reply to author
Forward
0 new messages