I started following a super-basic tutorial on Python as I’d learned the basics over the years and wanted to learn again from scratch.
The very first thing they do is:
>> import requests
>> import requests Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: No module named requests
So now I’m spending half an hour trying to debug the most basic thing in a Python tutorial. This is clearly a sign of things to come.
Various StackOverflow answers describing complicated solutions that did not help:
Turns out the solution was to do:
pip install requests `
Fortunately, I had
pip installed. But basically a complete beginner would have that as an additional hurdle to overcome.
>>> import sys >>> sys.path ['', 'etc....','etc...', '/usr/local/lib/python2.7/site-packages']
''=> current working directory
then searches through directories.
/usr/local/lib/python2.7/site-packages => third party packages
Note: on Debian this is called
Following a script that mentions `os.environ` I get:
`NameError: global name ‘os’ is not defined`
Turns out I need to import
os. Python folks – can’t this be done automatically? It’s not hard. Just see a variable that matches a package you know and import it. DONE. Kind of like the Mac’s AutoSave. Let’s get out of the ’80s here…
Again, following that script I copy and paste part into a REPL to try it out. As the indentation is different I get:
`IndentationError: unexpected indent`
Groan. So, I have to go through the script manually adding indents. Again, let’s get rid of indent restrictions. Stupid.
Gibberish logs and debug output.
A method I had copied was clearly wrong. When I attempted to use it from the REPL with `ec2 = get_client(“ec2”)` I got:
>> ec2 = get_client("ec2") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in get_client File "/Users/snowcrash/.virtualenvs/my-project/lib/python2.7/site-packages/boto3/session.py", line 80, in __init__ self._setup_loader() File "/Users/snowcrash/.virtualenvs/my-project/lib/python2.7/site-packages/boto3/session.py", line 120, in _setup_loader self._loader = self._session.get_component('data_loader') File "/Users/snowcrash/.virtualenvs/my-project/lib/python2.7/site-packages/botocore/session.py", line 729, in get_component return self._components.get_component(name) File "/Users/snowcrash/.virtualenvs/my-project/lib/python2.7/site-packages/botocore/session.py", line 946, in get_component self._components[name] = factory() File "/Users/snowcrash/.virtualenvs/my-project/lib/python2.7/site-packages/botocore/session.py", line 186, in <lambda> lambda: create_loader(self.get_config_variable('data_path'))) File "/Users/snowcrash/.virtualenvs/my-project/lib/python2.7/site-packages/botocore/session.py", line 281, in get_config_variable elif self._found_in_config_file(methods, var_config): File "/Users/snowcrash/.virtualenvs/my-project/lib/python2.7/site-packages/botocore/session.py", line 308, in _found_in_config_file return var_config in self.get_scoped_config() File "/Users/snowcrash/.virtualenvs/my-project/lib/python2.7/site-packages/botocore/session.py", line 385, in get_scoped_config raise ProfileNotFound(profile=profile_name) botocore.exceptions.ProfileNotFound: The config profile (sb) could not be found
What a pile of gibberish. To be clear –
21 lines and
1629 characters of gibberish.
Why not print it out in Assembly just to make it less clear?! Has anyone made any effort whatsoever on making this more user-friendly?
or a line like:
testing = os.environ['testing']
Traceback (most recent call last): File "./mock.py", line 28, in <module> testing = os.environ['testing'] File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/os.py", line 669, in __getitem__ raise KeyError(key) from None KeyError: 'testing'
Why not just output:
testing = os.environ['testing'] # Error generated. No such key "testing"
I’ve got an object that’s been returned using a pretty standard library. i.e.
client = boto3.client('ec2')
There is no output when I run it from the REPL. Sounds OK.
Let’s inspect this object. Looking for
Python has a strong set of introspection features. OK, let’s try
>>> client.type() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Users/snowcrash/.virtualenvs/my-project/lib/python2.7/site-packages/botocore/client.py", line 555, in __getattr__ self.__class__.__name__, item) AttributeError: 'EC2' object has no attribute 'type'
Jeez! Another 6 lines of gibberish.
client.getattr()? Surely that’s got to return something?!
>>> support.getattr() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Users/snowcrash/.virtualenvs/limit-monitor/lib/python2.7/site-packages/botocore/client.py", line 555, in __getattr__ self.__class__.__name__, item) AttributeError: 'EC2' object has no attribute 'getattr'
Why can’t they just return messages like:
AttributeError: 'EC2' object has no attribute 'getattr' and get it over with. Then you could have some debug parameter to find out more if any of the additional text above is actually useful.
At least the very user-friendly
underscore underscore dict underscore underscore method (i.e.
__dict__) helps figure out what’s going on behind the scenes. That was an easy one to figure out without digging through Stackoverflow. Not.
Let’s follow the 4 simple steps here:
1. Download or clone the repository.
2. Open terminal and point to root of repository. Type:
pip install -r requirements.txt
I get (in red):
awscli 1.15.53 has requirement botocore==1.10.52, but you’ll have botocore 1.12.23 which is incompatible.
I’ve no idea now whether I need to upgrade awscli, downgrade botocore. Or even why I’m getting this message.
It also fails with:
Could not install packages due to an EnvironmentError: [Errno 13] Permission denied: ‘/usr/local/man’
Consider using the `–user` option or check the permissions.
Why on earth didn’t the maintainers bother to mention that you might need to use
--user in the install instructions.
pip install --user -r requirements.txt
and no longer see the red fails. I’ve no idea why the awscli, botocore errors have disappeared.
3. Run server with:
python3 application.py. Alternatively:
Great. 2 options to fail.
Let’s try the second:
and the nice simple error message:
Traceback (most recent call last): File "./manage.py", line 11, in <module> from elastichq import create_app File "/Users/snowcrash/Code/Elasticsearch/elasticsearch-HQ/elastichq/__init__.py", line 5, in <module> from elastichq.api import api_blueprint, endpoints, public_blueprint, ws_blueprint File "/Users/snowcrash/Code/Elasticsearch/elasticsearch-HQ/elastichq/api/endpoints.py", line 4, in <module> from . import clusters File "/Users/snowcrash/Code/Elasticsearch/elasticsearch-HQ/elastichq/api/clusters.py", line 11, in <module> from elastichq.model import ClusterDTO File "/Users/snowcrash/Code/Elasticsearch/elasticsearch-HQ/elastichq/model/__init__.py", line 3, in <module> from elastichq.model.ClusterModel import * File "/Users/snowcrash/Code/Elasticsearch/elasticsearch-HQ/elastichq/model/ClusterModel.py", line 7, in <module> from ..globals import db, ma File "/Users/snowcrash/Code/Elasticsearch/elasticsearch-HQ/elastichq/globals.py", line 12, in <module> from .config import settings File "/Users/snowcrash/Code/Elasticsearch/elasticsearch-HQ/elastichq/config/settings.py", line 2, in <module> from functools import lru_cache ImportError: cannot import name lru_cache
I don’t understand why they couldn’t make this less simple to understand. Perhaps another 1500 lines of gibberish to reduce legibility would have helped. E.g. they could have thrown in some random characters to help confuse the end user.
Given that the instructions say:
and I find this issue buried on github:
which helpfully suggests ignoring the official (faulty) install instructions and using (the also incorrect):
pip3 install -r requirements.txt
The correct install instructions are:
pip3 install --user -r requirements.txt
Handily there’s also no mention that:
will take 10 seconds before it starts generating output and so appearing it’s not working.
4. Access HQ with:
Did I say I hate Python?
Why on earth use 4 spaces?!
Let me rephrase it. If you use one less or more of an invisible character your code will break. Or if you swap it out for another invisible character that looks exactly the same (i.e. the tab) it will also break.
Brilliant design idea.
Let’s find something analogous in the real world.
If you reach for the right glass you can have a drink of water.
But if you reach for the wrong glass (that looks exactly the same) it breaks.
I refuse to believe strong typing is the future of coding. All the talk about catching bugs earlier is guff. Adding pre-compilation gates just slows down the coding process. The compiler and interpreter should be the ones doing the heavy lifting – not the programmer.
print(“URL: + some_url)
None then you get:
Traceback (most recent call last): File "my-script.py", line 451, in <module> lambda_handler(None, None) File "my-script.py", line 442, in lambda_handler print("Some URL: " + some_url) TypeError: cannot concatenate 'str' and 'NoneType' objects
I’m fed up of junk like this:
pyenv install 2.7.14 pyenv install 2.7.14 python-build: use openssl from homebrew python-build: use readline from homebrew Downloading Python-2.7.14.tar.xz... -> https://www.python.org/ftp/python/2.7.14/Python-2.7.14.tar.xz Installing Python-2.7.14... python-build: use readline from homebrew ERROR: The Python zlib extension was not compiled. Missing the zlib? Please consult to the Wiki page to fix the problem. https://github.com/pyenv/pyenv/wiki/Common-build-problems BUILD FAILED (OS X 10.13.6 using python-build 20180424) Inspect or clean up the working tree at /var/folders/q_/1rht_37j3vx9mwvq4wj48gd00000gn/T/python-build.20190115160947.69139 Results logged to /var/folders/q_/1rht_37j3vx9mwvq4wj48gd00000gn/T/python-build.20190115160947.69139.log Last 10 log lines: rm -f /Users/snowcrash/.pyenv/versions/2.7.14/share/man/man1/python.1 (cd /Users/snowcrash/.pyenv/versions/2.7.14/share/man/man1; ln -s python2.1 python.1) if test "xno" != "xno" ; then \ case no in \ upgrade) ensurepip="--upgrade" ;; \ install|*) ensurepip="" ;; \ esac; \ ./python.exe -E -m ensurepip \ $ensurepip --root=/ ; \ fi