feat(python): virtual env in template

This commit is contained in:
Jan De Dobbeleer 2021-12-04 11:56:55 +01:00 committed by Jan De Dobbeleer
parent f495a7093a
commit 29afb86e61
34 changed files with 233 additions and 159 deletions

View file

@ -27,7 +27,7 @@ Supports conda, virtualenv and pyenv.
## Properties
- home_enabled: `boolean` - display the segment in the HOME folder or not - defaults to `false`
- display_virtual_env: `boolean` - show the name of the virtualenv or not - defaults to `true`
- fetch_virtual_env: `boolean` - fetch the name of the virtualenv or not - defaults to `true`
- display_default: `boolean` - show the name of the virtualenv when it's default (`system`, `base`)
or not - defaults to `true`
- display_version: `boolean` - display the python version - defaults to `true`

View file

@ -23,8 +23,8 @@ const (
ExcludeFolders Property = "exclude_folders"
// IgnoreFolders duplicate of ExcludeFolders
IgnoreFolders Property = "ignore_folders"
// DisplayVersion show the version number or not
DisplayVersion Property = "display_version"
// FetchVersion fetch the version number or not
FetchVersion Property = "fetch_version"
// AlwaysEnabled decides whether or not to always display the info
AlwaysEnabled Property = "always_enabled"
// SegmentTemplate is the template to use to render the information

View file

@ -17,12 +17,12 @@ const (
// Properties
func (p properties) getOneOfBool(property, legacyProperty Property) bool {
func (p properties) getOneOfBool(property, legacyProperty Property, defaultValue bool) bool {
_, found := p[legacyProperty]
if found {
return p.getBool(legacyProperty, false)
return p.getBool(legacyProperty, defaultValue)
}
return p.getBool(property, false)
return p.getBool(property, defaultValue)
}
func (p properties) hasOneOf(properties ...Property) bool {
@ -306,3 +306,81 @@ func (s *session) getFormattedText() string {
}
return fmt.Sprintf("%s%s%s%s", sshIcon, s.UserName, separator, s.ComputerName)
}
// Language
const (
// DisplayVersion show the version number or not
DisplayVersion Property = "display_version"
)
func (l *language) string() string {
if !l.props.getBool(DisplayVersion, true) {
return ""
}
err := l.setVersion()
if err != nil {
l.Error = err.Error()
}
displayError := l.props.getBool(DisplayError, true)
if err != nil && displayError {
return err.Error()
}
if err != nil {
return ""
}
segmentTemplate := l.props.getString(SegmentTemplate, "{{ .Full }}")
template := &textTemplate{
Template: segmentTemplate,
Context: l.version,
Env: l.env,
}
text, err := template.render()
if err != nil {
return err.Error()
}
if l.props.getBool(EnableHyperlink, false) {
versionURLTemplate := l.props.getString(VersionURLTemplate, "")
// backward compatibility
if versionURLTemplate == "" {
text = l.buildVersionURL(text)
} else {
template := &textTemplate{
Template: versionURLTemplate,
Context: l.version,
Env: l.env,
}
url, err := template.render()
if err != nil {
return err.Error()
}
text = url
}
}
if l.props.getBool(EnableVersionMismatch, false) {
l.setVersionFileMismatch()
}
return text
}
// Python
const (
// DisplayVirtualEnv shows or hides the virtual env
DisplayVirtualEnv Property = "display_virtual_env"
)
func (p *python) legacyString() string {
if p.Venv == "" {
return p.language.string()
}
version := p.language.string()
if version == "" {
return p.Venv
}
return fmt.Sprintf("%s %s", p.Venv, version)
}

View file

@ -596,3 +596,50 @@ func TestPropertySessionSegment(t *testing.T) {
}
}
}
// Python
func TestPythonVirtualEnv(t *testing.T) {
cases := []struct {
Case string
Expected string
ExpectedDisabled bool
VirtualEnvName string
CondaEnvName string
CondaDefaultEnvName string
PyEnvName string
DisplayVersion bool
DisplayDefault bool
}{
{Case: "VENV", Expected: "VENV", VirtualEnvName: "VENV"},
{Case: "CONDA", Expected: "CONDA", CondaEnvName: "CONDA"},
{Case: "CONDA default", Expected: "CONDA", CondaDefaultEnvName: "CONDA"},
{Case: "Display Base", Expected: "base", CondaDefaultEnvName: "base", DisplayDefault: true},
{Case: "Hide base", Expected: "", CondaDefaultEnvName: "base", ExpectedDisabled: true},
{Case: "PYENV", Expected: "PYENV", PyEnvName: "PYENV"},
{Case: "PYENV Version", Expected: "PYENV 3.8.4", PyEnvName: "PYENV", DisplayVersion: true},
}
for _, tc := range cases {
env := new(MockedEnvironment)
env.On("hasCommand", "python").Return(true)
env.On("runCommand", "python", []string{"--version"}).Return("Python 3.8.4", nil)
env.On("hasFiles", "*.py").Return(true)
env.On("getenv", "VIRTUAL_ENV").Return(tc.VirtualEnvName)
env.On("getenv", "CONDA_ENV_PATH").Return(tc.CondaEnvName)
env.On("getenv", "CONDA_DEFAULT_ENV").Return(tc.CondaDefaultEnvName)
env.On("getenv", "PYENV_VERSION").Return(tc.PyEnvName)
env.On("getPathSeperator", nil).Return("")
env.On("getcwd", nil).Return("/usr/home/project")
env.On("homeDir", nil).Return("/usr/home")
var props properties = map[Property]interface{}{
DisplayVersion: tc.DisplayVersion,
DisplayVirtualEnv: true,
DisplayDefault: tc.DisplayDefault,
}
python := &python{}
python.init(props, env)
assert.Equal(t, !tc.ExpectedDisabled, python.enabled(), tc.Case)
assert.Equal(t, tc.Expected, python.string(), tc.Case)
}
}

View file

@ -184,20 +184,20 @@ func (g *git) shouldIgnoreRootRepository(rootDir string) bool {
func (g *git) string() string {
statusColorsEnabled := g.props.getBool(StatusColorsEnabled, false)
displayStatus := g.props.getOneOfBool(FetchStatus, DisplayStatus)
displayStatus := g.props.getOneOfBool(FetchStatus, DisplayStatus, false)
if !displayStatus {
g.HEAD = g.getPrettyHEADName()
}
if displayStatus || statusColorsEnabled {
g.setGitStatus()
}
if g.Upstream != "" && g.props.getOneOfBool(FetchUpstreamIcon, DisplayUpstreamIcon) {
if g.Upstream != "" && g.props.getOneOfBool(FetchUpstreamIcon, DisplayUpstreamIcon, false) {
g.UpstreamIcon = g.getUpstreamIcon()
}
if g.props.getOneOfBool(FetchStashCount, DisplayStashCount) {
if g.props.getOneOfBool(FetchStashCount, DisplayStashCount, false) {
g.StashCount = g.getStashContext()
}
if g.props.getOneOfBool(FetchWorktreeCount, DisplayWorktreeCount) {
if g.props.getOneOfBool(FetchWorktreeCount, DisplayWorktreeCount, false) {
g.WorktreeCount = g.getWorktreeContext()
}
// use template if available

View file

@ -84,25 +84,17 @@ const (
LanguageExtensions Property = "extensions"
)
func (l *language) string() string {
if !l.props.getBool(DisplayVersion, true) {
return ""
func (l *language) renderTemplate(segmentTemplate string, context SegmentWriter) string {
if l.props.getBool(FetchVersion, true) {
err := l.setVersion()
if err != nil {
l.Error = err.Error()
}
}
err := l.setVersion()
l.Error = err.Error()
displayError := l.props.getBool(DisplayError, true)
if err != nil && displayError {
return err.Error()
}
if err != nil {
return ""
}
segmentTemplate := l.props.getString(SegmentTemplate, "{{ .Full }}")
template := &textTemplate{
Template: segmentTemplate,
Context: l.version,
Context: context,
Env: l.env,
}
text, err := template.render()
@ -110,27 +102,22 @@ func (l *language) string() string {
return err.Error()
}
if l.props.getBool(EnableHyperlink, false) {
versionURLTemplate := l.props.getString(VersionURLTemplate, "")
// backward compatibility
if versionURLTemplate == "" {
text = l.buildVersionURL(text)
} else {
template := &textTemplate{
Template: versionURLTemplate,
Context: l.version,
Env: l.env,
}
url, err := template.render()
if err != nil {
return err.Error()
}
text = url
}
if !l.props.getBool(EnableHyperlink, false) {
return text
}
if l.props.getBool(EnableVersionMismatch, false) {
l.setVersionFileMismatch()
versionURLTemplate := l.props.getString(VersionURLTemplate, "")
// backward compatibility
if versionURLTemplate == "" {
return l.buildVersionURL(text)
}
template = &textTemplate{
Template: versionURLTemplate,
Context: l.version,
Env: l.env,
}
text, err = template.render()
if err != nil {
return err.Error()
}
return text
}

View file

@ -1,7 +1,5 @@
package main
import "fmt"
type python struct {
language
@ -9,19 +7,16 @@ type python struct {
}
const (
// DisplayVirtualEnv shows or hides the virtual env
DisplayVirtualEnv Property = "display_virtual_env"
// FetchVirtualEnv fetches the virtual env
FetchVirtualEnv Property = "fetch_virtual_env"
)
func (p *python) string() string {
if p.Venv == "" {
return p.language.string()
segmentTemplate := p.language.props.getString(SegmentTemplate, "")
if len(segmentTemplate) == 0 {
return p.legacyString()
}
version := p.language.string()
if version == "" {
return p.Venv
}
return fmt.Sprintf("%s %s", p.Venv, version)
return p.language.renderTemplate(segmentTemplate, p)
}
func (p *python) init(props properties, env environmentInfo) {
@ -54,7 +49,7 @@ func (p *python) enabled() bool {
}
func (p *python) loadContext() {
if !p.language.props.getBool(DisplayVirtualEnv, true) {
if !p.language.props.getOneOfBool(DisplayVirtualEnv, FetchVirtualEnv, true) {
return
}
venvVars := []string{

View file

@ -6,25 +6,38 @@ import (
"github.com/alecthomas/assert"
)
func TestPythonVirtualEnv(t *testing.T) {
func TestPythonTemplate(t *testing.T) {
cases := []struct {
Case string
Expected string
ExpectedDisabled bool
VirtualEnvName string
CondaEnvName string
CondaDefaultEnvName string
PyEnvName string
DisplayVersion bool
DisplayDefault bool
Case string
Expected string
ExpectedDisabled bool
Template string
VirtualEnvName string
FetchVersion bool
}{
{Case: "VENV", Expected: "VENV", VirtualEnvName: "VENV"},
{Case: "CONDA", Expected: "CONDA", CondaEnvName: "CONDA"},
{Case: "CONDA default", Expected: "CONDA", CondaDefaultEnvName: "CONDA"},
{Case: "Display Base", Expected: "base", CondaDefaultEnvName: "base", DisplayDefault: true},
{Case: "Hide base", Expected: "", CondaDefaultEnvName: "base", ExpectedDisabled: true},
{Case: "PYENV", Expected: "PYENV", PyEnvName: "PYENV"},
{Case: "PYENV Version", Expected: "PYENV 3.8.4", PyEnvName: "PYENV", DisplayVersion: true},
{Case: "No virtual env present", FetchVersion: true, Expected: "3.8.4", Template: "{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}"},
{Case: "Virtual env present", FetchVersion: true, Expected: "VENV 3.8.4", VirtualEnvName: "VENV", Template: "{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}"},
{
Case: "Virtual env major and minor dot",
FetchVersion: true,
Expected: "VENV 3.8",
VirtualEnvName: "VENV",
Template: "{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Major }}.{{ .Minor }}",
},
{
Case: "Virtual env hide on default",
FetchVersion: true,
Expected: "3.8",
VirtualEnvName: "default",
Template: "{{ if ne .Venv \"default\" }}{{ .Venv }} {{ end }}{{ .Major }}.{{ .Minor }}",
},
{
Case: "Virtual env show non default",
FetchVersion: true,
Expected: "billy 3.8",
VirtualEnvName: "billy",
Template: "{{ if ne .Venv \"default\" }}{{ .Venv }} {{ end }}{{ .Major }}.{{ .Minor }}",
},
}
for _, tc := range cases {
@ -33,16 +46,16 @@ func TestPythonVirtualEnv(t *testing.T) {
env.On("runCommand", "python", []string{"--version"}).Return("Python 3.8.4", nil)
env.On("hasFiles", "*.py").Return(true)
env.On("getenv", "VIRTUAL_ENV").Return(tc.VirtualEnvName)
env.On("getenv", "CONDA_ENV_PATH").Return(tc.CondaEnvName)
env.On("getenv", "CONDA_DEFAULT_ENV").Return(tc.CondaDefaultEnvName)
env.On("getenv", "PYENV_VERSION").Return(tc.PyEnvName)
env.On("getenv", "CONDA_ENV_PATH").Return(tc.VirtualEnvName)
env.On("getenv", "CONDA_DEFAULT_ENV").Return(tc.VirtualEnvName)
env.On("getenv", "PYENV_VERSION").Return(tc.VirtualEnvName)
env.On("getPathSeperator", nil).Return("")
env.On("getcwd", nil).Return("/usr/home/project")
env.On("homeDir", nil).Return("/usr/home")
var props properties = map[Property]interface{}{
DisplayVersion: tc.DisplayVersion,
DisplayVirtualEnv: true,
DisplayDefault: tc.DisplayDefault,
FetchVersion: tc.FetchVersion,
SegmentTemplate: tc.Template,
DisplayMode: DisplayModeAlways,
}
python := &python{}
python.init(props, env)

View file

@ -122,9 +122,9 @@
"background": "p:python",
"properties": {
"prefix": " \uE235 ",
"display_version": true,
"display_mode": "files",
"display_virtual_env": false
"fetch_virtual_env": false,
"template": "{{ .Full }}"
}
},
{

View file

@ -91,9 +91,9 @@
"background": "#FFDE57",
"properties": {
"prefix": " \uE235 ",
"display_version": true,
"display_mode": "files",
"display_virtual_env": false
"fetch_virtual_env": false,
"template": "{{ .Full }}"
}
},
{

View file

@ -288,7 +288,6 @@
"foreground": "#ffffff",
"properties": {
"prefix": " \uf5ef ",
"postfix": " ",
"time_format": "_2,15:04"
}
}

View file

@ -14,7 +14,6 @@
"foreground": "#fff",
"properties": {
"prefix": "",
"postfix": " ",
"template": "{{ .UserName }}"
}
},
@ -26,9 +25,7 @@
"background": "green",
"foreground": "#fff",
"properties": {
"style": "folder",
"prefix": " ",
"postfix": " "
"style": "folder"
}
},
{
@ -53,9 +50,7 @@
"foreground": "#fff",
"background": "lightMagenta",
"properties": {
"time_format": "15:04",
"prefix": " ",
"postfix": " "
"time_format": "15:04"
}
}
]

View file

@ -36,8 +36,7 @@
"folder_icon": "\uF115",
"folder_separator_icon": " \uE0B1 ",
"style": "full",
"prefix": "<transparent>\uE0B0</> ",
"postfix": " "
"prefix": "<transparent>\uE0B0</> "
}
},
{
@ -47,7 +46,6 @@
"background": "#007ACC",
"properties": {
"prefix": "<#ffffff>\uE0B1</> ",
"postfix": " ",
"template": "{{ .HEAD }}"
}
},

View file

@ -39,8 +39,7 @@
"foreground": "#193549",
"background": "#4caf50",
"properties": {
"time_format": "2006-01-02 15:04:05",
"prefix": " "
"time_format": "2006-01-02 15:04:05"
}
},

View file

@ -84,8 +84,7 @@
"foreground": "#ffffff",
"background": "#83769c",
"properties": {
"always_enabled": true,
"prefix": " "
"always_enabled": true
}
},
{
@ -96,7 +95,6 @@
"foreground": "#FFD700",
"background": "#86BBD8",
"properties": {
"prefix": " ",
"postfix": "",
"root_icon": "⚡"
}
@ -118,11 +116,7 @@
"trailing_diamond": "\uE0B4",
"invert_powerline": true,
"foreground": "#ffffff",
"background": "#33658A",
"properties": {
"prefix": " ",
"postfix": " "
}
"background": "#33658A"
}
]
},

View file

@ -16,7 +16,6 @@
"foreground": "#fff",
"background": "#003543",
"properties": {
"prefix": " ",
"windows": "\uF179",
"postfix": ""
}
@ -105,9 +104,9 @@
"background": "#0087D8",
"properties": {
"prefix": " \uE235 ",
"display_version": false,
"display_mode": "context",
"display_virtual_env": true
"fetch_virtual_env": true,
"template": "{{ .Venv }}"
}
},
{

View file

@ -91,9 +91,9 @@
"background": "#FFDE57",
"properties": {
"prefix": " \uE235 ",
"display_version": true,
"display_mode": "files",
"display_virtual_env": false
"fetch_virtual_env": false,
"template": "{{ .Full }}"
}
},
{

View file

@ -16,7 +16,6 @@
"leading_diamond": "\uE0B6",
"trailing_diamond": "\uE0B0",
"properties": {
"prefix": " ",
"wsl": "",
"wsl_separator": ""
},
@ -59,7 +58,6 @@
"fetch_stash_count": true,
"fetch_status": true,
"fetch_upstream_icon": true,
"prefix": " ",
"template": "{{ .UpstreamIcon }}{{ .HEAD }}{{ if .Staging.Changed }} \uF046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \uF692 {{ .StashCount }}{{ end }}"
},
"style": "powerline",

View file

@ -59,7 +59,6 @@
"style": "mixed",
"home_icon": "\uf7dd ",
"prefix": "",
"postfix": " ",
"enable_hyperlink": true
}
},

View file

@ -41,7 +41,6 @@
"foreground": "#DCB977",
"properties": {
"template": "\uF119",
"prefix": " ",
"postfix": ""
}
},

View file

@ -13,7 +13,6 @@
"foreground": "#0077c2",
"background": "#fbfbfb",
"properties": {
"postfix": " ",
"macos": "\uEF179",
"windows": "\uF17A",
"linux": "\uF17C",
@ -87,7 +86,6 @@
"style": "plain",
"foreground": "#FFD54F",
"properties": {
"prefix": " ",
"text": "{{if .Root}}#{{else}}${{end}}",
"postfix": ""
}

View file

@ -69,9 +69,9 @@
"foreground": "#4584b6",
"properties": {
"prefix": "| \uE235 ",
"display_version": false,
"display_mode": "context",
"display_virtual_env": true
"fetch_virtual_env": true,
"template": "{{ .Venv }}"
}
},
{

View file

@ -82,7 +82,6 @@
"foreground": "#d6deeb",
"background": "#575656",
"properties": {
"postfix": " ",
"threshold": 0,
"style": "roundrock"
}

View file

@ -39,8 +39,7 @@
"style": "plain",
"foreground": "#DCB977",
"properties": {
"template": "\uF119",
"prefix": " "
"template": "\uF119"
}
}
]

View file

@ -14,7 +14,6 @@
"foreground": "red",
"properties": {
"prefix": "",
"postfix": " ",
"root_icon": "\uF0E7"
}
},

View file

@ -26,8 +26,7 @@
"foreground": "#26C6DA",
"background": "#546E7A",
"properties": {
"style": "full",
"postfix": " "
"style": "full"
}
},
{

View file

@ -30,8 +30,7 @@
"background": "#0000ff",
"powerline_symbol": "\uE0B4",
"properties": {
"style": "full",
"postfix": " "
"style": "full"
}
},
{
@ -41,7 +40,6 @@
"background": "#D4E157",
"powerline_symbol": "\uE0B4",
"properties": {
"prefix": " ",
"template": "{{ .HEAD }}"
}
}

View file

@ -95,9 +95,9 @@
"background": "#FFDE57",
"properties": {
"postfix": " \uE235 ",
"display_version": true,
"display_mode": "files",
"display_virtual_env": false
"fetch_virtual_env": false,
"template": "{{ .Full }}"
}
},
{
@ -172,7 +172,6 @@
"background": "#000000",
"background_templates": ["{{ if gt .Code 0 }}#cc2222{{ end }}"],
"properties": {
"prefix": " ",
"always_enabled": true,
"template": "{{ if gt .Code 0 }}{{ .Text }}{{ else }}✔{{ end }}"
}

View file

@ -40,7 +40,6 @@
"foreground": "#BF616A",
"properties": {
"template": "\u2717",
"prefix": " ",
"postfix": ""
}
}

View file

@ -18,9 +18,7 @@
"foreground": "#ffffff",
"properties": {
"wsl": "",
"wsl_separator": "",
"prefix": " ",
"postfix": " "
"wsl_separator": ""
}
},
{
@ -42,8 +40,7 @@
"max_depth": 2,
"folder_icon": "\uF115",
"folder_separator_icon": " \uE0B1 ",
"style": "agnoster_short",
"postfix": " "
"style": "agnoster_short"
}
},
{

View file

@ -18,9 +18,7 @@
"foreground": "#EF7D00",
"properties": {
"wsl": "",
"wsl_separator": "",
"prefix": " ",
"postfix": " "
"wsl_separator": ""
}
},
{

View file

@ -1240,19 +1240,10 @@
"properties": {
"properties": {
"properties": {
"display_version": {
"$ref": "#/definitions/display_version"
},
"display_default": {
"fetch_virtual_env": {
"type": "boolean",
"title": "Display Default Env",
"description": "Show the name of the virtualenv when it's default (`system`, `base`)",
"default": true
},
"display_virtual_env": {
"type": "boolean",
"title": "Display Virtual Env",
"description": "Show the name of the virtualenv or not",
"title": "Fetch Virtual Env",
"description": "Fetch the name of the virtualenv or not",
"default": true
},
"display_mode": {
@ -1263,6 +1254,9 @@
},
"enable_hyperlink": {
"$ref": "#/definitions/enable_hyperlink"
},
"template": {
"$ref": "#/definitions/template"
}
}
}

View file

@ -17,7 +17,6 @@
"foreground": "#fff",
"background": "#003543",
"properties": {
"prefix": " ",
"windows": "\uE62A ",
"postfix": ""
}

View file

@ -46,7 +46,6 @@
"foreground": "#68a063",
"properties": {
"display_version": true,
"prefix": " ",
"postfix": "",
"display_mode": "files",
"display_package_manager": true,
@ -61,7 +60,6 @@
"properties": {
"display_version": true,
"display_mode": "files",
"prefix": " ",
"postfix": ""
}
},
@ -71,7 +69,6 @@
"foreground": "#DE3F24",
"properties": {
"display_version": true,
"prefix": " ",
"postfix": "",
"display_mode": "files"
}
@ -81,11 +78,10 @@
"style": "plain",
"foreground": "#FED142",
"properties": {
"display_virtual_env": false,
"display_version": true,
"prefix": " ",
"fetch_virtual_env": false,
"postfix": "",
"display_mode": "context"
"display_mode": "context",
"template": "{{ .Full }}"
}
},
{