edgewall / genshi

Python toolkit for generation of output for the web
http://genshi.edgewall.org
Other
86 stars 35 forks source link

Added a support for StopIteration as PEP 479 #67

Closed mahdialibi closed 3 months ago

mahdialibi commented 2 years ago

With Python 3.7 there was changes in handling StopIteration as described in https://peps.python.org/pep-0479/, Here a patch to make correction for this problem

hodgestar commented 2 years ago

@mahdialibi Thank you for the patch! Do you have a small example that fails before the patch that could be used as a unit test?

mahdialibi commented 2 years ago

When we create an iterator class for example :

class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self

  def __next__(self):
    if self.a <= 20:
      x = self.a
      self.a += 1
      return x
    else:
      raise StopIteration

when we use this iterator in a template with for each directive <li py:for="number in mynember" we will have an error

Traceback (most recent call last): File "/.../py3_deps_pypi__Genshi_0_7_7/genshi/template/directives.py", line 584, in _generate next(stream) # skip start tag StopIteration

hodgestar commented 2 years ago

@mahdialibi I added your example as a test case, but it doesn't fail without your patch. Looking at the code, it is clear why -- the next(stream) calls the stream iterator (not the special iterator created in the test) and the stream alway has a first item, namely the tag being stripped.

Could you fix the test so that if fails before the patch and passes afterwards?

mahdialibi commented 2 years ago

It turns out that the problem is in another location ! I have this code in a template

 <div class="classz">
                            <input class="" type="text" name="" value="${client.get('emailAddress')}" readonly="true" maxlength="255" />
                            <py:choose>
                                <py:when test="client.get('emailAddress')" py:strip=""></py:when>
                                <py:otherwise>
                                    <div class="help-class"><i class="class2"></i> Help text.</div>
                                </py:otherwise>
                            </py:choose>
                        </div>

I get the error

To get rid of this error I change my code like this:

 <div class="classz">
                            <input class="" type="text" name="" value="${client.get('emailAddress')}" readonly="true" maxlength="255" />
                            <py:choose>
                                <py:when test="client.get('emailAddress')" ></py:when>
                                <py:otherwise>
                                    <div class="help-class"><i class="class2"></i> Help text.</div>
                                </py:otherwise>
                            </py:choose>
                        </div>

so basically I delete the strip and all work again. the same thing if we make modifications in genshi code I am using Genshi 0.7.7 So I Think it's linked to strip directive when accessing any iterator . Yo have patched the same method "_generate" in other directives but not in the "strip" directive.

I hope this explanation help you.

hodgestar commented 2 years ago

@mahdialibi Could you please try write a failing test? I can guess why the template above might fail, but without an example to run that fails I will be going exactly that -- just guessing. As I already explained, the strip direction cannot fail in the way your original example suggests, and copying changes from elsewhere for a fix to a different issue that cannot occur here doesn't seem likely to be correct.

My guess is that something happens when py:when and py:strip try to remove the same directive, but it's hard to be sure without having a concrete example. If that is the case, perhaps this fix will be correct, but for entirely different reasons to the reason in the example you gave initially.

hodgestar commented 3 months ago

I'm closing this as its been stale for two years. Happy to re-open it at any point if it becomes active again.