Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web2Py support: ImportError('No module named react.render',) #70

Closed
Anima-t3d opened this issue Oct 14, 2016 · 11 comments
Closed

Web2Py support: ImportError('No module named react.render',) #70

Anima-t3d opened this issue Oct 14, 2016 · 11 comments

Comments

@Anima-t3d
Copy link

Does this work with Web2Py? I am relatively new to python and Web2Py. I want to implement react server side rendering in an existing Web2Py application.

I tried the following on a local instance:
pip install react and created modules/react_test.py:

from react.render import render_component

def test_render(url):
    return render_component('../react/Url.jsx', {'arg': url})

It will give an error ImportError('No module named react.render',).
Did I do something wrong or is it because I am trying to use python-react with Web2Py?

Thanks in advance.

@markfinger
Copy link
Owner

markfinger commented Oct 14, 2016

Hi,

There's no obvious reason why Web2Py would be the problem. My guess would be PYTHONPATH issues in your setup.

Can you provide more detail, e.g.:

  • What OS and version are you on? What python version (python --version)?
  • What command are you using to start the python process?
  • If you start a python interpreter with just python, then run import react. What happens? If it works, can you try react.__file__?

For context, my suspicion here is that either your python setup is broken (and the interpreter can't find the libraries), or you may need to run a different command to start the process.

@Anima-t3d
Copy link
Author

What OS and version are you on? What python version (python --version)?
I am running a local instance of the web2py app on mac OS X El Capitan 10.11.6. With Python 2.7.10

What command are you using to start the python process?
I use the bundled web2py app to start the server and modify it through the browser.

If you start a python interpreter with just python, then run import react. What happens? If it works, can you try react.file?

$ python
[TEXT HERE]
>>> import react
>>> react.__file__
'/Library/Python/2.7/site-packages/react/__init__.pyc'

It seems that when I run the app it doesn't get access to the react file. Could it be solved by copying or symlinking to this file inside the/Users/XXX/Documents/web2py/web2py.app/Contents/Resources/applications/react_test/modules or like you mentioned do something with the PYTHONPATH

I am first trying it out on a local instance, but once I get it working it will be deployed on a CentOS server.

@markfinger
Copy link
Owner

Adding '/Library/Python/2.7/site-packages' to your PYTHONPATH may help. Manipulating the PYTHONPATH during init is a common practice to target source roots, but targeting an interpreter's site-packages is a bit odd.

I haven't looked at the zip you linked, but my guess is that the web2py app is using its own python interpreter, not your system or venv binary. If you check the web2py docs, they might have instructions for how to install libraries within their system.

@Anima-t3d
Copy link
Author

Anima-t3d commented Oct 16, 2016

Thanks for the reply, based on your input I found the Third party modules chapter in the documentation:

web2py is written in Python, so it can import and use any Python module, including third party modules. It just needs to be able to find them. As with any Python application, modules can be installed in the official Python "site-packages" directory, and they can then be imported from anywhere inside your code.

Modules in the "site-packages" directory are, as the name suggests, site-level packages. Applications requiring site-packages are not portable unless these modules are installed separately. The advantage of having modules in "site-packages" is that multiple applications can share them.

In order for the error to disappear I had to copy more than just the react folder in /Library/Python/2.7/site-packages/ (for now I copied all folders there). I will close this once I have it fully working (I still have some component not found error, but this is probably just my mistake)

@markfinger
Copy link
Owner

No worries, best of luck with it.

I think there's a way for pip to install locally, something like pip install react --target /path/to/dir which should create a directory called react that contains the library). Might be of use to workaround web2py's quirks as you could now use relative imports, eg: from .react.render import ....

@Anima-t3d
Copy link
Author

Anima-t3d commented Oct 17, 2016

The local install into the modules folder worked. However I have this <class 'react.exceptions.ComponentSourceFileNotFound'> thrown by the render_component function

If I try to do the Web2Py way of the basic example:

...
rendered = render_component(
        os.path.join(os.getcwd(), 'static', 'js', 'CommentBox.jsx'),
        {
            'comments': comments,
            'url': '/comment/',
        },
        to_static_markup=True,
)
...
...
rendered = render_component(
        # '../static/CommentBox.jsx',
        # OR
        URL('static','CommentBox.jsx'),
        {
            'comments': comments,
            'url': '/comment/',
        },
        to_static_markup=True,
)
...

I get the above error. So it seems that in Web2Py my urls are not pointing to the file correctly. I tried relative and absolute both in different and same folder. In the end I got it working by using:

rendered = render_component(os.path.dirname(os.path.abspath(__file__)) + '/CommentBox.jsx', {'comments': comments, 'url': '/comment/'})

Any ideas on where I can look to find the issue?

Also using this way around for now I managed to setup the render server. But eventhough I use the basic example templates I get the following error: ReactRenderingError: Message: /Users/XXX/web2py/web2py.app/Contents/Resources/applications/my_test/modules/react_templates/CommentBox.jsx: Unexpected token (8:3)

Stack trace: SyntaxError: /Users/XXX/web2py/web2py.app/Contents/Resources/applications/my_test/modules/react_templates/CommentBox.jsx: Unexpected token (8:3)
�[0m �[90m  6 | �[39m    render() {
 �[90m  7 | �[39m       �[36mreturn�[39m (
�[31m�[1m>�[22m�[39m�[90m  8 | �[39m          �[33m<�[39m�[33mdiv�[39m�[33m>�[39m
 �[90m    | �[39m          �[31m�[1m^�[22m�[39m
 �[90m  9 | �[39m              �[33m<�[39m�[33mCommentList�[39m comments�[33m=�[39m{�[36mthis�[39m�[33m.�[39mprops�[33m.�[39mcomments} �[33m/�[39m�[33m>�[39m
 �[90m 10 | �[39m              �[33m<�[39m�[33mCommentForm�[39m url�[33m=�[39m{�[36mthis�[39m�[33m.�[39mprops�[33m.�[39murl} �[33m/�[39m�[33m>�[39m
 �[90m 11 | �[39m          �[33m<�[39m�[33m/�[39m�[33mdiv�[39m�[33m>�[39m�[0m
    at Parser.pp.raise

@markfinger
Copy link
Owner

The path provided to the renderer needs to be an absolute path to the file, so your last example should work fine.

I usually have something like

ROOT = os.path.dirname(__file__)

# ...

rendered = render_component(
    os.path.join(ROOT, 'path', 'to', 'CommentBox.jsx'), 
    {'comments': comments, 'url': '/comment/'}
)

@Anima-t3d
Copy link
Author

I see, for it to work properly I need to place the templates in a sub folder. I was thinking to use it as:

|-views
|-modules (which would point to the jsx which would be inside the views directory)

Any idea what is wrong with the jsx file? Is it my babel not configured correctly or is something up with the file? As far as I can tell the syntax is correct?

@markfinger
Copy link
Owner

Hard to tell with the encoding artifacts, but I'd guess that it hasn't installed the jsx plugin. You'll need to make sure that the .babelrc file is in the same (or maybe higher, not sure though) dir as the render server's script.

@Anima-t3d
Copy link
Author

Anima-t3d commented Oct 18, 2016

Thanks. I finally managed it to show up. It was indeed the fact that .babelrc was not in the bloodline directory that the template would look for. As stated in the babel docs:

Babel will look for a .babelrc in the current directory of the file being transpiled. If one does not exist, it will travel up the directory tree until it finds either a .babelrc, or a package.json with a "babel": {} hash within.

I updated this answer with the final setup so other people using web2py would have a better insight in how to get react working.

So what I had to do to get it to work with Web2Py:

  • pip install react --target /path/to/dir which should create a directory called react that contains the library. I pointed the path to the application modules folder: /Users/AAA/web2py/web2py.app/Contents/Resources/applications/BBB/modules/ Where AAA is the user and BBB is the application name.
  • create the node install (package.json, .babelrc, ...) inside the same modules/ folder. I didn't use the static and templates folders. I did create a templates folder which contains my jsx templates and possibly css. Make sure that your templates are a descendant or the same folder as the .babelrc.
  • create a python file inside the modules folder e.g. my_react.py which contains the functions for rendering your components. NOTE: Use XML() to enable raw HTML to be output to the client.
from react.render import render_component
from gluon import *
import os

def test_render(comments, url):
    rendered = render_component(os.path.dirname(os.path.abspath(__file__)) + '/node_render_server/templates/CommentBox.jsx', {'comments': comments,'url': url})
    return XML(rendered)
  • inside the controller e.g. default.py:
from my_react import test_render
def index():
    react_test = test_render([],'https://github.com')

    return dict(message=T('Welcome to web2py!'),my_react_test=react_test)
  • inside the view e.g. defaul/index.html:
...
<div id="react-test">{{=my_react_test}}</div>
...
<script>
   var comments = [];
   var url = 'http://www.github.com/some/other/url';
     ReactDOM.render(
      React.createElement(/*App.components.CommentBox or url?*/, {'comments': comments,'url': url}),
      document.getElementById('react-test')
    );
    </script>

NOTE: I am not sure about the absolute path to the component, but I use webpack and make sure of library to expose the root components to the client. This is the relevant part of the webpack.config.js file:

...
output: {
        filename: 'dist/scripts/[name].js',
        library: ['App', 'components'] //This will create a window.App.components object on the client.
    },
...

Overview of folder setup:

controllers/
modules/
|- node_render_server/
    |- node_modules (installed via npm install)
    |- templates (containing all the folders with css and jsx templates
    - .babelrc
    - package.json
    - render_server.js
|- optional_django/  (installed via pip install react)
|- react/  (installed via pip install react)
|- requests/  (installed via pip install react)
- my_react.py (the actual serverside rendering functions for my app)
views/

markfinger added a commit that referenced this issue Oct 19, 2016
@markfinger
Copy link
Owner

Thanks for the write-up, @Anima-t3d.

I've added a FAQ section to the docs and linked to your above comment.

https://github.com/markfinger/python-react/blob/master/README.md#can-python-react-integrate-with-web2py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants