Wednesday, 24 June 2020

Go Language: Errors

errors (standard package)

errors - The Go Programming Language

Go by Example: Errors

If function returns type error and we want to return error object with custom message:

return errors.New("Argument is nil: file")

To create an error with formatted message use fmt.Errorf:

err := fmt.Errorf("user %q (id %d) not found", name, id)

Example when type assertion is used to convert from error to some specific error type:
What is err.(*os.PathError) in Go?


fi, err := file.Stat()
if err != nil {
return 0, fmt.Errorf("Failed to access file %s", (err.(*os.PathError)).Path)
} package

Go default package "errors" does not support capturing stack trace info at the moment when error is created. When the error is created somewhere deep on the stack, it can be returned from the chain of function calls to the main error handler where the only information which can be extracted is error text message, without its context. When such message appears in the log, it is difficult to find out where it came from, from which function. 

Example of the Go app log snippet:

Error: Bad status: 404 Not Found
Terminating with error: 1
Process exited with code 1

All we know from error message "Bad status: 404 Not Found" that some HTTP response returned 404 but we don't know which one and in which part of the code.

To capture stack trace at the moment when error gets created and later be able to print it out, we can use package.

errors package ·

This article explains best practices and how you need to change our code in order to use this package efficiently:

Here are the changes in the code base that need to be done when switching from errors to package:

