Code Monkey home page Code Monkey logo

palm-cli's Introduction

Palm CLI: The extensible CLI at your fingertips

Palm is a universal CLI developed to improve the life and work of data professionals.

Palm CLI documentation

Installing Palm

pip install palm

note for mac users: if you get this warning:

  WARNING: The script palm is installed in '/Users/yourname/Library/Python/3.8/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.

you will need to add '/Users/yourname/Library/Python/3.8/bin' to your path for palm to work.

you can do that with this command:

echo "\nexport PATH=$PATH:/Users/yourname/Library/Python/3.8/bin\n" >> ~/.zprofile

Upgrading palm

To upgrade palm to the latest version, use pip install palm -U

Requirements

  1. You will need Docker You can check to see if you already have it with docker --version

  2. You will need Python3 You can check to see if you already have it with python3 --version

Developing palm

If you have the repo on your computer This will install whatever version you have checked out at the moment.

cd path/to/this/repo &&
python3 -m pip uninstall palm || true # for new installs
python3 -m pip install .

You can verify the install with

palm --help

palm-cli's People

Contributors

cgaunt-palmetto avatar charliesu avatar emekdahl-palmetto avatar emilypastewka avatar ethanknox-palmetto avatar jakeberesford-palmetto avatar mariahjrogers avatar norton120 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

palm-cli's Issues

Exclude/disable commands via config

Context
Palm commands come from many places. Core, plugins, the repository... and that list is growing!
Some of those commands are useful maybe one time (palm containerize). The rest of the time, those commands are clutter in palm --help.
Some commands may also just not work in your project - for example palm lint which uses the black library to lint python will not work in a javascript project. Ideally, palm lint is overridden by a command that does work. However, in the event that linting is not implemented, a developer on that project should be able to disable that command entirely.

Is your feature request related to a problem? Please describe.
When I'm working in an established palm project, I do not want to see irrelevant, or un-useful commands in palm help.

Describe the solution you'd like
Allow each project to specify plugins to exclude via palm config. E.g.

disable_commands:
- containerize
- init
- lint

Describe alternatives you've considered

  • One-time use commands could potentially be disabled with logic (e.g. is this project already containerized?) however that does not scale well and will not solve the need to disable a command due to incompatibility (e.g. the linting example)

Is there an existing feature request for this?

  • I have searched the existing issues

Support Modern Docker Compose

Context
Palm only supports the now deprecated docker-compose command, it should support v2 of docker/compose using the docker compose command.

Is your feature request related to a problem? Please describe.

$ docker compose version
Docker Compose version v2.17.3
$ palm test
Docker Compose is not installed, please install it first

Describe the solution you'd like
Support docker compose (with backwards compatibility for those still using docker-compose?)

Describe alternatives you've considered

# /usr/bin/docker-compose
docker compose $@

Additional context
nope

Is there an existing feature request for this?

  • I have searched the existing issues

Parameterized docker .env variables no longer auto-populate

Describe the bug
Parameterized variables in docker file do not populate as env vars any longer. This is functionality that used to work.

Your environment

  • palm version: 2.1.0
  • OS: Mac
  • Docker version: Docker version 20.10.10, build b485636, Docker Compose version v2.1.1
  • Other dependencies & versions:

How to reproduce
Build palm docker container with .env. Run the docker container and /bin/bash into it. Use the command printenv. Note that parameterized variables are not present.

Expected behavior
printenv shows parameterized variables in .env

Actual behavior
parameterized variables are not populated (e.g. SNOWFLAKE_USERNAME= )

Screenshots
If applicable, add screenshots to help explain your problem.

Additional context
Add any other context about the problem here.

Palm needs a logo

Context
This project is really cool, and deserves a bit of basic branding. An official logo is as basic as that gets I think.

Describe the solution you'd like
A single logo with all the fixins. this should probably live in an assets folder in the docs section for now, with the logo itself released under a unique license. Maybe follow Python's example.

Describe alternatives you've considered

  • Not having a logo. This is fine, but would be better with one.

Additional context

  • the team has played with kind of a retro-80s-synthwave-palm-tree look, and that has been interesting. But really open to any ideas that feel right for the tool.

Is there an existing feature request for this?

  • I have searched the existing issues

support `exec` commands

Context
if your project uses persistent containers, palm can't exec them. womp.

Is your feature request related to a problem? Please describe.
it's totally reasonable to architect projects from scratch to always use new run instances. but sometimes you really might need to exec a running instance - OR it just might be a better pattern that makes more sense

