Forum Archive

Using pelican to build a website in Pythonista 3

victordomingos

I am experimenting with Pelican, a static website generator and managed to pip install all the requirements using StaSh. I was able to type pelican content/ -s pelicanconf.pyin StaSh and the html files were correctly generated as expected. However, when I started editing the settings file (pelicanconf.py) and added some Python 3.6 specific code, I noticed that there was an error.

I was able to isolate the following snippet that triggers the error:

from glob import glob
from pathlib import Path

DISPLAY_DATE_ON_ARTICLE_LIST = False
SITEIMAGE_FOLDER = 'images/avatars'  # Images to be used randomly in the header
SITEIMAGES = [ Path(*Path(img).parts[1:])
               for img in glob(f'{PATH}/{SITEIMAGE_FOLDER}/*.png')]

I get this error message:

CRITICAL: SyntaxError: invalid syntax (pelicanconf.py, line 49)

Line 49 correspond the to list comprehension as reproduced above. Digging further, it seems that StaSh is running pelican in Python 2.7 mode. For instance, it seems that it can't import the pathlib module. Is there any way to force it to use Python 3?

JonB

In short, stash runs using 2.7. there was an experimental python3 command, but I forget if that is in the master repo.

You ought to be able to open the main script in your library, then long press play in order to input arguments, then you can run it in python 3

JonB

See https://forum.omz-software.com/topic/3735/running-python-3-scripts-in-stash/2

If you want the experimental python3 command, check out the discussion and link to @bennr01 s repo.

victordomingos

