diff --git a/internal/quickstart/choose_sdk.go b/internal/quickstart/choose_sdk.go index 22ca5233..58d8d25e 100644 --- a/internal/quickstart/choose_sdk.go +++ b/internal/quickstart/choose_sdk.go @@ -94,11 +94,12 @@ func (m chooseSDKModel) View() string { } type sdkDetail struct { - canonicalName string - displayName string - index int - kind string - url string // custom URL if it differs from the other SDKs + canonicalName string + displayName string + index int + kind string + url string // custom URL if it differs from the other SDKs + hasInstructions bool // to remove when we get all instructions loaded } func (s sdkDetail) FilterValue() string { return "" } @@ -106,7 +107,7 @@ func (s sdkDetail) FilterValue() string { return "" } var SDKs = []sdkDetail{ // {canonicalName: "react", displayName: "React", kind: clientSideSDK}, {canonicalName: "node-server", displayName: "Node.js (server-side)", kind: serverSideSDK}, - {canonicalName: "python", displayName: "Python", kind: serverSideSDK}, + {canonicalName: "python", displayName: "Python", kind: serverSideSDK, hasInstructions: true}, {canonicalName: "java", displayName: "Java", kind: serverSideSDK}, {canonicalName: "dotnet-server", displayName: ".NET (server-side)", kind: serverSideSDK}, {canonicalName: "js", displayName: "JavaScript", kind: clientSideSDK}, diff --git a/internal/quickstart/container.go b/internal/quickstart/container.go index 26fbf5f3..66da3dc7 100644 --- a/internal/quickstart/container.go +++ b/internal/quickstart/container.go @@ -88,6 +88,7 @@ func (m ContainerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.sdk.displayName, m.sdk.url, m.flagKey, + m.sdk.hasInstructions, ) cmd = m.currentModel.Init() } @@ -103,6 +104,7 @@ func (m ContainerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { msg.sdk.displayName, msg.sdk.url, m.flagKey, + msg.sdk.hasInstructions, ) cmd = m.currentModel.Init() m.sdk = msg.sdk diff --git a/internal/quickstart/messages.go b/internal/quickstart/messages.go index 27c1d0ce..36be5bfd 100644 --- a/internal/quickstart/messages.go +++ b/internal/quickstart/messages.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "net/http" + "os" tea "github.com/charmbracelet/bubbletea" @@ -134,6 +135,17 @@ func sendFetchSDKInstructionsMsg(url string) tea.Cmd { } } +func sendReadSDKInstructionsMsg(filename string) tea.Cmd { + return func() tea.Msg { + content, err := os.ReadFile(fmt.Sprintf("internal/sdks/sdk_instructions/%s.md", filename)) + if err != nil { + return errMsg{err: err} + } + + return fetchedSDKInstructions{instructions: content} + } +} + type showToggleFlagMsg struct{} func sendShowToggleFlagMsg() tea.Cmd { diff --git a/internal/quickstart/show_sdk_instructions.go b/internal/quickstart/show_sdk_instructions.go index 2ffe4637..668d8d80 100644 --- a/internal/quickstart/show_sdk_instructions.go +++ b/internal/quickstart/show_sdk_instructions.go @@ -18,18 +18,19 @@ const ( ) type showSDKInstructionsModel struct { - accessToken string - baseUri string - canonicalName string - displayName string - flagKey string - help help.Model - helpKeys keyMap - instructions string - sdkKey string - spinner spinner.Model - url string - viewport viewport.Model + accessToken string + baseUri string + canonicalName string + displayName string + flagKey string + help help.Model + helpKeys keyMap + instructions string + hasInstructionsFile bool // TODO: remove when we have all instructions saved + sdkKey string + spinner spinner.Model + url string + viewport viewport.Model } func NewShowSDKInstructionsModel( @@ -39,6 +40,7 @@ func NewShowSDKInstructionsModel( displayName string, url string, flagKey string, + hasInstructionsFile bool, ) tea.Model { s := spinner.New() s.Spinner = spinner.Points @@ -48,7 +50,6 @@ func NewShowSDKInstructionsModel( BorderStyle(lipgloss.RoundedBorder()). BorderForeground(lipgloss.Color("62")). PaddingRight(2) - vp.MouseWheelEnabled = true return showSDKInstructionsModel{ accessToken: accessToken, @@ -61,16 +62,23 @@ func NewShowSDKInstructionsModel( Back: BindingBack, Quit: BindingQuit, }, - spinner: s, - url: url, - viewport: vp, + spinner: s, + url: url, + viewport: vp, + hasInstructionsFile: hasInstructionsFile, } } func (m showSDKInstructionsModel) Init() tea.Cmd { + // to remove when we have all instruction files loaded + instructionsCmd := sendFetchSDKInstructionsMsg(m.url) + if m.hasInstructionsFile { + instructionsCmd = sendReadSDKInstructionsMsg(m.canonicalName) + } + return tea.Sequence( m.spinner.Tick, - sendFetchSDKInstructionsMsg(m.url), + instructionsCmd, sendFetchEnv(m.accessToken, m.baseUri, defaultEnvKey, defaultProjKey), ) } @@ -118,7 +126,6 @@ func (m showSDKInstructionsModel) View() string { func (m showSDKInstructionsModel) renderMarkdown() (string, error) { renderer, err := glamour.NewTermRenderer( glamour.WithAutoStyle(), - glamour.WithWordWrap(viewportWidth), ) if err != nil { return "", err diff --git a/internal/sdks/sdk_instructions/python.md b/internal/sdks/sdk_instructions/python.md new file mode 100644 index 00000000..84c3f1f7 --- /dev/null +++ b/internal/sdks/sdk_instructions/python.md @@ -0,0 +1,57 @@ +# Set up your application + +If you want to skip ahead, the final code is available in our [GitHub repository](https://github.com/launchdarkly/hello-python). + + +1. Create a new directory: + +```bash +mkdir hello-python && cd hello-python +``` + +2. Next, create a file called `requirements.txt` with the SDK dependency and install it: + +```bash +echo "launchdarkly-server-sdk==9.3.1" >> requirements.txt && pip install -r requirements.txt +``` + +3. Create a file called `test.py` and add the following code: + +```python +# Import the LaunchDarkly client. +import ldclient +from ldclient import Context +from ldclient.config import Config + +# Create a helper function for rendering messages. +def show_message(s): + print("*** {}".format(s)) + print() + +# Initialize the ldclient with your environment-specific SDK key. +if __name__ == "__main__": + ldclient.set_config(Config("1234567890abcdef")) + +# The SDK starts up the first time ldclient.get() is called. +if ldclient.get().is_initialized(): + show_message("SDK successfully initialized!") +else: + show_message("SDK failed to initialize") + exit() + +# Set up the evaluation context. This context should appear on your LaunchDarkly contexts +# dashboard soon after you run the demo. +context = Context.builder('example-user-key').name('Sandy').build() + +# Call LaunchDarkly with the feature flag key you want to evaluate. +flag_value = ldclient.get().variation("my-flag-key", context, False) + +show_message("Feature flag 'my-flag-key' is {} for this user".format(flag_value)) + +# Here we ensure that the SDK shuts down cleanly and has a chance to deliver analytics +# events to LaunchDarkly before the program exits. If analytics events are not delivered, +# the user properties and flag usage statistics will not appear on your dashboard. In a +# normal long-running application, the SDK would continue running and events would be +# delivered automatically in the background. +ldclient.get().close() +``` \ No newline at end of file