Describe the solution you'd like
context.obj has run_in_docker
it would be cool if it also had exec_in_docker so you could palm up and then palm migrate which runs exec commands on the container from the up command.

Describe alternatives you've considered
re-architect the project to use only run commands, but there are some things that just isn't going to work for I don't think.

Is there an existing feature request for this?

  • I have searched the existing issues

move from "docker" to "container" to prepare for podman support

Context
Palm relies on containerization. Presently that has been 100% via Docker, but we'd like to expand the ecosystem to a fully OSS offering.

Is your feature request related to a problem? Please describe.
Docker is not OSS and there are limitations, and the learning curve for a thing like podman is not steep but does exist.
We want to make the switch painless for our users, and we can start by abstracting "Docker" command aliases in palm to "container" commands. then under the hood we can run in the container engine of the user's choice.

Describe the solution you'd like
run_in_docker becomes run_in_container. Then under the hood we pipe the work to Docker, OR have the ability to use podman instead.

Describe alternatives you've considered
Stick with pure Docker support. Meh.

Additional context
This can start by abstraction and then balancing 100% of requests to a Docker mechanics class for now. That way we can roll podman as seperate work.

Is there an existing feature request for this?

  • I have searched the existing issues

run_on_host defaults to capture_output

Describe the bug
The first pass at run_on_host was overly aggressive with capture_output (and the older equivalent piping stdout and stderr)
as a result, nothing using run_on_host plays live on stdout. which is bad.

Your environment

  • palm version: 2.0.1
  • OS: Macos
  • Docker version: 20.10.6
  • Other dependencies & versions:

