Skip to content

Commit

Permalink
feat(python): virtual env in template
Browse files Browse the repository at this point in the history
  • Loading branch information
JanDeDobbeleer committed Dec 4, 2021
1 parent f495a70 commit 29afb86
Show file tree
Hide file tree
Showing 34 changed files with 233 additions and 159 deletions.
2 changes: 1 addition & 1 deletion docs/docs/segment-python.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
4 changes: 2 additions & 2 deletions src/properties.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
84 changes: 81 additions & 3 deletions src/segment_deprecated.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}
47 changes: 47 additions & 0 deletions src/segment_deprecated_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
8 changes: 4 additions & 4 deletions src/segment_git.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
57 changes: 22 additions & 35 deletions src/segment_language.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,53 +84,40 @@ const (
LanguageExtensions Property = "extensions"
)

func (l *language) string() string {
if !l.props.getBool(DisplayVersion, true) {
return ""
}

err := l.setVersion()
l.Error = err.Error()
displayError := l.props.getBool(DisplayError, true)
if err != nil && displayError {
return err.Error()
}
if err != nil {
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()
}
}

segmentTemplate := l.props.getString(SegmentTemplate, "{{ .Full }}")
template := &textTemplate{
Template: segmentTemplate,
Context: l.version,
Context: context,
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(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
}
Expand Down
19 changes: 7 additions & 12 deletions src/segment_python.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
package main

import "fmt"

type python struct {
language

Venv string
}

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()
}
version := p.language.string()
if version == "" {
return p.Venv
segmentTemplate := p.language.props.getString(SegmentTemplate, "")
if len(segmentTemplate) == 0 {
return p.legacyString()
}
return fmt.Sprintf("%s %s", p.Venv, version)
return p.language.renderTemplate(segmentTemplate, p)
}

func (p *python) init(props properties, env environmentInfo) {
Expand Down Expand Up @@ -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{
Expand Down
59 changes: 36 additions & 23 deletions src/segment_python_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
Expand Down

0 comments on commit 29afb86

Please sign in to comment.