Transcript #337: Backtracking For a Package
Return to episode page view on github00:00 Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds.
00:05 This is episode 337, recorded May 23rd, 2023.
00:10 And I am Brian Okken.
00:12 And I'm Michael Kennedy.
00:13 I want to thank everybody that's watching, but anybody that's listening,
00:18 I encourage you to at least once in a while drop by YouTube and see the upcoming list of events at pythonbytes.fm/live to be part of the audience.
00:28 It's usually fun.
00:29 It's usually Tuesdays at 11 Pacific time.
00:33 Occasionally we switch.
00:35 If you'd like to connect with us, we're all on Fostadon, or at least the three of us, Michael and I on the show.
00:42 It's mkennedy at Fostadon and at Brian Okken and at Python Bytes.
00:47 And with that, let's jump into our first topic.
00:52 Let's jump into it.
00:53 It's not going to be a rough one, is it?
00:56 So the first topic is rough, which is obviously, you know, Charlie Marsh's project.
01:04 It's very successful.
01:05 People know that.
01:06 It's not exactly rough.
01:07 It's a way to use rough.
01:09 And this one comes to us from John Hagen.
01:14 John runs this project called Python Blueprint.
01:19 So he's been playing around a lot with that project and PyCharm and rough and realized that now there's a plugin for all the JetBrains IDEs, most notably PyCharm, called just rough.
01:34 And the idea is that, you know, PyCharm has all these little squigglies and warnings and maybe even more importantly, the auto corrections.
01:44 So it'll do things like if you wanted to replace double quotes or single quotes, you can just hit Alt-Enter and it'll suggest, hey, why don't we just do that for you?
01:54 All right.
01:55 Things like that.
01:56 And so this integrates all the rough functionality into that same basic UI system, right?
02:03 You get little warnings or errors on the screen based on rough output.
02:09 So it has inspection and highlighting.
02:11 It can set it up so it runs rough on your code when you run reformat code or just hit the hot key, Command-Alt-L, Control-Alt-L.
02:18 It has the quick fixes that I was just talking about.
02:21 And it will actually run, you could run rough-fix as an action.
02:26 And you can even run that when a file is saved just automatically.
02:29 Like, hey, if there's stuff wrong with it, just fix it rough.
02:31 Just do that for me.
02:32 You can configure which version of rough is running.
02:35 So basically the plugin lets you specify, do you use a global one, maybe managed by pipx, do you use a local one in a virtual environment?
02:43 I sort of feel like isolating that to a per project basis is the right thing.
02:47 So that's what I'm doing, playing with this.
02:49 And yeah, you can run it as a new process.
02:51 You can specify a config option, like a YAML.
02:55 I'm not sure what the format that is, but whatever the rough config file format is so that you can say, you know what?
03:00 I don't really care about the line length for this thing.
03:04 So just ignore that and don't ever run that and so on.
03:07 So yeah, you can even run it out of a WSL Windows subsystem for Linux.
03:12 And there's some nice screenshots, as all UI things should have in there.
03:17 You can even see some of the settings if you want to try it out.
03:19 So it has 4.8 out of 5 ratings and looks pretty new.
03:24 But yeah, anyway, I think it looks like a good option.
03:27 So people can check that out.
03:29 Also, yeah, I'm really excited about it.
03:32 I've installed it and going to give it a try.
03:33 You can go check out the, it's open source, obviously.
03:36 So you can go check out basically the repo for the plugin.
03:41 And John sent over to us and I'm linking to this thing where it says you can add additional PyCharm specific instructions for both black and rough.
03:53 So he's got this section that shows you basically how to integrate both black and rough at the same time as automatic code formatters and PyCharm using the file watchers plugin.
04:04 So just follow along with the steps there.
04:07 And even has NOC support.
04:08 But yeah, cool.
04:09 So if that sounds interesting to you, if you want to have kind of auto rough just built into PyCharm and you use PyCharm, then check this out.
04:17 It looks cool.
04:17 Thanks, John.
04:18 Yeah, that's nice.
04:18 And rough, of course, is written in Rust.
04:24 And I'd like to talk a little bit more about Rust.
04:27 So there was an article I ran across called, it's from Koblo's blog.
04:33 Don't know who, that's a first name or last name, but thanks, Koblo's.
04:37 Writing Python like it's Rust.
04:39 And what I haven't written Rust yet, but a little bit.
04:46 Anyway, the thing I liked about this article was really basically he's going from Rust back to Python programming in both.
04:55 And one of the things he misses is some of the safety that types give you.
04:59 So he's discovered that he's changing or they're changing how they're using types within Python.
05:07 And I kind of liked some of the suggestions.
05:09 I think these are some of the things I didn't even think of before.
05:13 The obvious one, of course, is for function signatures.
05:16 So we really want to, if it's not obvious, like there's an example with a find item with records and check.
05:24 But what is that?
05:26 What are those types of those things?
05:28 So it's really helpful to your call, the people using your API to specify what the parameters look like or what you expect them to look like.
05:37 And there's so many options within Python now.
05:40 And also that, too, return value.
05:44 And here is an example.
05:45 It's optional item.
05:47 So I actually hadn't thought about that, of like using optional as a return type.
05:51 That's pretty cool.
05:52 Which means you can either, and you could probably do like item or none to say,
05:58 it can return none or something.
06:00 That's a, it is good to, especially if it's something, if it's possible to return none,
06:06 good to have that in the types.
06:08 So that's the low hanging fruit.
06:11 That's, I think a lot of people have gotten there yet already.
06:14 The other thing that I found recently is I've got some types that are like tuples or dictionaries or specifically a specific kind of dictionary,
06:25 like a string to any or even I use name tuples a lot, which are a little bit better than just your normal types.
06:33 But his recommendation is to go ahead and use data classes because they're more descriptive.
06:40 even if it's similar information, you can write up a little data class.
06:44 And then like in the example, instead of saying that you're returning a dictionary, go ahead and return like a person item, specific types.
06:54 And I'm kind of used to that from C++ of like writing little types because they're more, they're more descriptive and they're easier to read sometimes.
07:02 So bringing this into Python is kind of a cool idea.
07:06 The other, one of the things I thought was really awesome is this idea.
07:10 There's an example using the, where he's using like these packet types.
07:15 And since I work with communications a lot, this, this really hit home of you have, you have, you can, a packet might be either a header or payload or a trailer.
07:26 This is a Rust example, but you can do the same sort of thing within Python to say, I can have different data types using data classes to specify what kind of information you're going to get from these.
07:38 And then you can create a union type and have a, have that be a different name, but related to everything.
07:45 And I, I kind of love this idea of using a union type instead of, instead of using the ores.
07:51 I mean, using or for types is good too, but combining that into a union type is pretty slick.
07:58 Yeah.
07:58 Yeah.
07:59 That is pretty interesting.
08:00 I like that.
08:00 It's, so is that if you're going to receive say a packet off a network and it had first the header bit and then the payload and then the trailer or something like that?
08:08 Yeah.
08:09 Or I'm like a function that takes, that can like count the bits in there or something like that.
08:14 And it can either be a header or a payload or a trailer.
08:18 You could do something different with those and having a union type is pretty, pretty cool.
08:22 Now within it, I'm not, and here's an example of what, how do you do with that?
08:28 Deal with that.
08:29 You'd still with inside, you'd have to either do pattern matching or if clauses.
08:34 I've been using a lot more pattern matching lately to be able to just, you know, this is, this is great for you.
08:40 You take the packet type, but then you can match it against either a header or payload or trailer.
08:46 This is a really clean way to have union types and then unpack them with the pattern matching.
08:51 It's a pretty cool way to deal with that.
08:54 So.
08:54 Yeah, that is actually pretty clean.
08:56 That's one of the better examples of pattern matching that I've seen lately.
09:00 And this is just like a third of the article, but the rest of it does talk about different ways to basically, we have a lot of these tools within our within Python now to make it more to utilize data types that we are used to in other languages.
09:18 And you can kind of write some really clean looking code and easier to read.
09:22 So it's nice.
09:23 Yeah, very nice.
09:24 I like it.
09:25 So Kim out there has a question in the audience.
09:28 Ryan, is there possibly some overlap with writing Python after writing a bunch of C as you do?
09:34 As in same way, Rust leads to some good ideas in Python.
09:37 Yeah.
09:38 Well, I mean, that's, this, this is a, this person's writing it from the experience of Rust, but I'm looking at it going, this is a lot of the C++ stuff that I use.
09:48 So it is, yeah, I'm looking at it.
09:51 We're, we're actually, my team is being, is having a lot more fun with Python with the pattern matching statement because the, I know it can do a lot more stuff, but it really does.
10:02 Even if you're just using it to, to get away from a long list of if clauses and make it more like a switch statement, it is so much nicer.
10:12 It's one of the, well, easy bits.
10:15 So that's a good example.
10:16 Cool.
10:16 Yeah.
10:17 Marco out there says, but do a lot of Rust missing mismatch as well.
10:21 All right.
10:22 Shall we move on?
10:23 Sure.
10:25 All right.
10:26 Well, go ahead.
10:26 Go ahead with your first.
10:27 I know you had an announcement as well.
10:29 You wanted to give out.
10:30 No, I was just wondering, do we want to, today's episode is not brought to you by an external sponsor, but it's brought to you by us.
10:38 It is brought to you by us.
10:39 And I'd like to hear some of the news from Michael.
10:43 Well, the big news for me, which I have sort of put in as an extra now and then is the mobile apps.
10:50 So people go out there, download the mobile apps, talkpython.fm/apps.
10:54 And in there, if you create an account or log in with your account, at a minimum, you'll find like six different courses that are free.
11:01 You just tap on them and you can take those courses right away within the mobile apps.
11:05 If you get this super, super quickly, if you're one of the very, very prompt listeners, there's a chance that our Git course actually is free as well as part of a celebration of the mobile app launch.
11:17 But that lasts for about eight hours from the time of recording, which will be a few less hours from the time I actually release this to the general public, not in the live stream.
11:27 So you'll have to act fast on that one.
11:29 But do check out the mobile apps if you're interested in Python courses.
11:32 They're a great way to take it.
11:34 They have some free ones and they also are the best way to take ones that you paid for as well.
11:38 So four months of work.
11:40 Finally, really, really nice apps that we got out there.
11:43 I'm listening to a couple, watching and listening to a couple, a couple of courses right now.
11:48 Not right now, but in some of my free time.
11:52 I love the mobile app.
11:53 It's working great.
11:54 Awesome.
11:55 Thanks.
11:55 And you also have a thing to shout out as well, right?
11:57 Yeah.
11:58 I wanted to let people know I wrote a book.
12:00 No, you all know that.
12:03 But the exciting bit, I just got this email this morning.
12:06 So my book, Python Testing with pytest, second edition.
12:10 I've had a lot of great feedback of saying I didn't.
12:14 People saying they read the first one and it was good.
12:18 But the second one really nailed.
12:19 They really got some of the concepts in.
12:21 So I'm glad that I wrote the second.
12:23 So the news, I just got this morning, an email from Pragmatic saying that there is a sale right now.
12:30 So there's a whole bunch of other books, but Python Testing with pytest is one of them.
12:34 And if you use the coupon code spring 2023, and you can save 50% off of the e-book.
12:42 And that's up.
12:43 That expires June 1st.
12:44 So don't delay.
12:45 Spring 2023.
12:47 Awesome.
12:48 Let's bring you to some testing.
12:49 Well, that's us.
12:52 How about a new topic?
12:54 Yeah, thank you everyone for supporting the show by supporting our work.
12:57 Let's talk about PIP.
12:59 So this is about a month old.
13:02 I've been looking to grab a slot to talk about it, but there's been other sort of higher important stuff.
13:07 But I do want to point this out.
13:09 So Zyrtex over on Reddit, who if you follow over to the GitHub and then from GitHub, I think to Twitter, maybe named Damien.
13:17 Not entirely clear.
13:18 So I want to give credit, but it's not easy to do.
13:21 It says that pip 23 or points out that pip 23.1 was released with massive improvements to backtracking.
13:28 And backtracking is an algorithm that is part of the requirements resolver.
13:33 So if you say, you know, pip install requests Flask and, you know, something else.
13:40 pip has to say, okay, well, we know what those are.
13:43 But both requests and Flask may depend on some library.
13:47 I don't think that's true, but I don't think there's an intersection there.
13:50 But, you know, follow along.
13:51 If they did, then it's got to figure out, well, okay, Flask requires this range of versions and request requires that range.
13:59 So let me find a version that will satisfy both of those requirements.
14:02 Right.
14:03 And there might be a transit of dependency upon that, right?
14:07 Like that, that shared, potentially shared library itself has another thing that it depends on.
14:13 So the article or not article, Reddit post says, you know, for example, let's say you require package A and B.
14:19 The latest versions of A and B are downloaded.
14:21 pip checks their requirements and it finds that A depends on C version 2, but B depends on C version 1.
14:27 And so it's got to figure out, like, well, can I go back and get an older version of A that would allow, say, C equals 1 to work, right?
14:37 So prior to pip 20.3, the default process would allow pip to install conflicting requirements with a warning saying that this may or may not go well.
14:48 We couldn't find one.
14:49 That was a good fit.
14:51 But that's no longer an option.
14:52 I have very mixed feelings about that.
14:54 I love that it tries to be more strict and correct.
14:57 But at the same time, the alternative or the tradeoff is we guarantee correctness 100% of the time in terms of a version match for all the transitive dependencies across all the different things.
15:11 And instead of saying, well, install something that doesn't work or may not work because there might be some functionality that you may or may not interact with that is incompatible version-wise, we're just going to say your application cannot run.
15:22 It's impossible for your app to use these dependencies and run.
15:26 Personally, I would prefer to say, huge warning, this is not a great idea, but at least you can take a shot at it rather than it's impossible for you to run this application.
15:34 But, you know, that's the tradeoff pip made.
15:37 And because of that, it has to be even better at tracking down these version matches as best it can because the alternative is your application cannot be installed and run.
15:48 So there's a lot of interesting history here, but it talks about some of the algorithms that have been used and points out that pip now separates out the resolution logic into a library called ResolveLib.
16:03 And it was discovered that there was an error, logical error that both for performance and for correctness as well, you know, better backtracking technique called back jumping and an actual error that were fixed and implemented in ResolveLib and now come out in 23.1.
16:19 So if you're using pip and if you're listening to us, there's a real good chance that you are.
16:24 You want to upgrade your pip to 23.1 or higher.
16:27 Whenever I install requirements, I just have like a multi-step macro or alias.
16:34 The first thing it does is say, pip install --upgrade PIP.
16:38 Now go try to do the other stuff, you know, just it's like a concept for me, but I know not everyone does that.
16:44 So when you see that little warning that says, hey, warning, your pip is out of date.
16:48 If it's less than 23.1, you probably want to take that advice and update it this time.
16:55 Yeah.
16:56 Yeah.
16:56 Just this morning, I got a message.
16:58 Sorry, we cannot install your website because some, you know, Sentry requires this version of EuroLib 3 and Request requires a different version of EuroLib 3.
17:08 So you can't run your app.
17:10 Goodbye.
17:10 It's like, come on.
17:12 I'm sure that it's not actually using the conflicting.
17:16 And one thing that this does point out here is traditionally people haven't had to worry about this.
17:22 So you'll see things like one of the dependencies will say it has to be exactly like 1.2.3.
17:31 When really what it means is it's got to be lighter than 1.2, you know, and they've just pinned it overly tight.
17:38 And you end up with this crash where, you know, for sure that it wouldn't actually be a problem in your situation.
17:44 Like, how do you know?
17:45 Well, because before pip 20.1, it was running, you know, those kinds of things.
17:50 And so there's this little bit of, you know, I know it's great that it's trying to be more accurate and precise, but sometimes I'd rather have at least an option than none.
17:59 And so, I don't know, there's a whole interesting discussion down here.
18:02 People can check it out in the comments.
18:05 It devolves into a debate about Python 2.3 for a little while, which is weird.
18:09 And then just skip that.
18:10 That's not productive reading.
18:11 But there's some interesting conversations going on there.
18:14 And also, before we move on really quick, Brian, there is, I think it's Damien, as I said, points out that there is a PEP 658, which is accepted.
18:28 Or what version of Python is this?
18:30 I don't know, 2021.
18:31 So a couple versions ago.
18:32 That allows the metadata.
18:34 It used to be that pip would actually have to download and install a package just to see what the dependencies were.
18:40 And now that's separated out the metadata so you can get a very simple, small download without trying to do stuff to it to go, what does this actually need?
18:48 This version needs what?
18:49 Right.
18:50 So there are some improvements that are being brought into here, but still, there we have it.
18:53 Yeah.
18:54 A couple of comments, which I kind of agree with.
18:57 It'd be from Grant.
18:59 It'd be nice if there was a worn unresolvable or something to keep the old behavior.
19:05 I agree with Grant on that, yeah.
19:06 So I guess this is a reminder to library authors as well that your dependencies, you might know that you have a lower limit on some dependency that you need.
19:21 You need version like 1.2 of this library or above.
19:24 Think about it.
19:24 I prefer to have libraries in their dependencies, the transitive dependencies in a lower bound and not upper bound version because, I mean, you don't know what the upper bound is unless you do.
19:39 Unless there really is, there was a breaking change and you really know that there's a break.
19:44 Right.
19:45 The thing for me more is about, which I agree with you, Brian, and the comments, but it's about like there might be an absolute 100% conflict.
19:54 Like if this library tries to do, so for example, let's say like request tries to use Kerberos authentication instead of basic authentication.
20:03 And in that scenario, this other library does something crazy.
20:06 It crashes unless it's high enough.
20:08 If I'm never using that authentication mechanism, I'm never going to.
20:11 So like, yes, it is actually a break and change, but it's not a break and change for me.
20:15 Oh, yeah.
20:16 In my use case of that, the combination of those two things, right?
20:19 Like that's, that's kind of where I've been thinking about this.
20:22 Oh, yeah.
20:23 Interesting.
20:23 Yeah.
20:24 Because there's a lot of like a lot of Swiss Army knife libraries out there and you're not using all of them.
20:29 You probably, it's very unlikely you're hitting 100% surface area of a thing and its dependencies, right?
20:34 Exactly.
20:35 Yeah.
20:35 Interesting.
20:36 Yeah.
20:36 Yeah.
20:37 All right.
20:37 Well, anyway, this is, this is an improvement.
20:39 I feel like we're kind of like debating the 20.3 debate.
20:43 This is an improvement on the stuff that's already been decided to be done.
20:48 So 23.1 is a good way to go.
20:51 Yeah.
20:51 It's good.
20:52 Last item was a kind of a cool tool called Markdown Code Runner.
21:00 So this, this did remind me of a tool that I've known before.
21:04 So the Markdown Code Runner is a package that automatically executes code blocks within a Markdown file.
21:11 It's, it can include hidden code blocks.
21:15 So you can have, the code blocks can be in comments.
21:18 And so you can't see it in the Markdown file.
21:20 It just runs it.
21:21 So it runs the snippet and then you can have the output show up somewhere.
21:24 So this, in the example, let's run to an example.
21:30 You've got a little, a code block that says Python, but instead of just Python, you say, you know, you got your back ticks and then you say Python space Markdown dash code dash runner.
21:41 And then it runs the code in the code block and then it pops it out.
21:44 You've got another couple of comments for output start and output end, and it'll throw the output in there.
21:51 The kind of the neat thing is it's not just for Python.
21:53 It's for bash also.
21:55 So you can run some bash scripts.
21:57 Like if you want to show a, I was thinking if you wanted to show what the, the, the directory looked like with the tree command, you can go ahead and run tree within, within a Markdown file and run it or other stuff.
22:11 Has, has, has several examples that they think would be neat.
22:15 Things like, oh, I don't know, like diagrams or tables or various things that you might want to output with Python visualizations.
22:25 You can use that.
22:26 This is really cool.
22:27 Yeah.
22:28 It did kind of remind me of cog, but the, the syntax is a little different.
22:32 So cog from Ned Batchelder has, is a similar sort of thing.
22:37 You throw, you throw some code in, in place with some special tags.
22:41 He uses like a three bracket tags instead of an actual code block.
22:45 So the thing I kind of like about this is a lot of times I actually do want to show the code block.
22:51 So you can go ahead and show the code block and then run it.
22:55 So that's neat.
22:55 So some, some, it's fun.
22:59 I tried it a little bit.
23:00 There's an example of using rust.
23:02 So you can have actually running rust also.
23:05 I couldn't get the rust example to work, but I got the, the markdown and the, or the, the Python and the, the bash examples to work.
23:12 So actually pretty cool.
23:14 The, within the documentation, it also talks about running this as a Git lab or a, yeah, get, get, get, github, a CI snippet.
23:24 So, and that, that'd be a great place to do it is to just rerun your, rerun, like reproduce the code output from your readme on the new code.
23:33 So kind of a cool idea.
23:34 Yeah.
23:35 My first thought was, Oh, I have a code example and it says the output is this, like rather than trying to maintain those, just let it put the output there.
23:42 But it's also could be useful for just, I have a little Python bit of code that generates some other output that is, is useful, right?
23:50 Like here's the go through and generate a little, all the topics that it saw in the subjectry or something like that.
23:56 Yeah.
23:57 Yeah.
23:57 Like kind of a, just a markdown, like a macro within a markdown.
24:01 Generate a table of contents or something.
24:02 Yeah, exactly.
24:04 Something like that.
24:05 Cool.
24:05 Cool.
24:05 That's all of it, right?
24:06 That's all the main topics.
24:08 That is our main topics.
24:09 Yes.
24:10 All right.
24:10 I have a few extras to throw out here.
24:12 Let's jump over there real quick.
24:15 So same person who pointed out the rough plugin, John Hagan also pointed out, you know, I had talked previously about how I wish pip would update itself when I create a virtual environment by default.
24:29 So if I say Python 3.0.
24:30 So if I say Python 3.0.
24:30 So if I say Python 3.0.m.
24:31 V and V and V, the very next thing after activating it is your pip is out of date.
24:36 My God, geez.
24:37 Okay.
24:37 So hence, that's partly why my first thing to do is always upgraded is just to not see the warning more than anything, honestly.
24:44 But pointing out that since Python 3.0.m.
24:45 But pointing out that since Python 3.9, there's an additional option you can pass to the virtual environment creation story.
24:54 So instead of just dash M, V, and V and V directory, you can also pass --upgrade depends, which will automatically do that upgrade of pip and dependencies as well.
25:07 pip setup tools to the latest version as part of creating the virtual environment.
25:10 Yeah.
25:12 So nothing major, but quite nice, right?
25:15 Yeah.
25:15 I mean, I usually have that as a second step within my little macro.
25:19 So do I.
25:20 So do I.
25:21 And I was looking to replace that.
25:23 And I'm like, you know what?
25:24 Not quite.
25:25 Because I also want to install things like pip-tools and a couple other things that this doesn't include.
25:32 So I'm like, I still would have to write that line.
25:34 So I'll just leave it.
25:34 But anyway, still, it's really nice to have --upgrade depths.
25:38 You want it to have a shiny new virtual environment all the time.
25:42 Yeah.
25:42 And one of the things I really love that came in like a few versions ago is the if you do the --prompt and give it a dot.
25:49 It uses the directory name.
25:51 Yeah, that's really excellent.
25:52 It names the virtual environment containing directory names.
25:56 So it has like the name of the virtual environment is the name of your project often, which is great.
26:00 Yep.
26:01 All right.
26:02 More things, more extras.
26:03 One is PyCon South Africa.
26:07 PyCon ZA will be held in Durban.
26:10 And the most important part here is that the call for proposals is out.
26:18 And when is the time frame?
26:21 Kim will have to let us know.
26:23 I know he's out in the audience.
26:24 But yeah.
26:25 Oh, here we go.
26:26 Talks need to be submitted by August 18th, 2023.
26:30 And it's pretty good.
26:32 I think it's both virtual and in person.
26:35 So some good options for people to attend and down in October.
26:40 And it's pretty convenient for Africa, Europe, much of Asia, although less so for, you know, you and me, Brian.
26:45 That's all right.
26:47 That's all right.
26:48 Yeah, cool.
26:50 So people, if they want to talk at PyCon South Africa, be sure to submit that talk.
26:57 And Kim says that's a soft deadline, but sooner is better.
27:01 Okay.
27:02 Generally true.
27:03 I got a friend that's in the cybersecurity area, and he's up all night anyway.
27:08 Yeah, there you go.
27:10 Yeah, you could definitely do it if you just live off hours.
27:14 Yeah.
27:14 Real quick follow-up from something before, Brian, and then we'll get to a joke.
27:18 I had put out a call to everyone and say, help me find some off-road trails for this adventure bike thing that I got into.
27:24 I didn't really get any feedback.
27:26 So I'm going to instead pay it forward to other people out there who might be listening to my ride.
27:30 So some really cool apps on X off-road.
27:33 You can go through and find, you just click a spot on the map, and it'll show you, like, here's all the public legal trails for you to go tear around on.
27:40 And they're even rated, like, 5 out of 10 or 7 out of 10 with pictures and distance and challenges.
27:46 So you can decide up front whether or not you want to go down that path, I suppose.
27:52 There's also GAIA, G-A-I-A, which is a similar thing.
27:57 And then backcountry discovery roads, which allow you to find, like, how do I traverse my state, at least in the U.S., or similar things in Europe with the Tet.
28:07 How do you, say, traverse all of Oregon, almost 100% off-road through the forest and the mountains and the deserts?
28:12 And so there's this app that has all these, like, GPS trails.
28:15 So anyway, I found some cool trails way up in the mountains using this app and can recommend it to people.
28:20 Neat.
28:21 Cool.
28:21 Yeah.
28:22 Cool.
28:23 All right.
28:23 A joke.
28:24 You got a joke for us.
28:25 Yeah.
28:26 I can't remember where I found this, but there's a website called userinyourface.com.
28:34 So instead of user interface, userinyourface.com.
28:40 So you just have to fill it out.
28:42 So...
28:44 It's like an anti-pattern, a whole combination of anti-patterns into one UI.
28:52 Okay.
28:52 So just start off right off the bat.
28:55 So for people listening, I'm sorry, you're going to have to watch this on the video or something.
28:59 Or visit the link.
29:00 Or go visit the link.
29:02 It says, Hi, and welcome to User Interface, a challenge exploration of user interactions and design patterns.
29:09 To play the game, simply fill in the form as fast and accurate as possible with a button that says, No.
29:16 Big green button.
29:17 So it says, Please click, underline, score, underlined click here to go to the next page.
29:24 And the next page is highlighted.
29:26 And the trick is, the only thing that you can click on is the here button.
29:31 It's not a button.
29:32 It's just, that's it.
29:33 Okay.
29:34 And then it...
29:35 Okay.
29:35 The site uses cookies.
29:36 Is that a problem for you?
29:38 Yes.
29:38 Yes doesn't do anything.
29:40 Okay.
29:41 No, not really.
29:42 That goes away.
29:43 Can we help?
29:44 There's a help field with no enter.
29:48 Just send the bottom.
29:49 One of those dreadful chat messages that pops up.
29:52 Yeah, it's great.
29:54 Choose your password.
29:57 You click on it.
29:58 And the highlighted choose your...
30:00 Or the preview text is already there.
30:04 So if you add your password to it, it doesn't delete the old one.
30:08 You got to like fill that out.
30:10 Oh, you can't tab through anything.
30:12 So you have to click.
30:13 Oh, the email's bad too.
30:15 Yeah.
30:15 Instead of a placeholder, it's just gray, actual gray text.
30:18 Yeah, but you also can't delete it.
30:21 Domain.
30:24 Oh, this one you have to delete also.
30:27 And oh, there's a hurry up.
30:30 Time is ticking.
30:31 A pop-up.
30:32 One minute.
30:32 A four.
30:33 Can I hit the...
30:35 Oh, the X isn't an X.
30:36 It's a maximize button.
30:38 Lock?
30:40 The copyright's a close.
30:41 Lock, unlock.
30:42 This doesn't do anything.
30:43 Oh, the close is the copyright.
30:46 Right.
30:46 That isn't obvious.
30:48 Yeah, okay.
30:49 I do not accept these terms.
30:51 Okay.
30:52 Cancel.
30:53 Oh, I'm not...
30:54 No, I meant okay.
30:55 Are you sure you want to cancel?
30:57 Cancel to cancel.
30:58 Next.
31:00 Oh, it says already selected.
31:02 I do not accept.
31:03 So you have to uncheck it to accept the terms and conditions.
31:07 What are the terms?
31:08 Yeah, okay.
31:10 Good luck getting out of that dialogue.
31:11 You got to scroll down to accept them now to get out of it.
31:14 Okay, well, we're stuck now.
31:18 Because you can't even...
31:19 Okay, this is terrible.
31:21 Anyway, I did get through it.
31:24 The fastest time I have so far is like five minutes.
31:28 People are going to speed run the in-your-face interface.
31:32 Yeah.
31:33 I'd love to see a speed run to see how fast...
31:36 If somebody can really get through it in like a couple minutes, please do a video.
31:39 I want to see that.
31:40 So...
31:41 Jeff out in the audience says, I worked for the company that made that site.
31:47 Yeah.
31:49 So, yeah, the company looks like Veerheart.
31:52 So, nice.
31:53 Yeah.
31:54 All right.
31:54 Well, that's enough frustration for one day.
31:58 Indeed.
31:59 Thanks again for joining us and doing another Python Bytes.
32:03 Thank you, everybody, for watching and listening and supporting us through the courses and books and everything.
32:10 And Patreon supporters.
32:12 We still have Patreon supporters.
32:13 Thank you, Patreon supporters.
32:14 Absolutely.
32:15 And thanks, Michael.
32:16 Thanks, Brian.