Giter Club home page Giter Club logo

Comments (8)

bitprophet avatar bitprophet commented on August 18, 2024

After thinking a bit I only see the following options:

  • Use partial as in description, either per-file (which could get annoying for folks with nontrivial task modules) or some sort of silly at-runtime mutation of the "real" callables (really don't want to do this and it didn't even work when I tested it).
  • Use a Runner class that can be instantiated with config options, then e.g. runner.run(xxx).
    • Probably the cleanest approach
    • Makes the "DSL" more verbose, requires both setup/pass-around (of instance) boilerplate, plus just a longer call
    • May pave the way for nigh inevitable Fabric API of e.g. Host().run("remote cmd")
  • Suck it up, use threadlocal globals or whatever.

Still need to research state of the art tho. But suspect the class is the way to go. Bye bye cutesy DSL.

from invoke.

bitprophet avatar bitprophet commented on August 18, 2024

Hadn't been considering the specifics of how the config data gets into Runner and friends, but:

  • Something needs to load the conf file from disk
    • And merge it with CLI options, if invoked by CLI
  • This loaded result has to be stored somewhere
  • Then referenced anytime one creates one of these classes

My suspicion is that in the CLI driven use case, we would build the config, then pass it into each task when the task is executed (thus requiring tasks to always have some initial argument, at which point it's effectively just like a method on a class where that argument is self).

In library use users would be responsible for loading their own config and then doing the same handoff to tasks whenever they get executed.

from invoke.

bitprophet avatar bitprophet commented on August 18, 2024

Kenneth mentioned how Requests has a similar setup, albeit via a dual API:

  • get()
  • Session(defaults).get()

This is a lot like what I had in mind originally for the Fabric2 level stuff, except the "unqualified" API would still be able to refer to a threadlocal or similar (probably not by default tho) whereas in Requests it's largely about ability to set defaults.

Which, honestly, is kind of the same here; we could say "if you want the ability to globally tickle defaults, you must call methods on an instantiated class. Users with simple needs can still use the API calls directly if they prefer it, users who want to "hook in" can call the method version.

from invoke.

bitprophet avatar bitprophet commented on August 18, 2024

MOAR COMMENTZ

Think the way to go is really what I had in mind before:

  • Core API is method calls on objects, so for the run-echo use case, maybe runner = Runner(config); runner.run() as above.
    • Figure out what sort of class/entity name would be extensible for Fab stuff too, i.e. what object like this would Host or HostCollection inherit from? Use that name.
  • Secondary API is module-level, e.g. runner.run / invoke.run, has default-None context/options kwarg.
    • If context object is None, refer to threadlocal context obj
    • Can optionally pass in a context object directly
    • That object's run method is invoked with our *args/**kwargs`

from invoke.

bitprophet avatar bitprophet commented on August 18, 2024

Thought about this a bunch more recently and started documenting it too.

The tl;dr is that it should look like this:

  • Lowest level and "default" (re: trivial base case) API is wholly functional and simple and totally state-unaware. E.g. the current implementation of run. It offers kwargs controlling all aspects of behavior.
  • To obtain a "modified" run call that can honor configuration state (such as whether to echo commands executed, see #32), call a run method on a settings or context object.
  • Such methods would understand their own, internal state (obtained from the CLI, conf files, or user manipulation) and use that as a guide re: default kwarg values, e.g.:
    • run(cmd): no echo
    • run(cmd, echo=True): echo
    • Context().run(cmd): no echo
    • Context().run(cmd, echo=True): echo
    • Context(echo=True).run(cmd): echo
  • Tasks can opt to be handed a Context object as their 1st argument (which is not taken into account when determining CLI flags) and the CLI module will create and hand one in.
    • This is the key: CLI sees echo flag, creates core Context for statekeeping, with echo on. That Context is what is passed into every "contextualized" task, they all use ctx.run() instead of run(), and presto, echoing occurs.
  • Specific API for how Context holds state related to run and any other methods that pop up, is TBD.
  • Should account for config files too -- some sort of override hierarchy such that it probably boils down to a single namespace
    • Though preserving the various sources for posterity.
  • One question is whether Contexts should be allowed to mutate (thus allowing one task to alter it, then pass the altered copy into another task it calls internally) or if we should try to be functional-like and prefer it be cloned instead.

from invoke.

bitprophet avatar bitprophet commented on August 18, 2024

Have context object being handed around successfully now, omitted from arg parsing, etc etc.

It's an empty object right now, but I will flesh it out as I implement #32. Leaving this open so I ensure it applies to auto-positional + auto-shortflag as subject suggests, once I am done.

from invoke.

bitprophet avatar bitprophet commented on August 18, 2024

#32 implemented, also the rest of the run related arguments. Hooray.

Right now the context object's inner API is very simply, just a .config attribute dict which holds a run subdict whose key/val pairs map to run() kwargs.

It suffices to enable CLI-flag-driven config, but should get cleaned up for code-level config, and documented.

from invoke.

bitprophet avatar bitprophet commented on August 18, 2024

Documented things a bit better, not bothering with anything deeper than the __init__ API (it's not like giving Context(run={'default': 'kwargs'}) is that ugly an API) for the time being.

from invoke.

Related Issues (20)

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.