Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[ProgressBar] Empty iterable throws Exception on "maximum number of steps is not set" #47259

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from

Conversation

freimair
Copy link
Contributor

Q A
Branch? 6.2
Bug fix? yes
New feature? no
Deprecations? no
Tickets Fix #47244
License MIT
Doc PR

Bug Description
When using the progress bar with an empty input and time estimates, an error has been thrown which stopped the execution:

            $bar = new ProgressBar($output = $this->getOutputStream());
            $bar->setFormat("%elapsed%/%estimated%");

            $input = [];
            foreach ($bar->iterate($input) as $item)
                var_dump($item);

I dug around in the code and found a semantically incorrect check for getMaxSteps() that evaluated a maxSteps of 0 (because of an empty input) to be interpreted like maxSteps has not been set at all und thus, triggering

                if (!$bar->getMaxSteps())) {
                    throw new LogicException('Unable to display the .* time if the maximum number of steps is not set.');
                }

Fix Proposal

I propose to change the check to be semantically correct as in "0 is a valid value of maxSteps, null is not".

More details and a bit of discussion in #47244.

@carsonbot
Copy link

Hey!

I see that this is your first PR. That is great! Welcome!

Symfony has a contribution guide which I suggest you to read.

In short:

  • Always add tests
  • Keep backward compatibility (see https://symfony.com/bc).
  • Bug fixes must be submitted against the lowest maintained branch where they apply (see https://symfony.com/releases)
  • Features and deprecations must be submitted against the 6.2 branch.

Review the GitHub status checks of your pull request and try to solve the reported issues. If some tests are failing, try to see if they are failing because of this change.

When two Symfony core team members approve this change, it will be merged and you will become an official Symfony contributor!
If this PR is merged in a lower version branch, it will be merged up to all maintained branches within a few days.

I am going to sit back now and wait for the reviews.

Cheers!

Carsonbot

@freimair
Copy link
Contributor Author

freimair commented Aug 12, 2022

well, the issues seems to be there since the creation of the progress bar #10356 back in 2014.

Has been merged into the 2.5-dev branch 554b28d.

Please let me know if I should PR against 2.8? I would opt for including it in v6, because stirring up code that old seems not reasonable to me. plus, nobody encountered the issue since then or people made sure not to iterate over emtpy arrays.

`max` value has been prepared to contain a `null` value, however,
the constructor with its default value of `max = 0` prevents
`$max` to ever be `null`.

Hence, declare `$max` as `int` instead of `?int`.
Up until now, it has been very hard to determin whether a progressbar
has a known maximum value or not, because the property `max` is an
integer. Up until now, `max == 0` has been treated like we do _not_
know the `max` value. However, `max == 0` _is_ a valid `max` value
when iterating over an empty but countable array for example.

We cannot simply keep `max == null` if unknown, because that would break
rendering mechanics and fixing those would require interface changes.

Hence, enter `isMaxKnown` - a property which keeps track of whether the
`max` value is known or not.
@freimair freimair requested review from fabpot and removed request for chalasr August 24, 2022 06:52
@@ -50,7 +50,8 @@ final class ProgressBar
private OutputInterface $output;
private int $step = 0;
private int $startingStep = 0;
private ?int $max = null;
private int $max = 0;
private bool $isMaxKnown = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this new variable? I suppose 0 is not a valid max, so having max at 0 probably means that it is not known?

Copy link
Contributor Author

@freimair freimair Aug 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the whole point of this PR and the issue I found with Progessbars is that max = 0 IS a valid max value but it is treated like it is not.

we stumbled over that behavior because we need to do a lot of import/sync operations, nasty but necessary. Once in a while, one of our imports/sync iterables is empty and thus max value = 0. foreach([] as ...) does not throw errors in vanilla PHP. Using the progressbar with foreach($bar->iterate([]) as ...) does.

@jwilson-ind
Copy link

I see this PR is in milestone 6.4 - does that mean that this fix will be in the 6.4 release?

@jwilson-ind
Copy link

I'd like to note that I believe this fix isn't going to help if you just use start():

$progressBar = new ProgressBar( $output, 0 );
$progressBar->start();

This only helps when you trigger the bar with $progressBar->iterate([]) as the isMaxKnown is only set it the iterate method.

@nicolas-grekas nicolas-grekas modified the milestones: 6.4, 7.1 Nov 15, 2023
@GromNaN
Copy link
Member

GromNaN commented Nov 15, 2023

I submitted an alternative patch, using $max = null to indicate when the value is unknown. #52605

@fabpot
Copy link
Member

fabpot commented Nov 16, 2023

Closing in favor of #52605

@fabpot fabpot closed this Nov 16, 2023
fabpot added a commit that referenced this pull request Nov 16, 2023
…ray (GromNaN)

This PR was merged into the 7.1 branch.

Discussion
----------

[Console] Support `ProgressBar::iterate()` on empty array

| Q             | A
| ------------- | ---
| Branch?       | 6.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | Fix #47244
| License       | MIT

Alternative to #47259

Use `$max = null` to indicate that the value is unknown. This allows `0` to be displayed by directly setting the progress bar to 100%.

Zero is only supported for `iterate()`. When passed to the constructor or `setMaxSteps`, it means "unknown max".

Commits
-------

574b8a3 Fix ProgressBar::iterate on empty iterator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[ProgressBar] Empty iterable throws Exception on "maximum number of steps is not set"
6 participants