Giter VIP home page Giter VIP logo

Comments (1)

Gorialis avatar Gorialis commented on June 19, 2024

This isn't a bug. Let's discuss why.

I have a set of rules that I follow while designing and developing Jishaku.
While some of these are documented or enforced by circumstance (e.g., 'all code must comply by the pylint/flake8 rules or have commented exceptions in the code, else the CI will fail and the publish process for a new version will fail'), most of the rules I set either by word of mouth or just personally retain as part of my development or design principles.

One of these unspoken design principles is the reason why this behavior isn't a bug. I'll write it out in plain English for reference later, but for now, I'm going to try and see if you can derive what the rule is from a set of examples regarding the design of the REPL components that back AsyncCodeExecutor, and by extension, jsk py and jsk pyi.

A REPL with a little more

Jishaku's design motive is to be a Discord-based frontend for evaluating and executing code.
It takes a lot of inspiration from how the standard Python REPL works - the one you get when you just run python, but simple Python evaluation isn't all Jishaku offers within its environment.

Let's go over some features Jishaku adds, starting from "least obviously magic" to "most obviously magic" (a sort of increasing nonstandardness). I'll also include how it differs from what you'd expect with standard Python, for reference.

Returned values are sent back to Discord

When you execute a block of code that contains a return, the value returned is sent to Discord as a message.
image

The value is interpreted and sent in whatever format is deemed most appropriate. For instance, discord.Embed instances get sent as actual embeds, discord.File instances get uploaded, etc.

This is the "most standard" behavior, because typically all eval or REPL command implementations have some variant of this kind of behavior. Some even have automatic await, but Jishaku doesn't.

What Would Python Do (WWPD)?

Either:

  • nothing (return value ignored)
  • SyntaxError: 'return' outside function

Bare expressions at the end of the top-level scope are sent back to Discord

When you execute a block of code that includes a bare expression at the end that isn't in control flow (such as for, while, if, etc), the value of the expression is sent back to Discord as a message.
image

This follows the same display procedures as returning. It is sometimes referred to as an "implicit return" in old documentation, but this isn't always how it's implemented, as we will soon find out.

What Would Python Do (WWPD)?

  • nothing (expression would be evaluated but nothing else would happen, for basic operations the bytecode may optimize it out - see "Statement seems to have no effect" pointless-statement (W0104) from the pylint documentation)

Yielded values are sent back to Discord

When you execute a block of code that includes yield statements, the yielded values are sent back to Discord as messages.
image

This is similar to the "implicit return", except it doesn't halt execution. This allows data to be sent back easily during longer evals, or in situations where states may have to be read at different times (such as wanting to check the attribute of an object before and after a given function call).

The message is even sent back to the evaluation context from the yield, allowing it to be inspected or edited.
image

What Would Python Do (WWPD)?

Depends on the exact context, but typically:

  • SyntaxError: 'yield' outside function
  • TypeError: object async_generator can't be used in 'await' expression

Yielding and returning values can be mixed.

When you execute a block of code that includes both 'yield' and 'return', they both work and function as expected.
image

While you may not see this as weird, this is actually nonstandard because it is usually not allowed for yield and return (with a value) to both be in an async generator (although it is OK for normal generators to have them).

To deal with this, Jishaku automatically packs out return x into the two separate statements when yields are present:

yield x
return

This allows returning of values to not require the cognitive overhead of checking whether it already contains a yield, as Jishaku makes the transformation for you.

What Would Python Do (WWPD)?

  • SyntaxError: 'return' with value in async generator

Import expressions

When a name is suffixed with an exclamation mark (!), the name is treated as a module and is implicitly imported for direct usage.
image

The module name to be imported can even be a submodule:
image

This is the most 'nonstandard' feature because it's effectively an in-Python extension of standard syntax. It allows what is usually a tedious procedure to write longform to be done quickly and effectively in-line, with nothing more than the acknowledgement of what needs to be imported.

What Would Python Do (WWPD)?

  • SyntaxError: invalid syntax

So what's the rule?

If you haven't yet figured out what the rule is, now's your chance to stop and reflect on the features I've highlighted above. I've formatted them very specifically, so try to pick out the pattern.

Here's an image to act as a scroll buffer while you think.

image

The answer, as you might expect, lies in the What Would Python Do (WWPD)? section.

Do you notice how for each of these changes, the way Python traditionally reacts is either by doing nothing or raising an exception? Or, in terms more fitting to this context, no feature modifies existing behavior as to subvert the developer's expectations?

This is the fiber that makes up one of the primary design philosophies that underpins Jishaku as an REPL. In plain English, it goes something like this:

When evaluating code, the intention of the developer is to be maintained; no amount of magic or extensibility should cause the effect of a given block of code to become unpredictable, or to have its behavior be in direct conflict with what is written.

Jishaku is a toolset designed to be used for legitimate, serious development and debugging. There may be legitimate times where a developer does, truly, wish to send their token to chat for whatever reason.

The reason the [token omitted] clause exists in the first place is to protect situations where developers unfamiliar with the logistics of the "implicit return" may, for instance, return the contents of their config file or the attributes of a class without realizing it. I consider this substitution acceptable because the implicit return is already augmented behavior - it doesn't happen in most other debug cogs.

However, outside of such cases, the intention is clear. In accordance with the above philosophy, when you write await _ctx.send(_bot.http.token), I assume you mean it. Jishaku isn't doing anything wrong - it is merely doing exactly what you are asking it to do.

The solution for this problem is thus clear: if you don't want your token to be sent to chat, don't run code that sends your token to chat.

The power of the interpreter is unwieldy. One who wields Jishaku holds the same power as whatever user it is running under (which in some cases, can even mean root access - depending on how the host is set up).

Perhaps in the future I should have Jishaku warn you more aggressively about this during usage, but for now, I think referring to the sudo lecture is most appropriate:

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

from jishaku.

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.