Open kezabelle opened 2 years ago
Hi, @kezabelle! Thanks so much for writing in!
I took a look at the issue you described and agree that the difference in behavior can feel confusing. I'll be reaching out to a member of my team to get additional context on whether this behavior is expected or not and to look into what can be done here. I'll add any updates or additional findings here within the next day or so!
Hi, @kezabelle!
I chatted with a member of my team about this and we identified that adding in error handling for the described scenario could potentially cause breaking changes. Because of this, and also since there's still some SDK side validation for the scenario, we are hesitant to add in additional error handling here and alter the behavior of SectionBlock
for these use cases. However, if the error message is confusing, we can definitely look into updating it!
Hey, @hello-ashleyintech, thanks for taking the time to look into it. I appreciate it. Apologies for the delay in responding, I've been away.
I'll preface everything hereafter with a degree of uncertainty, as I've primarily been branching out to using slack_sdk
only for the type classes in models
(ignoring all the other submodules) to replace fragile/ad-hoc dictionary construction for blocks. So please, take the following with a grain of salt and ignorance rather than being in any way combative.
[...] we identified that adding in error handling for the described scenario could potentially cause breaking changes.
Would you be able to describe in what scenarios it could produce valid output which Slack would actually consume?
From my (comparatively limited) experience, failure to encode and raise an exception for the invalid schema only pushes the problem to the communication point with Slack's API, and whether you can even surface that error depends on whether that block is being pushed via an API call to views.update
(et al) or as a response_action
in the acknowledgement HTTP body.
This hit me in production in both scenarios due to what looked like an innocuous change in text output, and it's only because submitting data to the API returned a JSON schema error caused an error, that I noticed it.
On that set of assumptions (which may be incorrect!), what breaking changes would this cause that aren't already broken? Any tightening of validation is always a backwards incompatible, breaking change in potentia, but this would seem to me (naively) to simply be bringing the API in-line with the schema.
[...] also since there's still some SDK side validation for the scenario [...]
Again, unfamiliar with the rest of the modules, but where might I expect to find this? I'm presuming SDK here means somewhere within slack_sdk
rather than at the API boundary for communicating with Slack via HTTP? In broad strokes, in an ideal world and in isolation, if that validation exists elsewhere in the project, I would argue that it's in the wrong place given there is some expectation of validation on the classes themselves -- but, perfect is the enemy of good, and I fully understand that real world behaviours may have called for it to be elsewhere.
However, if the error message is confusing, we can definitely look into updating it!
There error message itself is fine, honestly. It's the complete absence of an error in another scenario which amounts to the same error, that I'm finding fault with. Were there no validation, I'd just chalk it up to something to deal with myself, but as there is some I now need to mentally keep track of which validations the slack_sdk.models
package "bothers" with and which I need to manually check forever.
In case it's easier to read the (pseudo-)code I'd roughly be (naively) proposing, off the to of my head the validation would be something like the below, give or take personal proclivities for type-checking or shape-checking and stylistic choices for brevity etc:
if self.text is not None:
# handle TextObjects (or anything with `.text` attributes)
if hasattr(self.text, "text"):
if not self.text.text.strip():
raise ...
# handle dictionaries (or anything with __getitem__(text))
if isinstance(self.text, Mapping):
if 'text' not in self.text:
raise ...
if not self.text['text'].strip():
raise ...
# handle strings (or really anything with strip as a method which returns truthy/falsy)
if not self.text.strip():
raise ...
@kezabelle Thanks for the reply! 🙌
Would you be able to describe in what scenarios it could produce valid output which Slack would actually consume?
If any valid string that is not empty is passed in to the MarkdownTextObject
or PlainTextObject
for the text
property, this would be a valid output.
On that set of assumptions (which may be incorrect!), what breaking changes would this cause that aren't already broken?
This is a great question! On receiving this issue, I had actually tried to implement error handling for this locally in a similar place where the text or fields attribute must be specified
was implemented. Sadly, the returning of an error for empty strings being passed into MarkdownTextObject
or PlainTextObject
s ended up breaking quite a few tests. This is what prompted me to consult the team internally, to see if all the errors being thrown from the tests were a valid tradeoff to add additional validation.
Basically, with my tested implementation (similar to what @/eddyg had suggested), it seemed like throwing an error in that particular location would end up altering the behavior of SectionBlock
, which could cause a breaking change, which is why the unit tests were returning errors. Because of this cascading effect and potentially wider impact, we are hesitant to add additional error handling at this time.
Again, unfamiliar with the rest of the modules, but where might I expect to find this?
Within the Block Kit, there is some validation. Here is an example of a PlainTextObject
being passed into a Block Kit - as you can see, it throws an error, must be more than 0 characters
. The same would get thrown if a MarkdownTextObject
was passed in (this can be emulated by changing the type
to mrkdwn
).
Let me know if you have any additional questions here! This is helpful feedback and definitely something we can consider a better pathway for in the future, especially if more folks run into similar issues with this. 🙌
Given the following:
This is all correct enough and good enough. What's happening behind the scenes appears to be that
TextObject.parse
is used and does a truthy test on the incomingtext
, and returnsNone
as opposed to an empty string.Where that begins to go wrong, is here:
Slack will reject that as erroneous. If it's sent back as part of the acknowledgement response as a
response_action
we won't necessarily see (receive) an error related to failing to parse the JSON schema. Slack's block kit builder says of it:Missing required field: text
Category
Desired outcome
Ideally, I'd like to be able to trust (more) that the validation present in
slack_sdk
is going to raise on invalid configurations early, and consistently -- that is, where possible I'd like to assume that putting together something "empty" even if I've opted to use the classes instead of an equivalent base type (str
,dict
) should raise.