How to reproduce
Run something that used to display live logs, like palm run in a dbt project.
instead of the logs streaming into your terminal, the operation sits quietly and waits until it is done :(

Expected behavior
For most things we actually do not want to capture the output, and we want to let it stream.

Actual behavior
Default is to silently wait (blocking) and dump stdout and stderr into a tuple

Additional context
Maybe the answer here is to make run_on_host have the exact same interface as the latest subprocess.run (with capture_output and check args). then fix all the places I broke by matching the signature of run_on_host to the signature of subprocess.run in the current release. that way palm and downstream will work exactly the way it did before.

image inference from docker-compose, with multi-image support

Context
Lots of projects are complex and use more than one image. this is where palm could shine, if it supported multiple images

Is your feature request related to a problem? Please describe.
let's say I have a rails app. I've got a rails container, a postgres container, an nginx static file serve etc all in the local.
sometimes I want to run the rails test suite in the rails_app container. sometimes I want to force compile my static files in the static_server container. I need more than one.

Describe the solution you'd like
A well-documented heuristic. palm finds and parses the docker-compose, loading all the images into the context. the default is the first image in the file. setting a different default in the config changes that. Now in the context I can specify an override image name from the context, or leave it blank to use the default.
This also speeds up fails because we can parse the image list before running the docker command and short-circuit if it is not a valid image name.

Describe alternatives you've considered

  • refactoring projects into a mono image, which is awful.
  • shelling out and hand writing the compose, which is fine but takes away a LOT of palm magic

Is there an existing feature request for this?

  • I have searched the existing issues

more friendly + consistent interface for utilities

Context
Like all good software, palm functionality is made up of a lot of different tools under the hood. things like click and subprocess. I would give us a really valuable abstraction layer if palm was the single interface to these tools, so we can manage how they play together under the hood, and protect our user's command code from becoming brittle.

Is your feature request related to a problem? Please describe.
I worry about calling interfaces like click.secho directly where it clutters the interface, and makes it so we can't upgrade click past breaking versions. let's say click changes the arity in the next version, and we really want to use that version... we can't. not without breaking all our user's existing commands.

Describe the solution you'd like
All these utilities get migrated into palm as thin, highly opinionated wrappers.
same use case:

from palm.helpers import success_message, fail_message

...
success, msg = ctx.obj.run_in_docker(cmd, env_vars)
delivery = success_message if success else fail_message
delivery(msg)

# in palm/helpers.py
def success_message(msg:str): -> str
    return click.secho(msg, fg="green")

then when click decides to deprecate "fg" for "color_name" we can make the fix internally.

Describe alternatives you've considered
keep things pushed to the edge as they are. not as exciting.

Is there an existing feature request for this?

  • I have searched the existing issues

alias ctx.obj into ctx

Context
While the interface is still young we could consider simplifying it for readability.
since this API is a core user interface for palm we probably want it as reads-like-english as possible.

Describe the solution you'd like
We could potentially capture the context at top level, then monkeypatch __getattribute__ to make obj the final lookup path.
so it would look something like this:

class PalmContext(Context):
    def __getattribute__(self, attr):
        try: 
            return Context.__getattribute__(self, attr)
        except Exception as parent_exception: 
            try:
                 return self.obj.__getattribute__(self.obj, attr)
            except:
                raise parent_exception

then the interface would be

def some_command(context):
    context.run_in_docker("thing")

Describe alternatives you've considered
it would be trivial to just alias ctx.obj in the template, and that might actually be better for reasons stated below.

Additional context
Naming collisions would suck here. this is the kind of magic that makes OOP great. It's also the kind of magic that makes functional programmers hate OOP if something goes wrong here.

Is there an existing feature request for this?

  • I have searched the existing issues

Githook for ReadTheDocs

Context
ReadTheDocs can automagically deploy when we do via a githook. we should do that.

Is your feature request related to a problem? Please describe.
Right now we deploy, then need to remember to manually go to RTD and push the build button :(

Describe the solution you'd like
When we deploy, the githook fires and RTD builds.

Describe alternatives you've considered
Keep pushing the button.

Additional context
Whoever does this will need RTD project and repo maintainer access.

Is there an existing feature request for this?

  • I have searched the existing issues

Create a "command builder" that allows chaining w/ error handling inbetween

Context
Palm currently requires manual-ish command creation with strings which get passed to the container/host runner. We need a smart way for command chaining to occur so users aren't limited to a single command-line execution for their custom commands.

Is your feature request related to a problem? Please describe.
We currently have composite commands chain together with "&&", which requires every step in the command to complete successfully in order for the rest of the steps to run at all. This is a bug for palm-dbt (detailed in #17) because idempotency of dev/CI environments requires cleanup to execute regardless of model execution failure or success.

Describe the solution you'd like
Writing palm commands would be done through a palm library function for command building that provides chaining and the ability to handle errors. This would streamline development of new commands with repeated steps because you could simply chain together a set of existing commands in the desired execution order. Interface for a new command wouldn't appear as eg. dbt clean && dbt deps && dbt run && dbt test && dbt run-operation drop_branch_schemas. Instead, each command would be stored in a queue of some kind and executed one by one, with customization for whether a failure is raised to the process or handled, and customizable behavior depending on whether the preceding step succeeded or failed.

Why? Because a one-size-fits-all approach bakes in a lot of our opinionated processes. Since I work most in dbt, I'll focus on that use-case. Palm-dbt has an extremely prescriptive approach to dbt runs, which is fine for now, but most certainly doesn't feel scalable, and does feel brittle. Every command in the plugin has repeated code inside it (dbt clean && dbt deps && dbt seed --full-refresh && ... run-operation drop_branch_schemas) and there are bugs in the way commands execute (like the example mentioned above).

Chaining commands would allow us to specify how each piece of our completed command works independently. Then, you can chain them together safely with the confidence that it will just work. Users of plugins can use the building blocks of all the pieces that exist, with the ability to chain them together in different orders, with different default behavior, without reinventing the whole wheel.

Eg. new functionality for palm cycle inside a dbt project, utilizing palm-dbt:

def dbt_run(..., raise_error=False):
    try:
        result = run_in_docker('dbt run')
    except model_build_failures:
        if raise_error == True:
            raise model_build_failures
    return result
...
# palm cycle
def cli(count=2):
    cmd = palm.command_builder()
    cmd.add(dbt_clean)
    cmd.add(dbt_deps)
    while count > 0:
        cmd.add(dbt_run)
        cmd.add(dbt_test, depends_on_previous=True)
        count -= 1
    cmd.add(dbt_cleanup, raise_error=True)
    cmd.execute() # execution of all commands in the builder in above order

And the interface for a user running the command:

$ palm cycle 1
Executing `dbt clean`...
Clean as a whistle!
Executing `dbt deps`...
All dependencies installed!
Executing `dbt run`...
Oops, some models failed to build. Skipping test...
`dbt test` skipped due to model build failures
Executing `dbt run-operation drop_branch_schemas`...
Schema `test.mrogers_test_new_feature_01993049` cleaned up.

Then, a user of palm-dbt decides they want dbt test to run even if dbt run has model failures. They override palm cycle with their own command, changing only one line from our version:

def cli(count=2):
    cmd = palm.command_builder()
    cmd.add(dbt_clean)
    cmd.add(dbt_deps)
    while count > 0:
        cmd.add(dbt_run)
        cmd.add(dbt_test)
        count -= 1
    cmd.add(dbt_cleanup, raise_error=True)
    cmd.execute()
$ palm cycle
Executing `dbt clean`...
Clean as a whistle!
Executing `dbt deps`...
All dependencies installed!
Executing `dbt run`...
Oops, some models failed to build.
Executing `dbt test`...
Oops, some tests failed!
Executing `dbt run-operation drop_branch_schemas`...
Schema `test.mmoulds_test_another_feature_01856927` cleaned up.

Describe alternatives you've considered
Option: Keep things as they are.
Pros: This is simple for users writing new commands because they only have to think about how to execute code exactly as they would do it in the terminal. Single step commands are straightforward because they only require one execution. Advanced users can make use of our initial progress in this direction with our dbt_palm_utils functions, or the way palm cycle is implemented with a make_cmd() function.
Cons: Usefulness of these existing functions is limited because they are currently only available in palm-dbt; commands aren't reusable with library functions, so there's a lot of repeated code. Commands are built as strings concatenated together before being passed to the host/container runners, which is very brittle and prone to introducing bugs, since the interpreter can't identify bugs in the commands.

Option: Break all existing commands apart at the "&&" and run them in sequence with separate run_in_docker calls.
Pros: Better for error handling.
Cons: No clean way for modular, reusable commands to exist because each call to the runner will still execute independently and commands still won't have a library function interface.

Additional context
This feels awkwardly like trying to implement workflow orchestration. If using an existing orchestrator inside palm were an option, I would totally go with doing that as long as it is as platform agnostic as palm currently is. Otherwise, I think we could still do this simply enough that would provide a ton of value.

Is there an existing feature request for this?

  • I have searched the existing issues

pull subprocess into obj commands

Context
Calling subprocess directly is messy. plus subprocess has breaking changes from python3.7 and up. And as a palm user, I really want a single interface for all palm commands in one place.

Is your feature request related to a problem? Please describe.
when I'm building out commands I not only need to know the palm interface, I need to know the subprocess one.
most of the time I want a simple set of subprocess defaults, so let's provide them.

Describe the solution you'd like
ctx.obj has a run_on_the_metal method, with as close to the run_in_docker API as possible, and really opinionated defaults.
If a user needs something more complex they can import subprocess themselves ;)

Describe alternatives you've considered
keep using subprocess

Additional context
To support older Pythons we will need to use conditional calls to Subprocess - so abstracting this is a really good idea.

Is there an existing feature request for this?

  • I have searched the existing issues

Plugin scaffold should protect against bad naming ("palm-" prefix, special chars)

Describe the bug

This is really a feature, but feels like a bug when it's happening - so I'm calling it a bug first so others will be able to easily find the issue when it happens to them.

TLDR new plugin names need to not be prefixed with palm- and be valid python class names.

I wasn't clear on if my plugin should be named palm-git or git -even though the docs and help make it pretty clear. So I screwed that up and had to handhttps://github.com/palmetto/palm-cli/discussions-hack a lot of files to get it working.
This isn't absolutely a bug but it is pretty very un-intuitive I think, and would be a solid fit to encourage contribution.
Closely related, we create classnames from this name value - so we need to enforce that they are valid python.
you can't have special chars in there etc etc.

Your environment

  • palm version: 2.1.0
  • OS: Ubuntu 18.04
  • Docker version: Docker version 20.10.10, build b485636
  • Other dependencies & versions:

How to reproduce
use palm plugin new --name
think about the name for 10 minutes, decide it should match the folder and call it palm-whatever
spend a long time finding and deleting the palm prefixes from everything.

Expected behavior
remove palm- prefix from passed names, so people can make the mistake and we correct it for them. yell and abort when the formatted name is not valid python.
OR
always yell when the name is not valid python, and make it clear you don't need the palm prefix.

Actual behavior
Lots and lots of bad naming that needs to be manually corrected.

Autodocs

Context
Our rtd documentation does not have code docs. Since we use Google Python heredocs, we can support autodocumentation generation.

Is your feature request related to a problem? Please describe.
Right now the only way to see the interface to palm is to read the code directly :(

Describe the solution you'd like
Autodocs are built automatically from the code heredocs in our rtd documentation. Probably use Napoleon for compiling, and sensible settings (don't expose private methods, constants etc etc).

Describe alternatives you've considered
Manually building code docs.. why?

Additional context
We may also want a simple "cheat sheet" that is manually maintained and parsed from these. But real autodocs are huge.

Is there an existing feature request for this?

  • I have searched the existing issues

Deprecate `palm scaffold config` error message

Describe the bug
Running any palm command before a local project has been initialized (palm init) displays the old error message encouraging users to run the deprecated palm scaffold config command to generate the config file.

Your environment

  • palm version: 2.5.3
  • OS: Mac
  • Docker version: 24.0.1
  • Other dependencies & versions:

How to reproduce
Run palm --help in a new project folder before palm init has been run.

Expected behavior
An error message that suggests initializing the project with palm init

Actual behavior
An error message that suggests running palm scaffold config

Screenshots

Additional context

Bash and / or Zsh completion

Context
What are you trying to do and how would you want to do it differently? Is it something you currently cannot do?

I want to have the same bash / zsh completion when I shell in using docker that I would on my local

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

I want to run commands as fast as I can on my local dbt project outside of docker and have access to the history

Describe the solution you'd like
A clear and concise description of what you want to happen.

Something like this in the docker file? This is just an inspiration not an implementation.

RUN echo 'source /usr/share/bash-completion/bash_completion' >> /etc/bash.bashrc

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

Is there an existing feature request for this?

  • I have searched the existing issues

palm new-machine && palm-clone

Context
We are actually 2 steps away from palm being a complete instant-dev solution. think about it....

You start at Bluth's Bananastand co on a Monday. The onboarding box arrives with your brand new Mac/PC/Linux laptop, and a single post-it note on the box:

    Welcome to the team Pat! to get started (from the command line): 
    1. pip install palmcli 
    2. palm new-machine
    3. palm clone git@github:bluth-bananastand/banangrabber.git

    run `palm --help` if you have any questions.
    Please try to have jira issue NANA-123 done before lunch, it's a 1 point naming fix ;) Excited to have you aboard! 

Is your feature request related to a problem? Please describe.
There are still a few manual steps outside palm. this eliminates them.

Describe the solution you'd like

  1. Open up my brand new Mac, PC or Linux laptop.
  2. Power it on
  3. open the CLI, run palm new-machine
  4. Now the magic:
    • palm checks the OS, checks for docker, and installs the correct docker (or at least opens the browser dialog to do so)
    • palm prompts you to select a git repo provider (github & bitbucket are good intial options)
    • palm (generates if needed and) installs your ssh key into your gh/bb account

palm announces that you are ready to begin work! now to get started:

  1. cd into the directory you want your repos in
  2. use the palm clone command to add the repo palm clone [email protected]:your-company/some-repo-with-palm.git
    • palm clones the repo like normal git
    • palm looks for a .env file and parses it for expected environment variables (i.e. BANANA=${BANANA}
    • for each found environment variable, it checks to see if that is already exported into your path.
      • if it is, palm announces it ("found environment variable BANANA, skipping")
      • at the end of the cycle, it prompts you with a list of envars it needs ("repo banana_grabber requires the following environment variables: BANANA_USERNAME, BANANA_API_KEY, BANANA_HOST. proceed? (y/n):")
      • palm then sets each variable for the os (so .zshrc or .bashrc for unix, win sys envs for windows)
      • bonus we could make it super easy to set a custom message with the envars message in the palm file, like "if you do not have a BANANA_USERNAME yet, contact core systems at [email protected] and request one."

Describe alternatives you've considered
Manual documentation. which is fine. but not magic. This is amazing magic.

Additional context
This should be broken into implementation slices; each part has value on its own (ie palm new-machine and palm-clone)

Is there an existing feature request for this?

  • I have searched the existing issues

Use @pass_obj instead of @pass_ctx

Context
We use the click context heavily in palm commands since this is how we access the Environment for core functions like run_in_docker. The syntax is a little awkward as we have to access the Enviornment via ctx.obj, which is a click convention. We can improve the readability of our code by changing the implementation to use @pass_obj instead, and naming the first arg environment - this makes reasoning about how commands work much more clear for users who are unfamiliar with click.

Is your feature request related to a problem? Please describe.
ctx.obj.run_in_docker is a little mysterious enviornment.run_in_docker is more clear.

Describe the solution you'd like

  • Update all core commands to use pass_obj
  • rename arg ctx -> `environment
  • Update uses of ctx.obj -> environment

Describe alternatives you've considered

  • Click also has make_pass_decorator which could allow us to @pass_environment, but since the Environment constructor has required arguments, this will not work
  • Once we implement palm.decorators, we will likely add our own decorator for @pass_environment which would work in much the same way as @pass_obj, this issue is one step in that direction

Additional context
I have tested this and confirmed it works as described.

Is there an existing feature request for this?

  • I have searched the existing issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.