So... I changed my pelican settings file to catch the an exception as needed when running under Python 2. However, I had added some Python 3 code that I would like to run in the pelican settings, so I am missing some functionality. :-( I wouldn't like to have to learn Python 2 just to rewrite these 5 lines of code.

Meanwhile, I tried to make a separate Python 3 script to import pelican and use it to build the html files that way, as suggested here. However, if I use Python 3 to run this script (which works just fine on my Mac), I get NameError: name "StandardError" is not defined. Once again, running in Python 2, it goes fine.

Probably the pip install pelican done in StaSH has installed some Python 2 specific packages that is forcing Pythonista to use legacy Python...

JonB

print the full stacktrace, and post it here, or at least look at it. often in this sort of situation you will find the offending code is from some package you didnt intend to install. in that case, delete the folder from site-packages, then force quit and try again

ccc

On this particular exception, StandardError was removed in Python 3 and when porting, you usually replace it with Exception.

victordomingos

So, this is my current code:

import os

from pelican import Pelican
from pelican.settings import read_settings


abspath = os.path.abspath(__file__)
dname = os.path.dirname(abspath)
os.chdir(os.path.expanduser('~/Documents/pelican-stuff/The-No-Title-Tech-Blo/src'))

settings_filepath = os.path.expanduser(dname+'/The-No-Title-Tech-Blo/src/pelicanconf.py')
settings = read_settings(settings_filepath)
pelican = Pelican(settings)
pelican.run()

Running this on Python 3, I get this:

Traceback (most recent call last):
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/pelican-stuff/make_html.py", line 4, in <module>
    from pelican import Pelican
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/pelican/__init__.py", line 20, in <module>
    from pelican.generators import (ArticlesGenerator, PagesGenerator,
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/pelican/generators.py", line 22, in <module>
    from pelican.readers import Readers
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/pelican/readers.py", line 10, in <module>
    import docutils
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/docutils/__init__.py", line 112, in <module>
    class ApplicationError(StandardError):
NameError: name 'StandardError' is not defined

It seems clear that there are modules here bring run in Python 2. However, in my Mac, in a Python 3 virtual environment, ir runs fine...

JonB

remove the docutils folder, from site-packages.

victordomingos

I just tried that. Now it doesn’t run in either Python version. In Python 2, I get an import error for the missing package. In Python 3, I get this:

Traceback (most recent call last):
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/pelican-stuff/make_html.py", line 4, in <module>
    from pelican import Pelican
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/pelican/__init__.py", line 20, in <module>
    from pelican.generators import (ArticlesGenerator, PagesGenerator,
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/pelican/generators.py", line 22, in <module>
    from pelican.readers import Readers
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/pelican/readers.py", line 10, in <module>
    import docutils
ModuleNotFoundError: No module named 'docutils'
victordomingos

Correction: in Python 2, I get this error:

Traceback (most recent call last):
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/pelican-stuff/make_html.py", line 4, in <module>
    from pelican import Pelican
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/pelican/__init__.py", line 19, in <module>
    from pelican import signals
ImportError: cannot import name signals

JonB

Just to be clear, are you trying to run from py2, or 3, or you don't care as long as it runs?
For docutils, looks like you could try the experimental pip3 command (I forget whose fork but searching github for stash and pip3 may work) or else pip install docutils, then manually convert to py3 via wrench.

What are the 5 lines that need py3?
Maybe it would be easier to convert those.

victordomingos

I prefer Python 3 because it’s the one I understand better and know how to debug and extend, and because I believe it will tend to be better supported in the near future.

But for now it would in fact be very useful to update my current code to be compatible with either version, returning the same html. I am trying to keep my workflow Python 3 and Pythonista 3 compatible, so that I can use whatever machine I have to hand.

At the moment, I think the only piece of code that is getting in the way are the following lines, where I wanted to get a random image for each generated html page:

from pathlib import Path

SITEIMAGES = [ Path(*Path(img).parts[1:])
               for img in glob('{}/{}/*.png'.format(PATH,SITEIMAGE_FOLDER))]
JonB

ok, the simplest might just be to reinstall docutils (sorry bout that), then pip install pathlib2. then just use a
```
try:
from pathlib import Path
except ImportError:
from pathlib2 import Path

pathlib2 appears to be a complete backport of pathlib

victordomingos

Thanks. I have just tried that. Now, when running pelican content/ -s pelicanconf.py in StaSh, I get this:

CRITICAL: ImportError: No module named scandir

Now, that’s weird. It should be available in both Python2.7 and Python 3.6, right? When trying to import it in the console, I get an import error in both versions...

victordomingos

Just did a pip install scandir And apparently it’s working now, at least in StaSh. Thank you very much!

However, using the custom build script I had written I get an error on aone module used by the pelican-minify plug-in. Here’s what I get by running my build script in Python 2:

No handlers could be found for logger "pelican.settings"
Traceback (most recent call last):
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/pelican-stuff/make_html.py", line 15, in <module>
    pelican.run()
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/pelican/__init__.py", line 181, in run
    signals.finalized.send(self)
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/blinker/base.py", line 267, in send
    for receiver in self.receivers_for(sender)]
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/minify.py", line 32, in minify_html
    Parallel(n_jobs=-1)(delayed(create_minified_file)(filepath, options) for filepath in files_to_minify)
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/joblib/parallel.py", line 772, in __call__
    n_jobs = self._initialize_pool()
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/joblib/parallel.py", line 542, in _initialize_pool
    self._pool = MemmapingPool(n_jobs, **poolargs)
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/joblib/pool.py", line 580, in __init__
    super(MemmapingPool, self).__init__(**poolargs)
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/joblib/pool.py", line 419, in __init__
    super(PicklingPool, self).__init__(**poolargs)
  File "/var/containers/Bundle/Application/46E67BC7-8A23-4C29-9CBA-6E4CC2B2BB96/Pythonista3.app/Frameworks/Py2Kit.framework/pylib/multiprocessing/pool.py", line 160, in __init__
    self._repopulate_pool()
  File "/var/containers/Bundle/Application/46E67BC7-8A23-4C29-9CBA-6E4CC2B2BB96/Pythonista3.app/Frameworks/Py2Kit.framework/pylib/multiprocessing/pool.py", line 224, in _repopulate_pool
    w.start()
  File "/var/containers/Bundle/Application/46E67BC7-8A23-4C29-9CBA-6E4CC2B2BB96/Pythonista3.app/Frameworks/Py2Kit.framework/pylib/multiprocessing/process.py", line 131, in start
    self._popen = Popen(self)
  File "/var/containers/Bundle/Application/46E67BC7-8A23-4C29-9CBA-6E4CC2B2BB96/Pythonista3.app/Frameworks/Py2Kit.framework/pylib/multiprocessing/forking.py", line 122, in __init__
    self.pid = os.fork()
OSError: [Errno 1] Operation not permitted

It’s getting more complex...

victordomingos

While I don’t find a better solution, I am now detecting the current platform and just adding the minification plugin on desktop... but I really would like to get it working on both platforms.

JonB

no, Popen, fork, and the like are unavailable on iOS due to restrictions on creating subprocesses.

victordomingos

Turns out that the pelican-minify plug-in was using joblib to parallelize it’s execution. Reading through the code of them, I discovered I just needed to change a single character in site-packages/minify.py to make it work properly on Pythonista. By specifying n_jobs=1 in the Parallel class instantiation, instead of n_jobs=-1, it works fine:

    Parallel(n_jobs=1)(delayed(create_minified_file)(filepath, options) for filepath in files_to_minify)
victordomingos

I have been going on with this website project, and now I am experimenting with Pelican’s translation feature. I created some pages and articles with the required settings (same slug and different Lang) and added some settings to pelicanconf.py with the translation paths. Once again, it works on desktop (Mac/Python3.6), but not on Pythonista, where I get this:

$ pelican --debug
stash: <class 'locale.Error'>: unsupported locale setting

Traceback (most recent call last):
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/stash/system/shruntime.py", line 498, in exec_py_file
    exec code in namespace, namespace
  File "../../../stash_extensions/bin/pelican.py", line 5, in <module>
    main()
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/pelican/__init__.py", line 487, in main
    pelican.run()
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/pelican/__init__.py", line 171, in run
    p.generate_context()
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/pelican/generators.py", line 717, in generate_context
    context_sender=self)
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/pelican/readers.py", line 572, in read_file
    context=context)
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/pelican/contents.py", line 389, in __init__
    super(Static, self).__init__(*args, **kwargs)
  File "/private/var/mobile/Containers/Shared/AppGroup/F3C0E711-6D38-4FDF-81F2-DC3B97E4E9F1/Pythonista3/Documents/site-packages/pelican/contents.py", line 123, in __init__
    locale.setlocale(locale.LC_ALL, locale_string)
  File "/var/containers/Bundle/Application/46E67BC7-8A23-4C29-9CBA-6E4CC2B2BB96/Pythonista3.app/Frameworks/Py2Kit.framework/pylib/locale.py", line 583, in setlocale
    return _setlocale(category, locale)
Error: unsupported locale setting
>/var/containers/Bundle/Application/46E67BC7-8A23-4C29-9CBA-6E4CC2B2BB96/Pythonista3.app/Frameworks/Py2Kit.framework/pylib/locale.py(583)setlocale()
-> return _setlocale(category, locale)

Any hope to get this working? Any tips?

ccc

https://github.com/omz/Pythonista-Issues/search?q=locale&type=Issues

victordomingos

Well, apparently it works if I remove the lines that define different date formats for each language:

DATE_FORMATS = {
    'en': ('en_GB', '%d %B %Y'),
    'pt': ('pt_PT', '%d de %B de %Y'),
}

The rest of the stuff seems to work, so I will give it a shot without the date localization.