libsodium23 \
patch \
protobuf-compiler \
- virtualenv
+ python3-venv
install-ixfrdist-deps:
description: "Install all libraries needed for testing ixfrdist"
libboost-all-dev \
libsystemd0 \
libyaml-cpp0.6 \
- virtualenv
+ python3-venv
install-auth-dev-deps:
description: Install all packages needed to build the auth
sqlite3 \
systemd \
unixodbc-dev \
- virtualenv \
+ python3-venv \
wget
add-auth-repo:
pkg-config \
ragel \
rsync \
- virtualenv
+ python3-venv
if [ "${CIRCLE_PROJECT_USERNAME}" = "PowerDNS" -a "${CIRCLE_PROJECT_REPONAME}" = "pdns" -a "${CIRCLE_BRANCH}" = "master" ]; then
apt-get update && apt-get -qq -y install \
texlive-full
password: $DOCKERHUB_PASSWORD
steps:
- auth-regress-setup
- - run: apt-get -y -qq install virtualenv sqlite3
+ - run: apt-get -y -qq install python3-venv sqlite3
- run:
name: Run API tests
workdir: ~/project/regression-tests.api
protobuf-compiler \
ragel \
systemd \
- virtualenv
+ python3-venv
- get-workspace
- run:
name: autoconf
password: $DOCKERHUB_PASSWORD
steps:
- add-auth-repo
- - run: apt-get --no-install-recommends install -qq -y pdns-server pdns-backend-bind pdns-tools daemontools authbind jq libfaketime lua-posix lua-socket moreutils bc virtualenv protobuf-compiler
+ - run: apt-get --no-install-recommends install -qq -y pdns-server pdns-backend-bind pdns-tools daemontools authbind jq libfaketime lua-posix lua-socket moreutils bc python3-venv protobuf-compiler
- install-recursor-deps
- run:
name: Set up authbind
password: $DOCKERHUB_PASSWORD
steps:
- add-auth-repo
- - run: apt-get --no-install-recommends install -qq -y virtualenv pdns-tools
+ - run: apt-get --no-install-recommends install -qq -y python3-venv pdns-tools
- install-recursor-deps
- get-workspace
- run:
pkg-config \
protobuf-compiler \
ragel \
- virtualenv
+ python3-venv
- install-coverity-tools
- checkout-shallow
- run:
pkg-config \
protobuf-compiler \
ragel \
- virtualenv
+ python3-venv
- install-coverity-tools
- checkout-shallow
- run:
protobuf-compiler \
ragel \
systemd \
- virtualenv
+ python3-venv
- get-workspace
- run:
name: autoconf
versionmodified
vh
viewcode
-virtualenv
+venv
virtualized
visitedlinkcolor
vixie
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
- # Python and virtualenv are required for building the Authoritative server
+ # Python is required for building the Authoritative server
- uses: actions/setup-python@v2
with:
- python-version: '2.7'
- - run: pip install virtualenv
+ python-version: '3.8'
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
# and modify them (or add more) to build your code if your project
# uses a compiled language
+ - name: Update repository metadata
+ run: |
+ sudo apt-get update
- name: Install dependencies
run: |
- sudo apt-get update && sudo apt-get --no-install-recommends install -qq -y \
+ sudo apt-get -qq -y --no-install-recommends install \
bison \
default-libmysqlclient-dev \
flex \
- export CXXFLAGS=-O0
- export OPTFLAGS=-O0
- sudo apt-get -qq update
- # you can remove this when updating dist to something newer than trusty
- - pyenv global 2.7
- # needed for virtualenv to use the pyenv python
- - pip install virtualenv
+ - pyenv global 3.6
script:
- ./build-scripts/travis.sh
ENV DOCKER_FAKE_RELEASE ${DOCKER_FAKE_RELEASE}
# Manpage deps
-# RUN apt-get install -y virtualenv && apt-get clean
+# RUN apt-get install -y python3-venv && apt-get clean
# Manpage prevent
RUN touch pdns_recursor.1 rec_control.1 # avoid installing pandoc
On Debian 9, the following is useful:
```sh
-apt install g++ libboost-all-dev libtool make pkg-config default-libmysqlclient-dev libssl-dev virtualenv libluajit-5.1-dev
+apt install g++ libboost-all-dev libtool make pkg-config default-libmysqlclient-dev libssl-dev libluajit-5.1-dev python3-venv
```
When building from git, the following packages are also required:
For Ubuntu 18.04 (Bionic Beaver), the following packages should be installed:
```sh
-apt install libcurl4-openssl-dev luajit lua-yaml-dev libyaml-cpp-dev libtolua-dev lua5.3 autoconf automake ragel bison flex g++ libboost-all-dev libtool make pkg-config libssl-dev virtualenv lua-yaml-dev libyaml-cpp-dev libluajit-5.1-dev libcurl4 gawk libsqlite3-dev
+apt install libcurl4-openssl-dev luajit lua-yaml-dev libyaml-cpp-dev libtolua-dev lua5.3 autoconf automake ragel bison flex g++ libboost-all-dev libtool make pkg-config libssl-dev lua-yaml-dev libyaml-cpp-dev libluajit-5.1-dev libcurl4 gawk libsqlite3-dev python3-venv
# For DNSSEC ed25519 (algorithm 15) support with --with-libsodium
apt install libsodium-dev
# If using the gmysql (Generic MySQL) backend
ARG BUILDER_CACHE_BUSTER=
RUN apk add --no-cache gcc g++ make tar autoconf automake protobuf-dev lua-dev \
- libtool file boost-dev curl openssl-dev ragel py-virtualenv \
+ libtool file boost-dev curl openssl-dev ragel python3 \
flex bison git
# the pdns/ dir is a bit broad, but who cares :)
FROM dist-base as package-builder
ARG APT_URL
-RUN DEBIAN_FRONTEND=noninteractive apt-get -y install devscripts dpkg-dev build-essential python3 equivs
+RUN DEBIAN_FRONTEND=noninteractive apt-get -y install devscripts dpkg-dev build-essential python3-venv equivs
RUN mkdir /dist /pdns
WORKDIR /pdns
ARG BUILDER_CACHE_BUSTER=
RUN apk add --no-cache gcc g++ make tar autoconf automake protobuf-dev lua-dev \
- libtool file boost-dev ragel py-virtualenv git libedit-dev
+ libtool file boost-dev ragel python3 git libedit-dev
ADD builder/helpers/set-configure-ac-version.sh /dnsdist/builder/helpers/
ADD COPYING /dnsdist/
ARG BUILDER_CACHE_BUSTER=
RUN apk add --no-cache gcc g++ make tar autoconf automake protobuf-dev lua-dev \
- libtool file boost-dev curl openssl-dev ragel py-virtualenv \
+ libtool file boost-dev curl openssl-dev ragel python3 \
flex bison git
ADD COPYING NOTICE /pdns-recursor/
FROM dist-base as package-builder
RUN touch /var/lib/rpm/* && \
- yum install -y rpm-build rpmdevtools /usr/bin/python3 && \
- yum groupinstall -y "Development Tools" && \
- rpmdev-setuptree
+ yum install -y rpm-build rpmdevtools python3 "@Development Tools"
RUN mkdir /dist /pdns
WORKDIR /pdns
RUN touch /var/lib/rpm/* && yum install -y --verbose epel-release centos-release-scl-rh && \
yum install -y --nogpgcheck devtoolset-7-gcc-c++
+# Enable IUS Community Repository (for Python 3.6)
+RUN curl https://setup.ius.io/ | sh
+RUN touch /var/lib/rpm/* && yum install -y --verbose python36 && ln -s python36 /usr/bin/python3
+
# Do the actual rpm build
@INCLUDE Dockerfile.rpmbuild
texlive-font-utils \
texlive-fonts-extra \
texlive-latex-extra \
- virtualenv
+ python3-venv
RUN mkdir -p /pdns /dist /sdist
PDNS_WITH_SQLITE3
-PDNS_CHECK_VIRTUALENV
+PDNS_CHECK_PYTHON_VENV
+
+AM_CONDITIONAL([HAVE_API_SWAGGER_JSON], [test -e "$srcdir/pdns/api-swagger.json"])
+AM_COND_IF([HAVE_API_SWAGGER_JSON],[],[
+ AM_COND_IF([HAVE_VENV],[],[
+ AC_MSG_ERROR([Python 3 and/or venv module are not available, Authoritative Server cannot be built.])
+ ])
+])
+
+AM_CONDITIONAL([HAVE_MANPAGES], [test -e "$srcdir/docs/pdns_server.1"])
+AM_COND_IF([HAVE_MANPAGES],[],[
+ AM_COND_IF([HAVE_VENV],[],[
+ AC_MSG_WARN([Python 3 and/or venv module are not available, documentation will not be built.])
+ ])
+])
+
PDNS_FROM_GIT
dnl Checks for library functions.
EXTRA_DIST = $(MANPAGES_DIST)
-if HAVE_VIRTUALENV
+if HAVE_VENV
if !HAVE_MANPAGES
$(MANPAGES_DIST): %: mans/.complete manpages/%.rst
mv "$(<D)/$@" "$@" && rm -f "$<"
rm -rf "$(@D).tmp"
.venv: requirements.txt
- virtualenv .venv
- .venv/bin/pip install -U pip setuptools setuptools-git
+ $(PYTHON) -m venv .venv
+ .venv/bin/pip install -U pip setuptools setuptools-git wheel
.venv/bin/pip install -r requirements.txt
.NOTPARALLEL: \
rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./html-docs.tar.bz2 web1.powerdns.com:/srv/www/doc.powerdns.com/authoritative/
rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./PowerDNS-Authoritative.pdf web1.powerdns.com:/srv/www/doc.powerdns.com/authoritative/
-else # if HAVE_VIRTUALENV
+else # if HAVE_VENV
$(MANPAGES_DIST):
- echo "You need virtualenv to generate the manpages"
+ @echo "You need Python 3 and the 'venv' module to generate the manpages"
exit 1
PowerDNS-Authoritative.pdf:
- echo "You need virtualenv to generate the PDF"
+ @echo "You need Python 3 and the 'venv' module to generate the PDF"
exit 1
html-docs:
- echo "You need virtualenv to generate the HTML docs"
+ @echo "You need Python 3 and the 'venv' module to generate the HTML docs"
exit 1
endif
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.venv:
- virtualenv .venv
- .venv/bin/pip install -U pip setuptools setuptools-git
+ python3 -m venv .venv
+ .venv/bin/pip install -U pip setuptools setuptools-git wheel
.venv/bin/pip install -r requirements.txt
* `Boost <http://boost.org/>`_ 1.35 or newer
* `OpenSSL <https://openssl.org>`_
-To build from git, the following dependencies are also required:
+To build from a Git repository clone, the following dependencies are also required:
* `ragel <http://www.colm.net/open-source/ragel/>`_
* `bison <https://www.gnu.org/software/bison/>`_
* `flex <https://github.com/westes/flex>`_
-* `virtualenv <https://pypi.python.org/pypi/virtualenv>`_
+* `Python <https://python.org>`_ 3.6 or newer, with the 'venv' package
Optional dependencies
---------------------
--- /dev/null
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_python_module.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_PYTHON_MODULE(modname[, fatal, python])
+#
+# DESCRIPTION
+#
+# Checks for Python module.
+#
+# If fatal is non-empty then absence of a module will trigger an error.
+# The third parameter can either be "python" for Python 2 or "python3" for
+# Python 3; defaults to Python 3.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Andrew Collier
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 9
+
+AU_ALIAS([AC_PYTHON_MODULE], [AX_PYTHON_MODULE])
+AC_DEFUN([AX_PYTHON_MODULE],[
+ if test -z $PYTHON;
+ then
+ if test -z "$3";
+ then
+ PYTHON="python3"
+ else
+ PYTHON="$3"
+ fi
+ fi
+ PYTHON_NAME=`basename $PYTHON`
+ AC_MSG_CHECKING($PYTHON_NAME module: $1)
+ $PYTHON -c "import $1" 2>/dev/null
+ if test $? -eq 0;
+ then
+ AC_MSG_RESULT(yes)
+ eval AS_TR_CPP(HAVE_PYMOD_$1)=yes
+ else
+ AC_MSG_RESULT(no)
+ eval AS_TR_CPP(HAVE_PYMOD_$1)=no
+ #
+ if test -n "$2"
+ then
+ AC_MSG_ERROR(failed to find required module $1)
+ exit 1
+ fi
+ fi
+])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_PYTHON_VENV], [
+ dnl Check for optional Python, at least version 3.6.
+ AM_PATH_PYTHON([3.6],,[:])
+ dnl Check for Python venv module
+ AS_IF([test "${PYTHON}" != ":"], [
+ AX_PYTHON_MODULE([venv],[])
+ ])
+ AM_CONDITIONAL([HAVE_VENV], [test "x${HAVE_PYMOD_VENV}" = "xyes"])
+])
+++ /dev/null
-AC_DEFUN([PDNS_CHECK_VIRTUALENV], [
- AC_CHECK_PROG([VIRTUALENV], [virtualenv], [virtualenv], [no])
-
- AS_IF([test "x$VIRTUALENV" = "xno"], [
- AS_IF([test ! -f "$srcdir/pdns_server.1"],
- [AC_MSG_WARN([virtualenv is missing, unable to build manpages.])]
- )
- ])
- AM_CONDITIONAL([HAVE_VIRTUALENV], [test "x$VIRTUALENV" != "xno"])
- AM_CONDITIONAL([HAVE_MANPAGES], [test -e "$srcdir/docs/pdns_server.1"])
- AM_CONDITIONAL([HAVE_API_SWAGGER_JSON], [test -e "$srcdir/pdns/api-swagger.json"])
-])
api-swagger.yaml \
api-swagger.json \
requirements.txt \
- incfiles
+ incfiles \
+ convert-yaml-to-json.py
BUILT_SOURCES = \
bind-dnssec.schema.sqlite3.sql.h \
api-swagger.yaml: $(wildcard ../docs/http-api/swagger/authoritative-api-swagger.yaml)
cp $< $@
-if HAVE_VIRTUALENV
+if HAVE_VENV
.venv: requirements.txt
- virtualenv .venv
- .venv/bin/pip install -U pip setuptools setuptools-git
+ $(PYTHON) -m venv .venv
+ .venv/bin/pip install -U pip setuptools setuptools-git wheel
.venv/bin/pip install -r requirements.txt
api-swagger.json: api-swagger.yaml .venv
- .venv/bin/python -c "import sys, json, yaml; y = yaml.safe_load(sys.stdin.read()); json.dump(y, sys.stdout, indent=2, separators=(',', ': '))" < $< > $@
-else # if HAVE_VIRTUALENV
+ .venv/bin/python convert-yaml-to-json.py $< $@
+else # if HAVE_VENV
if !HAVE_API_SWAGGER_JSON
api-swagger.json:
- echo "You need virtualenv to generate the JSON API document"
+ echo "You need Python 3 and the 'venv' module to generate the JSON API document"
exit 1
endif
endif
--- /dev/null
+import sys, json, yaml
+
+with open(sys.argv[1], mode='r', encoding='utf-8') as f_in:
+ with open(sys.argv[2], mode='w', encoding='utf-8') as f_out:
+ json.dump(yaml.safe_load(f_in.read()), f_out, indent=2, separators=(',', ': '))
dist_man_MANS=$(MANPAGES)
-if HAVE_VIRTUALENV
+if HAVE_VENV
if !HAVE_MANPAGES
$(MANPAGES): %: docs/manpages/%.rst .venv
$(AM_V_GEN).venv/bin/python -msphinx -b man docs . $<
endif # if !HAVE_MANPAGES
.venv: docs/requirements.txt
- virtualenv .venv
- .venv/bin/pip install -U pip setuptools setuptools-git
+ $(PYTHON) -m venv .venv
+ .venv/bin/pip install -U pip setuptools setuptools-git wheel
.venv/bin/pip install -r $<
latex/dnsdist.pdf: docs/** .venv
rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./html-docs.tar.bz2 web1.powerdns.com:/srv/www/dnsdist.org
rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./dnsdist.pdf web1.powerdns.com:/srv/www/dnsdist.org
-else # if HAVE_VIRTUALENV
+else # if HAVE_VENV
$(MANPAGES):
- @echo "You need virtualenv to generate the manpages"
+ @echo "You need Python 3 and the 'venv' module to generate the manpages"
exit 1
html-docs: %: docs/manpages/%.rst .venv
- @echo "You need virtualenv to generate the HTML documentation"
+ @echo "You need Python 3 and the 'venv' module to generate the HTML docs"
exit 1
dnsdist.pdf:
- @echo "You need virtualenv to generate the pdf documentation"
+ @echo "You need Python 3 and the 'venv' module to generate the PDF"
exit 1
endif
PDNS_ENABLE_SANITIZERS
-PDNS_CHECK_VIRTUALENV
+PDNS_CHECK_PYTHON_VENV
+
+AM_CONDITIONAL([HAVE_MANPAGES], [test -e "$srcdir/dnsdist.1"])
+AM_COND_IF([HAVE_MANPAGES],[],[
+ AM_COND_IF([HAVE_VENV],[],[
+ AC_MSG_WARN([Python 3 and/or venv module are not available, documentation will not be built.])
+ ])
+])
LDFLAGS="$RELRO_LDFLAGS $LDFLAGS"
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.venv:
- virtualenv .venv
- .venv/bin/pip install -U pip setuptools setuptools-git
+ python3 -m venv .venv
+ .venv/bin/pip install -U pip setuptools setuptools-git wheel
.venv/bin/pip install -r requirements.txt
--- /dev/null
+../../../m4/ax_python_module.m4
\ No newline at end of file
--- /dev/null
+../../../m4/pdns_check_python_venv.m4
\ No newline at end of file
+++ /dev/null
-AC_DEFUN([PDNS_CHECK_VIRTUALENV], [
- AC_CHECK_PROG([VIRTUALENV], [virtualenv], [virtualenv], [no])
-
- AS_IF([test "x$VIRTUALENV" = "xno"], [
- AS_IF([test ! -f "$srcdir/dnsdist.1"],
- [AC_MSG_WARN([virtualenv is missing, unable to build manpages.])]
- )
- ])
- AM_CONDITIONAL([HAVE_VIRTUALENV], [test "x$VIRTUALENV" != "xno"])
- AM_CONDITIONAL([HAVE_MANPAGES], [test -e "$srcdir/dnsdist.1"])
-])
-
dist_man_MANS=$(MANPAGES)
-if HAVE_VIRTUALENV
+if HAVE_VENV
if !HAVE_MANPAGES
$(MANPAGES): %: docs/manpages/%.rst .venv
.venv/bin/python -msphinx -b man docs . $<
endif # if !HAVE_MANPAGES
.venv: docs/requirements.txt
- virtualenv .venv
- .venv/bin/pip install -U pip setuptools setuptools-git
+ $(PYTHON) -m venv .venv
+ .venv/bin/pip install -U pip setuptools setuptools-git wheel
.venv/bin/pip install -r docs/requirements.txt
html-docs: docs/** .venv
rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./html-docs.tar.bz2 web1.powerdns.com:/srv/www/doc.powerdns.com/recursor/
rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./PowerDNS-Recursor.pdf web1.powerdns.com:/srv/www/doc.powerdns.com/recursor/
-else # if HAVE_VIRTUALENV
+else # if HAVE_VENV
$(MANPAGES):
- echo "You need virtualenv to generate the manpages"
+ @echo "You need Python 3 and the 'venv' module to generate the manpages"
exit 1
PowerDNS-Recursor.pdf:
- echo "You need virtualenv to generate the PDF"
+ @echo "You need Python 3 and the 'venv' module to generate the PDF"
exit 1
html-docs:
- echo "You need virtualenv to generate the HTML docs"
+ @echo "You need Python 3 and the 'venv' module to generate the HTML docs"
exit 1
endif
AX_CHECK_SYSTEMD_FEATURES
AM_CONDITIONAL([HAVE_SYSTEMD], [ test x"$systemd" = "xy" ])
PDNS_WITH_SERVICE_USER([pdns-recursor])
-PDNS_CHECK_VIRTUALENV
+
+PDNS_CHECK_PYTHON_VENV
+
+AM_CONDITIONAL([HAVE_MANPAGES], [test -e "$srcdir/pdns_recursor.1"])
+AM_COND_IF([HAVE_MANPAGES],[],[
+ AM_COND_IF([HAVE_VENV],[],[
+ AC_MSG_WARN([Python 3 and/or venv module are not available, documentation will not be built.])
+ ])
+])
AC_SUBST(LIBS)
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.venv:
- virtualenv .venv
- .venv/bin/pip install -U pip setuptools setuptools-git
+ python3 -m venv .venv
+ .venv/bin/pip install -U pip setuptools setuptools-git wheel
.venv/bin/pip install -r requirements.txt
--- /dev/null
+../../../m4/ax_python_module.m4
\ No newline at end of file
--- /dev/null
+../../../m4/pdns_check_python_venv.m4
\ No newline at end of file
+++ /dev/null
-AC_DEFUN([PDNS_CHECK_VIRTUALENV], [
- AC_CHECK_PROG([VIRTUALENV], [virtualenv], [virtualenv], [no])
-
- AS_IF([test "x$VIRTUALENV" = "xno"], [
- AS_IF([test ! -f "$srcdir/pdns_recursor.1"],
- [AC_MSG_WARN([virtualenv is missing, unable to build manpages.])]
- )
- ])
- AM_CONDITIONAL([HAVE_VIRTUALENV], [test "x$VIRTUALENV" != "xno"])
- AM_CONDITIONAL([HAVE_MANPAGES], [test -e "$srcdir/pdns_recursor.1"])
-])
-
#!/usr/bin/env bash
if [ ! -d .venv ]; then
- if [ -z "$PYTHON" ]; then
- if [ ! -z "$(python3 --version | egrep '^Python 3.[6789]' 2>/dev/null)" ]; then
- # found python3.6 or better
- PYTHON=python3
- else
- # until we have better Linux distribution detection.
- PYTHON=python2
- fi
- fi
-
- virtualenv -p ${PYTHON} .venv
+ python3 -m venv .venv
fi
. .venv/bin/activate
python -V
#!/usr/bin/env bash
set -e
-readonly PYTHON=${PYTHON:-python2}
-
if [ ! -d .venv ]; then
- virtualenv -p ${PYTHON} .venv
+ python3 -m venv .venv
fi
. .venv/bin/activate
set -e
if [ ! -d .venv ]; then
- if [ -z "$PYTHON" ]; then
- if [ ! -z "$(python3 --version | egrep '^Python 3.[6789]' 2>/dev/null)" ]; then
- # found python3.6 or better
- PYTHON=python3
- else
- # until we have better Linux distribution detection.
- PYTHON=python2
- fi
- fi
-
- virtualenv -p ${PYTHON} .venv
+ python3 -m venv .venv
fi
. .venv/bin/activate
python -V
set -e
if [ ! -d .venv ]; then
- if [ -z "$PYTHON" ]; then
- if [ ! -z "$(python3 --version | egrep '^Python 3.[6789]' 2>/dev/null)" ]; then
- # found python3.6 or better
- PYTHON=python3
- else
- # until we have better Linux distribution detection.
- PYTHON=python2
- fi
- fi
-
- virtualenv -p ${PYTHON} .venv
+ python3 -m venv .venv
fi
. .venv/bin/activate
python -V
#!/bin/sh
-PYTHON=${PYTHON:-python2}
-
if [ ! -d .venv ]; then
- virtualenv -p ${PYTHON} .venv
+ python3 -m venv .venv
fi
. .venv/bin/activate
python -V