import (

will be replaced with 

import (
) go.mod will contain something like: v0.8.1

Error creation errors.New("...") will remain the same but 

fmt.Errorf("%s value is empty string", key)

will be replaced with 

errors.Errorf("%s value is empty string", key)

Instead of passing the original error and message:

if err :=, df); err != nil {
return err

...we can add a context info by adding a contextual error message (and still keeping the original one):

if err :=, df); err != nil {
return errors.Wrapf(err, "Fetching resource with ID = %s failed for entity with ID = %s", br.ResID, br.ID)

Instead of just printing the error message:

func LogAndExit(err error, code int) {
if err != nil {
log.Printf("Error: %s\nTerminating with error: %d", err.Error(), code)

we can now print message AND stack trace:
func LogAndExit(err error, code int) {
if err != nil {
log.Printf("Error: %+v\nTerminating with error: %d", err, code)

Monday, 15 June 2020

Go Linters in VS Code

If you are using VS Code for Go development, you have probably installed Go for Visual Studio Code extension. It allows configuring a linter of choice by going to settings (CTRL+,), typing go.lintTool and selecting a desired linter:


golint is a default linter. To run it across all files in the project, execute this from the project's root directory:

$ golint ./...

For each issue detected, golint's output contains source code file name, line and column numbers and the linter message.

When I run golint on one of my projects that I used for benchmark, it found 9 issues.


Staticcheck is an advanced linter. VS Code Go extension can install it automatically if we select staticcheck as go.lintTool value and opt to install it in the popup notification that will apper upon selection:

Installation log can be verified in the output window:

To run it across all files in the project, execute this from the project's root directory:

$ staticcheck ./...

Similar to golinit, for each issue detected the output contains source code file name, line and column numbers and the linter message.

When I run Staticcheck on my benchmark project, it found 57 issues.

Static check's repo is at and shows active development. At the time of writing has 72 watchers, 3.2k stars and 199 forks.


revive is another Go linting tool which is listed among other linters in the default linters list in go.lintTools:

Installation output log:

To run it across all files in the project, execute this from the project's root directory:

$ revive ./...

Similar to golinit, for each issue detected the output contains source code file name, line and column numbers and the linter message.

When I run revive on my benchmark project, it found 11 issues.

Revive repo is at and shows active development. At the time of writing has 29 watchers, 2.3k stars and 107 forks.


golangci-lint is a Go linters aggregator which currently includes 48 linters. Some are enabled by default (e.g. staticcheck) and some are not. There is no need to install all linters, this tool does it all, just select golangci-lint as go.lintTool value:

Installation log output:

To run it across all files in the project, execute this from the project's root directory:

$ golangci-lint run

The output is more verbose, in addition to source code file name, line and column numbers, for each issue detected golangci-lint also prints that code line with a caret that shows exact character in line for which the linter message is issued. All messages are coloured.

When I run golangci-lint on my benchmark project, it found the same number of issues as Staticcheck. When compared the output, I found that issues reported were mostly the same as those from Staticcheck but were reported as the catch of some other enabled linters (e.g. gosimple, govet, deadcheck, unused etc...).

golangci-lint repo is at and shows active development. At the time of writing has 77 watchers, 5.5k stars and 495 forks.


Given the more complete and verbose output and larger community around the project, I would opt for using golangci-lint as the preferred Go linting tool.

Wednesday, 20 May 2020

Generator Functions in various Programming Languages

A generator is a special type of function which can pause its execution, yield result back to the caller and resume later, at caller’s convenience. And this happens as long as the generator has something to return, some value to yield back. Caller is usually iterating over yielded values in a loop, it takes a new value as soon as generator yields it. The main benefit of generators is that not all elements in a  sequence have to be kept in memory at the same time but only a single one. 

Generators in Python

Sunday, 26 April 2020

How to install Scrapy on Ubuntu

$ which python3

$ python3 --version
Python 3.6.9

$ virtualenv --python=python3.6 venv
Running virtualenv with interpreter /usr/bin/python3.6
Already using interpreter /usr/bin/python3.6
Using base prefix '/usr'
New python executable in /home/bojan/dev/github/scrapy-demo/venv/bin/python3.6
Also creating executable in /home/bojan/dev/github/scrapy-demo/venv/bin/python
Installing setuptools, pip, wheel...

$ source venv/bin/activate

(venv) $ pip install scrapy
Collecting scrapy
  Downloading Scrapy-2.1.0-py2.py3-none-any.whl (239 kB)
Collecting service-identity>=16.0.0
  Downloading service_identity-18.1.0-py2.py3-none-any.whl (11 kB)
Collecting cryptography>=2.0
  Downloading cryptography-2.9.2-cp35-abi3-manylinux2010_x86_64.whl (2.7 MB)
Collecting cssselect>=0.9.1
  Downloading cssselect-1.1.0-py2.py3-none-any.whl (16 kB)
Collecting w3lib>=1.17.0
  Downloading w3lib-1.21.0-py2.py3-none-any.whl (20 kB)
Collecting pyOpenSSL>=16.2.0
  Downloading pyOpenSSL-19.1.0-py2.py3-none-any.whl (53 kB)
Collecting zope.interface>=4.1.3
  Downloading zope.interface-5.1.0-cp36-cp36m-manylinux2010_x86_64.whl (234 kB)
Collecting protego>=0.1.15
  Downloading Protego-0.1.16.tar.gz (3.2 MB)
Collecting parsel>=1.5.0
  Downloading parsel-1.5.2-py2.py3-none-any.whl (12 kB)
Collecting queuelib>=1.4.2
  Downloading queuelib-1.5.0-py2.py3-none-any.whl (13 kB)
Collecting lxml>=3.5.0
  Downloading lxml-4.5.0-cp36-cp36m-manylinux1_x86_64.whl (5.8 MB)
Collecting PyDispatcher>=2.0.5
  Downloading PyDispatcher-2.0.5.tar.gz (34 kB)
Collecting Twisted>=17.9.0
  Downloading Twisted-20.3.0-cp36-cp36m-manylinux1_x86_64.whl (3.1 MB)
Collecting pyasn1-modules
  Using cached pyasn1_modules-0.2.8-py2.py3-none-any.whl (155 kB)
Collecting pyasn1
  Using cached pyasn1-0.4.8-py2.py3-none-any.whl (77 kB)
Collecting attrs>=16.0.0
  Using cached attrs-19.3.0-py2.py3-none-any.whl (39 kB)
Collecting six>=1.4.1
  Using cached six-1.14.0-py2.py3-none-any.whl (10 kB)
Collecting cffi!=1.11.3,>=1.8
  Downloading cffi-1.14.0-cp36-cp36m-manylinux1_x86_64.whl (399 kB)
Requirement already satisfied: setuptools in ./venv/lib/python3.6/site-packages (from zope.interface>=4.1.3->scrapy) (46.1.3)
Collecting incremental>=16.10.1
  Downloading incremental-17.5.0-py2.py3-none-any.whl (16 kB)
Collecting Automat>=0.3.0
  Downloading Automat-20.2.0-py2.py3-none-any.whl (31 kB)
Collecting hyperlink>=17.1.1
  Downloading hyperlink-19.0.0-py2.py3-none-any.whl (38 kB)
Collecting PyHamcrest!=1.10.0,>=1.9.0
  Downloading PyHamcrest-2.0.2-py3-none-any.whl (52 kB)
Collecting constantly>=15.1
  Downloading constantly-15.1.0-py2.py3-none-any.whl (7.9 kB)
Collecting pycparser
  Downloading pycparser-2.20-py2.py3-none-any.whl (112 kB)
Collecting idna>=2.5
  Using cached idna-2.9-py2.py3-none-any.whl (58 kB)
Building wheels for collected packages: protego, PyDispatcher
  Building wheel for protego ( ... done
  Created wheel for protego: filename=Protego-0.1.16-py3-none-any.whl size=7765 sha256=7696d4fa63732f3509349e932b23800b7dacc6034fc150eaa3f4448fa401c6aa
  Stored in directory: /home/bojan/.cache/pip/wheels/b2/74/25/517a0ec6186297704db56664268e72686f5cfa8ab398582f33
  Building wheel for PyDispatcher ( ... done
  Created wheel for PyDispatcher: filename=PyDispatcher-2.0.5-py3-none-any.whl size=11515 sha256=17b011eb905d7eccda1eaafb51833fbe7a1b8406fb4a7764e7216ef19fafd698
  Stored in directory: /home/bojan/.cache/pip/wheels/28/db/61/691c759da06ba9b86da079bdd17cb3e01828d49d5c152cb3af
Successfully built protego PyDispatcher
Installing collected packages: six, pycparser, cffi, cryptography, pyasn1, pyasn1-modules, attrs, service-identity, cssselect, w3lib, pyOpenSSL, zope.interface, protego, lxml, parsel, queuelib, PyDispatcher, incremental, Automat, idna, hyperlink, PyHamcrest, constantly, Twisted, scrapy
Successfully installed Automat-20.2.0 PyDispatcher-2.0.5 PyHamcrest-2.0.2 Twisted-20.3.0 attrs-19.3.0 cffi-1.14.0 constantly-15.1.0 cryptography-2.9.2 cssselect-1.1.0 hyperlink-19.0.0 idna-2.9 incremental-17.5.0 lxml-4.5.0 parsel-1.5.2 protego-0.1.16 pyOpenSSL-19.1.0 pyasn1-0.4.8 pyasn1-modules-0.2.8 pycparser-2.20 queuelib-1.5.0 scrapy-2.1.0 service-identity-18.1.0 six-1.14.0 w3lib-1.21.0 zope.interface-5.1.0

(venv) $ pip list --local
Package          Version
---------------- -------
attrs            19.3.0 
Automat          20.2.0 
cffi             1.14.0 
constantly       15.1.0 
cryptography     2.9.2  
cssselect        1.1.0  
hyperlink        19.0.0 
idna             2.9    
incremental      17.5.0 
lxml             4.5.0  
parsel           1.5.2  
pip              20.0.2 
Protego          0.1.16 
pyasn1           0.4.8  
pyasn1-modules   0.2.8  
pycparser        2.20   
PyDispatcher     2.0.5  
PyHamcrest       2.0.2  
pyOpenSSL        19.1.0 
queuelib         1.5.0  
Scrapy           2.1.0  
service-identity 18.1.0 
setuptools       46.1.3 
six              1.14.0 
Twisted          20.3.0 
w3lib            1.21.0 
wheel            0.34.2 
zope.interface   5.1.0  

(venv) $ pip freeze 


(venv) $ scrapy
Scrapy 2.1.0 - no active project

  scrapy <command> [options] [args]

Available commands:
  bench         Run quick benchmark test
  fetch         Fetch a URL using the Scrapy downloader
  genspider     Generate new spider using pre-defined templates
  runspider     Run a self-contained spider (without creating a project)
  settings      Get settings values
  shell         Interactive scraping console
  startproject  Create new project
  version       Print Scrapy version
  view          Open URL in browser, as seen by Scrapy

  [ more ]      More commands available when run from project directory

Use "scrapy <command> -h" to see more info about a command

(venv) $ scrapy bench
2020-04-25 23:57:01 [scrapy.utils.log] INFO: Scrapy 2.1.0 started (bot: scrapybot)
2020-04-25 23:57:01 [scrapy.utils.log] INFO: Versions: lxml, libxml2 2.9.10, cssselect 1.1.0, parsel 1.5.2, w3lib 1.21.0, Twisted 20.3.0, Python 3.6.9 (default, Apr 18 2020, 01:56:04) - [GCC 8.4.0], pyOpenSSL 19.1.0 (OpenSSL 1.1.1g  21 Apr 2020), cryptography 2.9.2, Platform Linux-4.15.0-96-generic-x86_64-with-Ubuntu-18.04-bionic
2020-04-25 23:57:01 [scrapy.crawler] INFO: Overridden settings:
2020-04-25 23:57:01 [scrapy.extensions.telnet] INFO: Telnet Password: 6642b95b9fd73c04
2020-04-25 23:57:01 [scrapy.middleware] INFO: Enabled extensions:
2020-04-25 23:57:01 [scrapy.middleware] INFO: Enabled downloader middlewares:
2020-04-25 23:57:01 [scrapy.middleware] INFO: Enabled spider middlewares:
2020-04-25 23:57:01 [scrapy.middleware] INFO: Enabled item pipelines:
2020-04-25 23:57:01 [scrapy.core.engine] INFO: Spider opened
2020-04-25 23:57:01 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2020-04-25 23:57:01 [scrapy.extensions.telnet] INFO: Telnet console listening on
2020-04-25 23:57:03 [scrapy.extensions.logstats] INFO: Crawled 93 pages (at 5580 pages/min), scraped 0 items (at 0 items/min)
2020-04-25 23:57:03 [scrapy.extensions.logstats] INFO: Crawled 157 pages (at 3840 pages/min), scraped 0 items (at 0 items/min)
2020-04-25 23:57:04 [scrapy.extensions.logstats] INFO: Crawled 230 pages (at 4380 pages/min), scraped 0 items (at 0 items/min)
2020-04-25 23:57:06 [scrapy.extensions.logstats] INFO: Crawled 301 pages (at 4260 pages/min), scraped 0 items (at 0 items/min)
2020-04-25 23:57:07 [scrapy.extensions.logstats] INFO: Crawled 365 pages (at 3840 pages/min), scraped 0 items (at 0 items/min)
2020-04-25 23:57:08 [scrapy.extensions.logstats] INFO: Crawled 422 pages (at 3420 pages/min), scraped 0 items (at 0 items/min)
2020-04-25 23:57:09 [scrapy.extensions.logstats] INFO: Crawled 485 pages (at 3780 pages/min), scraped 0 items (at 0 items/min)
2020-04-25 23:57:10 [scrapy.extensions.logstats] INFO: Crawled 541 pages (at 3360 pages/min), scraped 0 items (at 0 items/min)
2020-04-25 23:57:11 [scrapy.extensions.logstats] INFO: Crawled 597 pages (at 3360 pages/min), scraped 0 items (at 0 items/min)
2020-04-25 23:57:12 [scrapy.core.engine] INFO: Closing spider (closespider_timeout)
2020-04-25 23:57:12 [scrapy.extensions.logstats] INFO: Crawled 646 pages (at 2940 pages/min), scraped 0 items (at 0 items/min)
2020-04-25 23:57:12 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 301439,
 'downloader/request_count': 661,
 'downloader/request_method_count/GET': 661,
 'downloader/response_bytes': 2092067,
 'downloader/response_count': 661,
 'downloader/response_status_count/200': 661,
 'elapsed_time_seconds': 10.596581,
 'finish_reason': 'closespider_timeout',
 'finish_time': datetime.datetime(2020, 4, 25, 22, 57, 12, 551514),
 'log_count/INFO': 20,
 'memusage/max': 55128064,
 'memusage/startup': 55128064,
 'request_depth_max': 22,
 'response_received_count': 661,
 'scheduler/dequeued': 661,
 'scheduler/dequeued/memory': 661,
 'scheduler/enqueued': 13220,
 'scheduler/enqueued/memory': 13220,
 'start_time': datetime.datetime(2020, 4, 25, 22, 57, 1, 954933)}

2020-04-25 23:57:12 [scrapy.core.engine] INFO: Spider closed (closespider_timeout)

Friday, 24 April 2020

How to install Jupyter Notebook on Ubuntu 18.04

Just wanted to share my experience with installing Jupyter Notebook on my Ubuntu 18.04 box.

$ cd my-project

$ virtualenv venv
Using base prefix '/usr'
New python executable in /home/bojan/dev/my-project/venv/bin/python3
Also creating executable in /home/bojan/dev/my-project/venv/bin/python
Installing setuptools, pip, wheel...

$ ls  venv

$ source venv/bin/activate

(venv) $ ls  venv

(venv) $ which pip

(venv) $ which pip3

(venv) $ pip --version
pip 20.0.2 from /home/bojan/dev/my-project/venv/lib/python3.6/site-packages/pip (python 3.6)

(venv) $ pip3 --version
pip 20.0.2 from /home/bojan/dev/my-project/venv/lib/python3.6/site-packages/pip (python 3.6)

(venv) $ pip install jupyter
Collecting jupyter
  Using cached jupyter-1.0.0-py2.py3-none-any.whl (2.7 kB)
Collecting jupyter-console
  Downloading jupyter_console-6.1.0-py2.py3-none-any.whl (21 kB)
Collecting ipywidgets
  Using cached ipywidgets-7.5.1-py2.py3-none-any.whl (121 kB)
Collecting ipykernelbojan@bobox:~/dev/my-project models
  Downloading ipykernel-5.2.1-py3-none-any.whl (118 kB)
Collecting notebook
  Downloading notebook-6.0.3-py3-none-any.whl (9.7 MB)
Collecting nbconvert
  Using cached nbconvert-5.6.1-py2.py3-none-any.whl (455 kB)
Collecting qtconsole
  Downloading qtconsole-4.7.3-py2.py3-none-any.whl (117 kB)
Collecting ipython
  Downloading ipython-7.13.0-py3-none-any.whl (780 kB)
Collecting pygments
  Downloading Pygments-2.6.1-py3-none-any.whl (914 kB)
Collecting jupyter-client
  Downloading jupyter_client-6.1.3-py3-none-any.whl (106 kB)
Collecting prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0
  Downloading prompt_toolkit-3.0.5-py3-none-any.whl (351 kB)
Collecting traitlets>=4.3.1
  Using cached traitlets-4.3.3-py2.py3-none-any.whl (75 kB)
Collecting nbformat>=4.2.0
  Downloading nbformat-5.0.6-py3-none-any.whl (170 kB)
Collecting widgetsnbextension~=3.5.0
  Using cached widgetsnbextension-3.5.1-py2.py3-none-any.whl (2.2 MB)
Collecting tornado>=4.2
  Downloading tornado-6.0.4.tar.gz (496 kB)
Processing /home/bojan/.cache/pip/wheels/1c/54/34/fd47cd9b308826cc4292b54449c1899a30251ef3b506bc91ea/prometheus_client-0.7.1-cp36-none-any.whl
Collecting pyzmq>=17
  Downloading pyzmq-19.0.0-cp36-cp36m-manylinux1_x86_64.whl (1.1 MB)
Collecting jinja2
  Downloading Jinja2-2.11.2-py2.py3-none-any.whl (125 kB)
Collecting Send2Trash
  Using cached Send2Trash-1.5.0-py3-none-any.whl (12 kB)
Collecting jupyter-core>=4.6.1
  Downloading jupyter_core-4.6.3-py2.py3-none-any.whl (83 kB)
Collecting ipython-genutils
  Using cached ipython_genutils-0.2.0-py2.py3-none-any.whl (26 kB)
Collecting terminado>=0.8.1
  Using cached terminado-0.8.3-py2.py3-none-any.whl (33 kB)
Collecting testpath
  Using cached testpath-0.4.4-py2.py3-none-any.whl (163 kB)
Collecting mistune<2,>=0.8.1
  Using cached mistune-0.8.4-py2.py3-none-any.whl (16 kB)
Collecting bleach
  Downloading bleach-3.1.4-py2.py3-none-any.whl (151 kB)
Collecting defusedxml
  Using cached defusedxml-0.6.0-py2.py3-none-any.whl (23 kB)
Collecting entrypoints>=0.2.2
  Using cached entrypoints-0.3-py2.py3-none-any.whl (11 kB)
Processing /home/bojan/.cache/pip/wheels/39/01/56/f1b08a6275acc59e846fa4c1e1b65dbc1919f20157d9e66c20/pandocfilters-1.4.2-cp36-none-any.whl
Collecting qtpy
  Downloading QtPy-1.9.0-py2.py3-none-any.whl (54 kB)
Requirement already satisfied: setuptools>=18.5 in ./venv/lib/python3.6/site-packages (from ipython->jupyter-console->jupyter) (46.1.3)
Collecting pexpect; sys_platform != "win32"
  Downloading pexpect-4.8.0-py2.py3-none-any.whl (59 kB)
Collecting decorator
  Downloading decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
Processing /home/bojan/.cache/pip/wheels/98/b0/dd/29e28ff615af3dda4c67cab719dd51357597eabff926976b45/backcall-0.1.0-cp36-none-any.whl
Collecting jedi>=0.10
  Downloading jedi-0.17.0-py2.py3-none-any.whl (1.1 MB)
Collecting pickleshare
  Using cached pickleshare-0.7.5-py2.py3-none-any.whl (6.9 kB)
Collecting python-dateutil>=2.1
  Using cached python_dateutil-2.8.1-py2.py3-none-any.whl (227 kB)
Collecting wcwidth
  Downloading wcwidth-0.1.9-py2.py3-none-any.whl (19 kB)
Collecting six
  Downloading six-1.14.0-py2.py3-none-any.whl (10 kB)
Collecting jsonschema!=2.5.0,>=2.4
  Using cached jsonschema-3.2.0-py2.py3-none-any.whl (56 kB)
Collecting MarkupSafe>=0.23
  Using cached MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl (27 kB)
Collecting ptyprocess; os_name != "nt"
  Using cached ptyprocess-0.6.0-py2.py3-none-any.whl (39 kB)
Collecting webencodings
  Using cached webencodings-0.5.1-py2.py3-none-any.whl (11 kB)
Collecting parso>=0.7.0
  Downloading parso-0.7.0-py2.py3-none-any.whl (100 kB)
Collecting pyrsistent>=0.14.0
  Downloading pyrsistent-0.16.0.tar.gz (108 kB)
Collecting importlib-metadata; python_version < "3.8"
  Downloading importlib_metadata-1.6.0-py2.py3-none-any.whl (30 kB)
Collecting attrs>=17.4.0
  Using cached attrs-19.3.0-py2.py3-none-any.whl (39 kB)
Collecting zipp>=0.5
  Downloading zipp-3.1.0-py3-none-any.whl (4.9 kB)
Building wheels for collected packages: tornado, pyrsistent
  Building wheel for tornado ( ... done
  Created wheel for tornado: filename=tornado-6.0.4-cp36-cp36m-linux_x86_64.whl size=427634 sha256=2889594a465ff46f8fd99501b165ee4f674855322f0fe1a1df215836d56e20a7
  Stored in directory: /home/bojan/.cache/pip/wheels/37/a7/db/2d592e44029ef817f3ef63ea991db34191cebaef087a96f505
  Building wheel for pyrsistent ( ... done
  Created wheel for pyrsistent: filename=pyrsistent-0.16.0-cp36-cp36m-linux_x86_64.whl size=97736 sha256=06c739603fe2717a15b5bb65e9e0d6cae6ca8de2f1d3ee4988966b6711ca9b89
  Stored in directory: /home/bojan/.cache/pip/wheels/d1/8a/1c/32ab9017418a2c64e4fbaf503c08648bed2f8eb311b869a464
Successfully built tornado pyrsistent
Installing collected packages: tornado, six, python-dateutil, pyzmq, decorator, ipython-genutils, traitlets, jupyter-core, jupyter-client, ptyprocess, pexpect, backcall, parso, jedi, wcwidth, prompt-toolkit, pygments, pickleshare, ipython, ipykernel, jupyter-console, pyrsistent, zipp, importlib-metadata, attrs, jsonschema, nbformat, prometheus-client, MarkupSafe, jinja2, testpath, mistune, webencodings, bleach, defusedxml, entrypoints, pandocfilters, nbconvert, Send2Trash, terminado, notebook, widgetsnbextension, ipywidgets, qtpy, qtconsole, jupyter
Successfully installed MarkupSafe-1.1.1 Send2Trash-1.5.0 attrs-19.3.0 backcall-0.1.0 bleach-3.1.4 decorator-4.4.2 defusedxml-0.6.0 entrypoints-0.3 importlib-metadata-1.6.0 ipykernel-5.2.1 ipython-7.13.0 ipython-genutils-0.2.0 ipywidgets-7.5.1 jedi-0.17.0 jinja2-2.11.2 jsonschema-3.2.0 jupyter-1.0.0 jupyter-client-6.1.3 jupyter-console-6.1.0 jupyter-core-4.6.3 mistune-0.8.4 nbconvert-5.6.1 nbformat-5.0.6 notebook-6.0.3 pandocfilters-1.4.2 parso-0.7.0 pexpect-4.8.0 pickleshare-0.7.5 prometheus-client-0.7.1 prompt-toolkit-3.0.5 ptyprocess-0.6.0 pygments-2.6.1 pyrsistent-0.16.0 python-dateutil-2.8.1 pyzmq-19.0.0 qtconsole-4.7.3 qtpy-1.9.0 six-1.14.0 terminado-0.8.3 testpath-0.4.4 tornado-6.0.4 traitlets-4.3.3 wcwidth-0.1.9 webencodings-0.5.1 widgetsnbextension-3.5.1 zipp-3.1.0


(venv) $ jupyter notebook
[I 01:18:31.669 NotebookApp] Serving notebooks from local directory: /home/bojan/dev/my-project
[I 01:18:31.669 NotebookApp] The Jupyter Notebook is running at:
[I 01:18:31.670 NotebookApp] http://localhost:8888/?token=c9c50e5b8874194d2aaf815a79e079dacdac8eace7691c60
[I 01:18:31.670 NotebookApp]  or
[I 01:18:31.670 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 01:18:31.674 NotebookApp] 
    To access the notebook, open this file in a browser:
    Or copy and paste one of these URLs:
Opening in existing browser session.


Thursday, 23 April 2020

How to upgrade VirtualBox on Ubuntu 18.04

In one of my previous posts I demonstrated how to install VirtualBox and I installed its version 6.0. But in the mean time a new version (6.1) has been released and I want to upgrade it.

I downloaded the most recent deb package but installation failed:

~/Downloads$ sudo dpkg -i virtualbox-6.1_6.1.6-137129_Ubuntu_bionic_amd64.deb 
Selecting previously unselected package virtualbox-6.1.
dpkg: regarding virtualbox-6.1_6.1.6-137129_Ubuntu_bionic_amd64.deb containing virtualbox-6.1:
 virtualbox-6.1 conflicts with virtualbox
  virtualbox-6.0 provides virtualbox and is present and installed.

dpkg: error processing archive virtualbox-6.1_6.1.6-137129_Ubuntu_bionic_amd64.deb (--install):
 conflicting packages - not installing virtualbox-6.1
Errors were encountered while processing:

I checked the name of my previous installation:

~/Downloads$ dpkg -l | grep virtualbox
ii  virtualbox-6.0                                              6.0.4-128413~Ubuntu~bionic                       amd64        Oracle VM VirtualBox

...and used it to uninstall existing version:

~/Downloads$ sudo dpkg -r virtualbox-6.0 
(Reading database ... 290543 files and directories currently installed.)
Removing virtualbox-6.0 (6.0.4-128413~Ubuntu~bionic) ...
Processing triggers for shared-mime-info (1.9-2) ...
Processing triggers for hicolor-icon-theme (0.17-2) ...
Processing triggers for gnome-menus (3.13.3-11ubuntu1.1) ...
Processing triggers for desktop-file-utils (0.23-1ubuntu3.18.04.2) ...
Processing triggers for mime-support (3.60ubuntu1) ...

After this installation was successful:

~/Downloads$ sudo dpkg -i virtualbox-6.1_6.1.6-137129_Ubuntu_bionic_amd64.deb 
(Reading database ... 289716 files and directories currently installed.)
Preparing to unpack virtualbox-6.1_6.1.6-137129_Ubuntu_bionic_amd64.deb ...
Unpacking virtualbox-6.1 (6.1.6-137129~Ubuntu~bionic) ...
Setting up virtualbox-6.1 (6.1.6-137129~Ubuntu~bionic) ...
addgroup: The group `vboxusers' already exists as a system group. Exiting.
Processing triggers for systemd (237-3ubuntu10.39) ...
Processing triggers for ureadahead (0.100.0-21) ...
Processing triggers for gnome-menus (3.13.3-11ubuntu1.1) ...
Processing triggers for desktop-file-utils (0.23-1ubuntu3.18.04.2) ...
Processing triggers for mime-support (3.60ubuntu1) ...
Processing triggers for hicolor-icon-theme (0.17-2) ...
Processing triggers for shared-mime-info (1.9-2) ...

Let's check the state of packages:

$ dpkg -l | grep virtualbox
rc  virtualbox-6.0                                              6.0.4-128413~Ubuntu~bionic                       amd64        Oracle VM VirtualBox
ii  virtualbox-6.1                                              6.1.6-137129~Ubuntu~bionic                       amd64        Oracle VM VirtualBox

First letter -> desired package state ("selection state"):
  • i ... install
  • r ... remove/deinstall
  • p ... purge (remove including config files)

Second letter -> current package state:
  • i ... installed
  • c ... config-files (only the config files are installed)

ii = It should be installed and it is installed
rc = It's removed/uninstalled but it's configuration files are still there