 Okay, happy Friday. Good afternoon to everybody Good evening or a good morning or whatever time of day it is for you this this can get it down a little bit Welcome this back on top. Okay Welcome to everyone. This is Deep dive program weekly live stream program. How's it going Jeff over in LA? Thanks for Coming along for the ride Into shippu So weekly deep dive live stream program where we are Typically working on circuit Python stuff. So for those that might be new Or if you have caught this before and this is a bit different So Scott who's the lead developer of circuit Python is the one who usually does This live stream he's out this week and he was out last week So I was here last week and I'm here now To the best of my knowledge he will be back next week, but I don't actually know for sure The more correct thing to say would be that I just haven't spoken with him about it at all So I don't know one way or another about next week, but I do know that I'm here now So we're gonna be working on some circuit Python stuff like usual If you are new to this and you want to learn more circuit Python org This is the main website for the project where you can learn more This is basically a version of Python that runs on tiny computers called microcontrollers and the ideas These devices will plug into your computer Typically via USB cable and they're gonna show up like a thumb drive on that thumb drive You can edit a Python code file and then when you save it the microcontroller the actual Computer that is inside the chip on these devices will execute that Python code for you It will interpret it and actually execute that Python code and the code is capable of interacting with other peripherals Via you know IO pins typically there's a bunch of them along the sides of the microcontrollers like that So you can connect up other devices But there are some things where there's stuff built in where it's just you know connected out of the box Like this has a touchscreen connected and a few other things this has got some Cherry key switches and some LEDs and a little screen and a knob This one's got different shapes for the pins So all different kinds of shapes and sizes of these things But the idea is you can write that Python code to interact with whatever other Electronic devices you have hooked up to it So that's kind of a high-level view again if you want to learn more circuit Python org also encourage you to join us Over on the discord, which is linked down below There's a help with circuit Python channel if you're trying to use circuit Python for a project Or you're trying to get involved in writing circuit Python code to do something you can get help there There's also a dev channel where we communicate and can coordinate all of the Development for circuit Python because it's an open-source project all the development occurs Out of the open on github. Here's the repo for the main project right here Everything is all open-source and the all of our kind of coordination occurs through Discord so head over there if you want to get involved or learn more about it Thank you as always to Adafruit. This is their website Adafruit.com Adafruit is a company who's paying for circuit Python the circuit Python project is open source Everyone's allowed to use it. Everyone's allowed to put it on their own hardware Even you know add support for your own hardware That's all fine, and you don't have to pay anybody to do that The company though who's paying the developers who work on it is Adafruit So they're paying a team of folks who work on the project full-time There's some folks like me who work on the project part-time and are paid by Adafruit And that includes the live streams like this one that includes also just writing code reviewing code PRs library work infrastructure work Projects all kinds of different things go into the circuit Python project and community as a whole And you know Adafruit is who's making all that stuff possible So huge thank you to them as always and if you want to help support the project You can do that by heading over to Adafruit.com and purchase hardware from them They sell the microcontrollers like we talked about they also sell all sorts of stuff that you can You know connect up with your microcontroller in order to do stuff with it There's also the learn system which has got loads and different guides and tutorials for making different projects and doing different things So if you need inspiration, that's a good place to go as well And that whole learn system is a it is for you don't have to pay anything to use any of that Diving into the actual Topic I want to work on tonight is circuit so circuit is a command line utility that allows you to manage circuit Python libraries on your device If you are at a all familiar with PIP PIP the Python I don't know what it stands for a Python packaging installing thing PIP, I don't yeah, I should have not tried to elaborate further because I don't know what it stands for but whatever it is If you're familiar with that circuit is a very Similar concept as that, but it is for circuit Python libraries And instead of installing it inside of a Python, you know, virtual environment or a Python Installation circuit is installing it on your device most typically that device is connected via usb cable And it's available as a storage drive But the actual specific thing we're going to dive into is a new possibility with circuit where instead of being connected By a usb cable. We are actually communicating with the web workflow, which is a HTTP and web socket api that makes the file Contents available the storage contents of your device How's it going cgrow work? Good afternoon to you my friend Get a little bit of dribbling going on. Oh, wow. Yeah, totally just dribbled all down my shirt. Okay. Um, let's see Didn't screw the lid on all the way or maybe it just had some kind of underneath the threads or whatever I'm gonna fix this before I just keep Keep spilling on myself here If it's going through the top or if it's coming through the threads anyway Okay, so the the part of this that we are gonna get into right now is Um, first of all a huge thank you hug report to vladak. This is the person who actually implemented the the vast majority of this Um to to make circup integrate with web workflow the one small part that we're working on is the auto Argument for circup so circup auto this argument what it does typically It reads the contents of code dot pi on your device It looks at all the imports in that code dot pi file and it installs any libraries that are necessary for that code dot pi file And that part of it is not implemented for the web workflow. So that's what we're gonna try to do Package installer for python pip. Thank you, Jeff I appreciate the uh the knowledge there pit python package installer for python. So they have a silent f there sort of Um Thank you for that package installer for python. I will probably remember that the next time i'm interested in the uh the acronym there Uh, so where did we leave us? So I did a I did a little bit of testing on this Kind of peeked around in the code, but not too much. So we got to figure out how to do this I have a hunch basically what we need to do is um Right now when we go and look in the code inside of here It's going to be trying to read code dot pi from the storage What we really need to be doing is Reading it from the api. We need to send a get request To the server running on the device. We need to get the response back Which should be the contents of code dot pi And then we should be able to just do whatever it's doing after it reads the the contents of the file We should be able to continue like normal after that Um Yeah, okay, here we go autofile not found Uh, so we need logic just like I asked him in the comments says we need logic that knows that we're doing a Remote one a web workflow one basically which is Evident by the host flag most Most specifically on off like if you have a host then it's web workflow if you don't have a host then it's usb Has gone polish. Okay. Happy. Uh, happy Friday to you as well Let's see Yeah Okay, I think there was somewhere else did I mention somewhere else looking the it would need to have an if statement with some logic I want to say there is somewhere else where there is that but we'll have to try to find it It's I mean it must be where we install stuff surely Uh, one thing we could do is look at the diff. So I have web workflow. I don't know there shouldn't I don't know if there's changes I merged and pushed. I think that's the last changes on this branch. Okay. Let's try Actually update main as well Let's try a compare Oh, we have more commits from main. Wait. No, I thought I merged those Maybe those are even newer And 30 I guess that's pretty recent. When did I merge? I don't know I left this comment, uh Okay 20 so it did yeah looks like there was a few commits after actually there's a few commits after But they don't conflict. There's no actual merge conflicts Which they were the first time So we don't think we care about those actually It should just resolve itself as long as there's as long as we keep it to there being no conflicts then it should just Work itself out. So where is Go If url scheme, okay, so path is still path and then Basically if url.scheme is http url see but part of our trickiness there so we get path as an argument Here we store it on self dot path We say url parse and then we store the result of that on url. I guess that's some kind of object which has these things Then we have our logic that's checking, you know url dot whatever But we don't store url. We don't have self dot url So if we wanted to replicate this logic, we would have to like redo this It seems wasteful kind of Should we store self dot url or should we store just like web workflow true false or you know usb workflow true false Is there anywhere else Where the logic is like The same like that where it's yeah right here It's just doing it again. In fact though, okay Well, maybe we just do it again. I guess is that better it feels like inefficient I don't know really what this is doing. How much work it costs or whatever. So Uh, maybe it doesn't matter Okay, we should do it the same It's doing it this way basically everywhere else. So we should keep it to that Uh, so Inside of where was our if statement where where did we say we would need this this is inside of install Install makes sense. It doesn't make sense. Does it well Okay, it's in install because it's auto. I see it's not install. Yeah Install auto is actually the thing I see. Yeah, I always so when I think install I think you know install a specific thing and that's the command install but Install actually has the auto flag as well. It's kind of like wildly different behavior But that's the part we're interested in Which is here in the way that it worked when it is storage is Is relative autofile split this stuff If not is absolute is relative autofile just join Libraries from imports and then it passes out. But what is autofile? Is that a file name? We need to go into that Okay, where is this at? This is around 1671 inside import. Let's get it out of here Inside of import Where's from imports? What is this expecting codepy? This is a full. Yeah, see that's tricky actually though, right because It's not really what we want Yeah, see so this is like All the way down inside of here find imports is now going to finally open the file Up to this point. We've just been passing The file name itself tokenize That input what does this do? I have no idea. I don't think I've ever seen this root equals ast dot parse f dot read file name So we have to modify the logic all the way in here. We can't just we can't just like inside of install We can't just add another if statement Or whatever right that's not going to work Reverie worse 16 should have just gone with the uh thing again install We can't just add more logic here that says like if it is web workflow then you know get autofile a different way Because ultimately this is just a file path, right? It's just like the path to the file only Which is kind of pretty much just the file name. So it's like overwhelmingly always just going to be codepie I Put when I was testing I tried autofile f s codepie We don't I don't think we really want to look for f s. I mean technically what this is going to do is now look at circuit pi f s codepie it's going to look for an f s folder on the circuit pie drive Do you not repeat yourself extract the same? Tracked it in the same file Are you saying do not repeat yourself as in don't do the parse over and over again? Unless that might have been like yeah, it was a couple minutes back um And so we can't and then this so then the file name gets passed into here which ultimately then gets passed into here Which finally will open the file with this I don't know what tokenize and what this part's doing But it's clearly opening the file and reading the contents of it finally And so in here is where we need new logic here's going to have to be like if we're You know in web workflow mode Then we need to behave differently here So I guess up to this point. We should just do everything the same and then here. Oh Okay, this is like inside of uh, where did I clicked through to? Oh, wait a minute. That's in the library. Excuse me. That's oh That's in the library right did I Okay, see that's tough because now so that's getting passed into find imports. We actually need a different method right because we're not We can't just give it a file. It's never Like find imports that third-party library that thing isn't is never going to know about web workflow I guess we could down We could download it What if we download code pi? To the temp folder and then we pass that as file That janky kind of a little bit you have the same code twice extract it to a function um, it wouldn't really be a function in this case to just be like I mean we could store it on self basically To store the result of it. We're not really You don't really need to recompute it or do any action other than know the results of was it web workflow or not But but one thing is I don't want to change too much Before we get stuff working like if we get it working and then we want to kind of Change away certain parts of it work and we can break it and then fix it again I'm okay with that, but I don't really want to like break it before we really Even get it working The auto part which is the part i'm working on the other part currently works fine um Yeah, we're gonna we have to find find imports We need another one of these is there an api there must be an api we can pass A string with the file contents instead of the File name, hopefully Hopefully that's the case. Where are the docs? Get some docs action to here tests proves release docs Are there docs for this just goes to pip this just goes to github dear How does anybody know how to use this? It's a link to home page which comes back to here. There's a license It goes to the license There's no docs badge That is weird. Why are there no docs? Do we just we can't just search like this can you? It's third party. It's not part of the core python Do you just people just look at the code? So the code's not that Oh, it's not really an api. It's a command line thing We may have no choice but to copy it from the device To the local drive somewhere to the pc right the pc is what's running circuit The circuit pi drive in this case is not connected via usb, but instead we have Web workflow, but this is just file name right find imports. It's only taking a file name There is not one that takes a string so we don't really have the option to pass it a string which means we can't just Get our file content from The web workflow and then pass it into this we have to Get our content from the web workflow save it somewhere temporarily and then pass that temporary In to find imports And then like even though it's not the one from the drive It doesn't matter because find imports will find all of the same imports Yeah, apparently let's get back to here Let's get back inside here and then instead of We have code pi Mod names I'm just gonna say web workflow goes false and then uh, and then if So We're gonna modify code pi I think we're gonna modify code pi. So code pi is gonna come in and it's gonna be Uh, most likely it's just gonna be the string code dot pi in inside of a string what we're gonna do is we're gonna Take whatever string it is read it from the actual web workflow Copy it to the temp directory Or somewhere. I'm gonna copy it somewhere and then Pass that and then we're gonna set wherever we copy it Into code pi and then the rest of the code should work How do we read it from web workflow? I do not know. Let me plug this in I have a feather tft A feather s2 tft. I don't have the top-down camera set up because I figured there's no I'm not doing anything on the device if you're interested in It what it looks like you can just imagine this device right here Because that's what it is it's plugged in All right now it's plugged in via usb technically we could actually just use the regular storage Uh, but what we are gonna do is use the web web workflow or just host this stuff out I do unfortunately you'll have to look at this for a minute, which is not going to be very interesting. I need to look at my settings dot toml And I can't show you You shouldn't show you I mean I can it's physically possible But then I need to reset a bunch of passwords and tokens and that's not ideal um Yeah That looks fine And then one thing I'm going to do also is Go dot pi is here and bring this back now Uh, so my code dot pi right now actually is running a web server as well. I'm gonna web server template test that's what this is print Hello We're just gonna do a nice old print hello world inside code pi And then I'm gonna do To I don't have any to have history is all gone is all messed up. What have I done? What Oats slash dev There we go run hello world. Okay, so our Code pi so I had a web server inside code pi and it would have been running on the same port as the web workflow which is not Ideal because you can only run one thing on a port so then the web workflow is not going to work So now though now we should how's going? Um, Scott nice to see you my friend 119 The board flows so if we go 119 like this We should see this page now we can go to editor And we have the password goes here Uh I'm gonna do don't save Disable the usb right right right right so we need to Yeah, we need to do that because we want to be able to write we want to be able to edit files from web workflow So we need to disable the ability for files to be edited via usb Yeah, for sure. I am happy to step in anytime for sure See here, uh, and then this is gonna refresh and we have Maybe we need to give it one of these ones There we go Okay, so when you how do we so how do we get a file? So I think it's a send a get request to dash fs I'm gonna do those watch the traffic here. So I'm gonna open Code pi Which is at the end maybe Yeah, there it is Open and then we're gonna look back in that traffic. Give me that traffic back In here. So we did what we sent a get request to fs um 119 And we need to do this too I don't know how this works Um warning you're probably gonna see my not so secure web workflow password Please don't access my device with it. And that's not sure I just won't leave my network before I change it but Uh web workflow base. We need base 64 decoding. We could do this in python code. I don't know the I don't know the Actually, I might know the code. Let's try it. Let's try and solve The things I want to do is kind of use python code more than just search up the same tool that I always use I think is it this base 64 and then just Decode right it's actually pretty easy This is gonna print or yeah fair warning, you know, don't do what I'm doing because that's gonna this is gonna print my password Which ordinarily you wouldn't want to do I'm gonna change mine after I get done showing everybody This thing one output Okay, we need to look at that. I don't know what to do with that Maybe it's wanting input stream output stream base 64 python example Have this workflows nice Have this already is this the api that tells us what it does instead of watching Dev tools maybe What? Yes It's not really good to the same place. Did it is it? Yeah, it is 8.x it is. I just don't is it have another space here I don't know why it's not just going there as a website. There we go There's file rest api The password is sent unencrypted How does it need anything with it though? Is it just the password base 64 encoded in the nothing else or is it um Is there something else with it like does it it needs a username? I assume but the username is empty. You prefer firefox for Linux. Um I like firefox. I would say that I like firefox. I use chrome too. You can say I have chrome open as well um I like firefox. I like mozilla. I like the mdn All right, this is a utility that mozilla makes available for free and it's super amazingly useful Um, you know, it's not firefox itself, but I like a lot of stuff mozilla does putting firefox. I think it's pretty nice I do use linux Authorize name directory modified file size look Sword curl password u. Okay, if you use curl though, you can just do it dash u So it is I think the colon is right. So there would be a username in front of the colon, but we use blank. I think is that That might be how this goes. So then our base 64. I think is going to be colon and then whatever my real password is I think requests will do the base 64 encoding For you it's standard htp access Ah, okay, let's try that uh requests. Let's try requests um I found requests Get with uh basic off. Yeah, that's a good idea. I didn't even think about I was like trying to build the request all manually and stuff. But yeah, this is totally going to be handle Handled in here Okay, make a session set off and then all session dot So we're gonna get we're gonna get the response We're gonna get the response and then we are going to write it to a temp file You need to do our imports Oh, this doesn't have imports. I guess requests probably I'm so far down. Let me do this legitimately on the line lead Oh, it already has requests actually even better. Okay. I believe this is always blank. I don't know. Are you allowed to set this? I know mine is blank Um, you need to I somehow we will have to provide this though, right? This will have to get Oh boy, we are in a pickle here. So yeah, we we're we'll need to pass this through somehow Uh from install So another option though, can you put it in the url? Is that how we should do this? How did I give the password before oh, I did put it in the url Is that true? Yeah, it looks like it. Well, no, circ up the other code put it in the url I did okay. I did password. We already have I've got dash dash password How does that come through? Circ up. So that's a circ up option How did we get that? How do we get access to that? That's what we need. We need to read that and then pass it to session right here username is before the colon I think the server assumes blank And it ends up in the header. Yeah, I do think it's in the header It's in like a one of the one of the um, one of the headers key values that gets passed We get a hold of those arguments url dot password I got pass device path Oh, this was happening already. I should have read other parts of the code which makes sense obviously because it's uploading stuff So of course, we're already doing the authentication Uh, okay. Okay. Okay. Yeah. Yeah. So we can just do the same thing here url parse and then This creates auth. Oh, that's an interest. That's a different way to do it So that's creating auth and then saying auth equals instead of creating a session It's uh, and instead of creating a session and then making the request inside that session It's creating the auth and then adding the auth When it just calls requests Uh, base for status. I don't know what that does. Well, I mean, I guess we probably want to do the same thing roughly, right? What do we have? We don't have self because Why don't we have self? So we're pieces here I remember this file. I poked around a little bit in this file I can't say that I understand a lot of it, but it's pretty like once you have seen a web server implementation You can kind of follow along even then it's in a different I liked Where did I steal this stuff from? Why do we not have um have self update what is this update is inside of Module why do we not have a module? I mean install would have gotten past a module Tools available modules We're not gonna have a path path is on module module represents a library We don't have the libraries yet because this is getting the libraries from the codepie file So we're don't we don't have those yet. This is Giving us those libraries which will in turn get turned into module objects, which then have path which then That other code was using to get the password and do all this stuff I think we need to find out how to access it off of the circuit argument somehow we can From inside of the install function somehow we must be able to get those circuit objects probably in context, I guess right print context print dur Text let's start there So the way we can test this is go pip install space dot which will install the repo the the directory i'm in Then we can i'm going to make a different terminal to go I'm basically copy pretty much this I'll do this one. I don't think it I don't think we want to require this fs. This is going to be for every file is going to have fs It should assume that based on the fact that it's web Okay, my p is the same my password is not actually that Super sneak it super super secret password is that Okay args Nope args is empty Command command path I mean, I guess we could get it potentially from there, but there there must be one of these that just has Them as a dictionary or something easy, right? scope to info dict prams protected args This is args These are like these are kind of yeah, these are like those Auto true auto file none requirement, but it does not have The circuit arg as opposed to the install arg. Sorry, uh Need a buzzer Good i'm learning a lot on this circuit python neophyte neophyte. I don't know how to pronounce that. Sorry um You could make a buzzer for chat that'd be interesting took me a while to come around on circuit. It's very nice. Yeah, I am I would say i'm the same it took me a while to start using it But once I start using it now I use it for everything like I used to actually have a cron script that would download a new bundle Every day on to my computer so that I could then go copy stuff out of it whenever I wanted it Uh, and I had settled that up prior to learning about circuit and circuit was the thing that made me just totally ditched that And now i'm just always installing with circuit. There must be a way to get the I'm going to call them the base command arguments click get Arguments seems It's going to give us the arguments for the sub command Very attic arguments file path arguments opening safety Let's find something that uses one of them again. So we have host This is our half written code Click option. So how do we read click options click Read click dot option value Tried params. I did I'm pretty sure You can try it again. I'm pretty sure I did Yeah params I Did we maybe I didn't run it. I don't know I think I did but I'm not sure we'll try it again though To be sure so we do install Run it. Yeah, so params gave us some params gave us basically like Some of these which is weird because we're on context which has also got passed so I don't know why is there options. So we try to args. We tried params. Is there options? These are alphabetical i l m m m Obj there is meta would meta be what we want parent Yeah, what kind of object was this? It told us back here. It's a click core context Let's see if this gave us anything options but this got Past which ours is not click pass context See so we have like a two-layer thing going on right like Sir cup has the the sir cup command has its own arguments which in this case are host and password and also command and then Based on the command. There's install Which is like a sub command like a another command that has its own arguments All the stuff that comes after So far everything we see is all that stuff that comes after but what we want is like The parent options This is always just using the ones that got passed in though Does that mean we need to pass it to here aren't they just passed into the function they wrap I I mean they are but this one isn't these two aren't host and password aren't well they are for They are for main But I then I guess we'll need to do we need to pass them along to install But does this this doesn't really call install If I just add them will they show up will click just called like put them in automatically No, that's fine I don't think that at all honestly ideas are helpful. Um Arg v a little command line so sir cup has a main with args Uh, well sir cup is all based on click which part of the problem is I don't I'm not really I wouldn't call myself fluent in click so if I knew the basics of click We might Be in a better spot, but let's try this. What if we just say host here And then will this be filled in that'd be convenient if that works I kind of don't think it will but My guess is it's got to be on context. We're probably close by looking at context object My guess is something in there Has got it. We just got to figure out which one Maybe this will work though. This would be convenient Action applications basics context whenever a click command is executed context holds the state Yeah, it's got to be in here somewhere should come in to come in Remember's parsed parameters. Yeah. Yeah. Yeah. Yeah Okay, we got to find that how's it going guard master uh over on youtube So I'm just calling convention building and get clone root command group option Pass context. Yep. Okay. That's exactly says because our install has that Install pass context Did I install that? I don't know. I'll do it again See what this does Nope, okay. It does not like host. Let's take that back out of there This is it though somehow click dot object Context dot object Equals repo what is repo is object In it home none debug os path Object doesn't do anything What is okay? Let's just print it out. What is context dot object have on it vj. Let's do dur also It's got helpful functions like get or something useful. Let's see oops install device path It is a it's a dictionary. So it has all the dictionary stuff, but it only has device path Go home debug. How are these passing through? What are we making? So we are working on circup Uh circup is a command line utility that lets you install and manage Libraries on your circup python device. I don't know how new you are if you if the stuff I'm talking about doesn't make sense I can give you a higher level version, but Um, it's command line utility that manages libraries on your circup python device We are trying to make it, uh a work for Web workflow, which is just a different way of accessing the content on your device Interleaved commands parent Be parent is what we need It's the apparent on the list before It's another context Which has all the same stuff So that one maybe has was it params. I think we're there. I think this is it It is Rams That could be beneficial to me. Awesome That's good to hear. I like making stuff that is beneficial to other people Ah, yeah, there we go. Okay parent dot params. That's a dictionary From that we can get password Now we're cooking. Okay back to where what are we doing here? Um, we needed that word. We needed it back down here. So I guess we do need to pass it to This otherwise We We either need to pass it into this or we need to write another version of this that works for web workflow And I'm inclined to pass it in because we already have this so I'm thinking we call that we're gonna already be passing this to true and then I mean The next question is do we pass host and password? Or do we change this all the way? Maybe we don't even do web workflow true false like this maybe instead Maybe instead we're passing context Which is the click context and then we're accessing the params from there that way We actually have all of them. We have host We have password and from Those we basically can derive whether or not we are web workflow true false install Now I will say it feels weird to have context get passed at the end of this But the beginning of the other one. So I guess we could change it But then it's like a breaking function, but it is I think an internal function. So maybe that's okay. I don't know. I'm usually averse to breaking stuff So I'm usually more of an added at the end But we'll do it this way. We'll see if we end up regretting it Where's the other place where it got used here concept? This one's weird because we don't have a context So I guess we're just gonna go with none on that one And then this will be we need to say if context is not none first of all Because if it is none then we know that we don't want to do any web workflow stuff It's not none then we want to look on it and determine whether or not we are using web workflow Which we can do by getting Basically if host and password exist at all, right? Have you worked with godot? I have not that's a game engine. I think if that's the game engine thing I have not worked with that You want to learn more python? Yeah, that's pretty cool. I like python a lot I'm always up for learning python. I think you want pip install e and you won't need to run it every time What? Are you for real? It's amazing. Hold on. Wait, what? Let's make this so it's actually not going to crash this for now It's a ball So that basically I guess that like links it so that The literal code here is like sim linked Or whatever so that when we change it I'm gonna get my new print context isn't none if context is not none I actually pass it in Missing parameter in the doc string. We'll fix that later I got my other two prints from here Oh, uh, it maybe it crashed actually before it got all the way to there I think it might have crashed before it got all the way to there But if I do that That's actually really cool Uh, yeah, I totally did not know that pip dash e editable Yeah, that's Basically means we don't have to go back and forth every time Okay, I actually have a class on python and ai development watching this can make me excel more in that class. Nice. It's good to hear uh context So we crashed but why did we crash because we don't want to crash before we get to there, right? We need to be able to make it to there, but we never added. Okay. Yeah, because we know we're crashing from here Because this came back So we need we do need like and not web workflow or something, right? We need this to not Crash if we know that we're trying to use web workflow Which again, it's basically Whether we have a host In a password. So I'm gonna say using web workflow equals There's a lot of quotes host in I don't know if you need this keys. I always write in keys, but I don't know if you actually need that host in keys Is that it should be a boolean? So now this should be true or false if Host is in the parent keys, then that's true And otherwise it's false so now If not is file. So we know this is gonna fail. So we also want to say and Not web workflow using web workflow If we're not using web workflow and the file doesn't exist, then we raise the error If we are using web workflow, then the file is allowed to not exist because we know that It's not supposed to exist yet I suppose we could copy it at this point But in my mind, honestly, it feels best to copy it like right here Copy it to a temp get its path and then set its path to codepie The rest of the code should work the same. That's kind of where my mind's at So if context is not none, we should be able to get to here now, right? Should be able to get to here, I think and we don't have to reinstall it. So we just go here up BAM Yes, context isn't none. We still error after that, which is fine But we're actually inside of Here we know our thing is not none So we can do we need to do yeah, we should do similarly the same kind of thing like Um using web workflow Wolves post in context dot parent dot params keys then That's not that so then If we are using web workflow Is this Okay we Still are not gonna have path We're we're not gonna have path We are gonna have to create it from host But I don't do we really need this I don't think we need to do this url parse because we don't have a path What we're gonna do is basic auth is empty the password comes from context parent dot params password We should probably handle the key error so far. We looked at host for this and not password, but I don't know if you're allowed to do blank. Not sure. I think we don't need this though That's not the right kind of comment We're not doing get or we're not doing delete. We're doing get we're not doing self dot path. We're doing Host we're doing so host is the this plus plus I don't know if that's gonna have a I don't know if that's gonna have a slash at the end or not I'm not gonna put us. I'm not gonna put a colon because it kind of muddies the water a little bit It might it should have a colon in it. I don't want to get Doesn't really matter, but okay does not actually have HTTP or anything like that. So we need to go That's weird though, right? Didn't I Did I I guess we just passed the Let me just pass the IP. I guess we need to go HTTP Maybe we'll make a url here Let's go maybe url instead of url parse. Let's go url equals HTTP Should be as uh, maybe not these Host We need to add our slash. We know we're always gonna be fs and then from there it is um autofile which is codepie But it's the value of codepie The variable url is this Or not Okay codepie actually already had a lot of stuff in it interesting, okay, so We don't need to append all that stuff I mean them So the main thing it doesn't have is fs. I guess we could Okay, let me say the url is just equal to codepie I'm gonna come back and delete these Just in case we want to copy more code from it. Oh is codepie and then rams and then git and then url Then r dot raise and then not doing this one. This is old r dot raise. So then the response Let's just say print response That's just gonna be the contents of codepie if everything works But it's not gonna work because fs is not in the url So we need to either Um, that's gonna in my life atm. I've lost my voice. So I'm happy film. We got streaming today After around fantastic stuff. I'm learning of course, uh, This guy, but you're really good too. Yeah, thanks Take it easy. Jeff by the way. Thanks for hanging out for a bit. It was nice to have you Let's see Yeah so One of two things we either have to kind of like modify that to add in the fs or we would have to require the user to do this for the web workflow version of the code but the Good news is well, I don't know if it's good news just yet, but I think this might actually just like work Honestly, let's see if this does So if we do go and put this fs codepie Then it should get inserted into the proper place. Oh, I didn't save let me save Now right now it's just gonna print so it's not gonna like actually work all the way but Maybe it'll print Yeah, totally worked. Okay. That is the contents of my codepie drive It's been a minute since we saw it, but yeah all the way back here So we want to write that So we want to write that to a local temp file And then set the path to that local temp file into this variable code underscore pi And then let the rest of the code do its thing and it should just work Do I want to just like make a temp file like literally f equals open code dot temp dot pi right f dot right I think we probably don't we probably want to make it in the temp directory We probably should try to find the python. There must be an api for like get the temp directory That's probably what we should do get the temp directory make it inside of there And then get the path to it and pass it But I am curious if this will work like this It doesn't crash anymore. Uh, let's get some code actual code, let's get display text Simple test bitmap label so the Required libraries for this this is the wrong place. I'm so used to going back to my ide to edit code not my browser The required libraries for this is display text and then display text itself. I think requires um bitmap Font so it should I think stack and get both of them. Uh, oh, that's interesting Wi-Fi. Okay. Did that save import error? No module display text Uh, I might have messed it up by having circuit open. I don't know if that messes it up. I think we still have this though, right? Let's see. There's my import error We'll close circuit now. We disconnected. We got no reconnect. Let's see if we try it again We did get an error on FS. That was a while ago though It's because we're just sitting at the crashed screen right now Get back to here. Okay This doesn't load Okay, all that stuff is still in there. So that that saved at least So we can go try to run our auto now Oh something was Something was trying to install. No, actually what was going on. It looks like stuff was trying to install back there But I don't hash live. I don't know why it would do that That's not used by display texts I don't know what was up that I wasn't actually watching how soon after the When I ran it that stuff started showing Come on somebody you got this so it found display text Does seem a little stuck now though We should turn off this print I'll be right back a little bit. It's so dark It's dark so early I should say Um Seems stuck after that I'm gonna entertain the cat here for a second Well as my legs will not go unattacked May find web workflow issues. What is my that actually one thing we should check is what version are we even on? I'm on 900 alpha 2 Possibly I should downgrade It seems like that request completed though. It seems like that part went fine Any of these anymore? I'll come back and delete them later. But just in case we want to use them again Is that I mean it must have saved right we must have yeah code.temp that must have worked and then we got it into here and then So maybe that's what got stuck last time, but I still don't get the hashlib right hashlib is not used by Anything and also this was empty It eventually time out though So possibly we just have like an open request sitting back there But we were able to load this so like the server's not frozen Which it did seem frozen for a second last time This doesn't seem frozen anymore Boarded Okay, let's try one more time to see if it was a fluke kind of doubt it, but Why didn't I comment that out? Oh, I didn't save afterwards. Let's try again Also want to see it not print all that extra stuff. Okay And for dependencies I do think I am going to try to go to I'm going to try to go to The released version see if we did stumble upon a web workflow bug or if we Have something wrong inside of circuit what we're modifying here Let's found someone choose using it. Okay Uh, I double clicked reset and I have no I have no display no neopixel And no drive Issues like the issues are on the released version too Here we go. I have no idea what I did last time, but this time I made it to the bootloader Uh, okay, we'll see if I get I'll I'll see if I get the same thing with this I can step backwards if I need to Go back through a couple Um worst-case scenario I can check I'm pretty sure the ladak who submitted this into circup repo As to this I don't I think they might have even put their version. So worst-case like I maybe go back to their version So right now we're installing circuit python 827 Back to here I'll let it reload. I don't know if it needs to like Initialize or whatever, you know, I guess possibly I could have got it stuck when I did the save and run That's actually when it got frozen last time. I guess Seems like it worked What we'll do is we'll go delete them so that it can actually install them. But what it did is it says so Searching for dependencies for display text it found those dependencies Well, it found bitmap font. That's a dependency for display text. So then the total list Of libraries to install is now display text and bitmap font It says bitmap font already installed and it says display text Successfully installed now and then if we go and So I don't know how to get it to run one thing that is weird on mine is I have um Auto reload turned off Oh, yeah, there we go So now that's actually running and it's showing hello world on the display Which proves that the libraries are installed now and we weren't getting that before one thing I'll do though is I'll actually go and delete these so let's go Um, can I close this? I don't know if that actually closes or what let's go open I think in here you can delete right Lib Or actually it doesn't have delete Oh, I swear. I saw it. Oh, there is delete. It's trash can the first one. Okay So let's uh delete bitmap font Wait for that. It'll take it a second and then delete display text close So this can no longer run. So if we go to serial and I try this again to reconnect I don't actually have control right now in here Well control c I should say is not doing anything. Nothing I do is really doing anything Let's try restart You start seems like no dice Now I run it says no module. So we don't have this play text. We can't run this code Now we go circuit install Well host password install auto Point it to auto file with fs Uh, we don't actually need I was doing dash dash pi before because of the uh 9.0 versus 8.0. We didn't have mpy yet We do now though so I could actually get rid of that and I think it should still work We have a few more prints we can get rid of searching dependencies display text Boom we found them bitmap font display text this time it's going to install them both Installed one installed two Should be able to run it again now And this time it doesn't crash it does succeed. I have hello world on the display Everything's working. That is amazing So let's go back and clean up some prints and some comments Um, do we want to delete this after? That's a good question I feel like if we put it in the temp directory, then do we do we need to delete it? If we are always going to call it the same thing every time maybe it doesn't matter I don't think it I don't think circup ever goes back and deletes the bundles that it downloads Um So I'm inclined to just download it into the same place and then not Treat it the same way as it's a bundle that we downloaded right just put it in there And then the user can if they have a temp cleanup routine or whatever it'll delete it and that's fine because it's only used Right afterwards, but you know where the bundles actually get downloaded from What did I just do? I think I had deleted a character, but it should be back now. You don't need this Oh, what's putting all these extra spaces? Cated fragment okay, so Uh, one open question is do we want to require this auto file fs slash Um, if you are still around scott, I'm curious if you have an opinion on this auto file. So basically We either have to require this like this auto file fs slash and then you know, most people are going to say codepie, but they could use whatever they want um, we have to either require that or we would have to Basically slip in the fs Automatically we'd have to so we know the thing we had before was The url without the fs in it Here's one of the old ones I thought we were printing the url. I guess that was a while ago though Oh, there it is. Okay No, that's the new url style Hmm somewhere back here. We were printing the url We could replace but then how do we know that codepie doing? I gotta go chase a cat off a window Add the fs internally. Okay Cat is like literally trying to scale a window A different window than he normally tries to scale actually so that's cool that we're changing it up at least but Would prefer we don't scale any windows ideally. So can we we could just is it gonna break anything if I just split? On slash and then the last one of those parts we know is the file name So then we can just replace The file name with itself But fs in front of it. Okay, so let's get back to without this Use without this also. In fact, we can go all of that stuff So url, it's not just going to be codepie. It's going to be I'm going to make another variable. I always like to call this variable parts equals codepie split on slash Then codepie is actually going to be codepie dot replace parts the last one Which is in our case the string codepie we want to replace that with fs slash Parts the last one So we will replace codepie with fs slash codepie We already have a slash before codepie Should be good I already took out the prints Where does url come from? Url, I mean the local variable url right here that we're about to send a request to comes from codepie Which got passed to us as Auto file which got filled in as codepie Well, no, no, no, no. It was it was not none So it did not get filled in right here. It was already filled in before I think I'm not sure I'm not sure where it got set, but I'm pretty sure it was set As soon as we already like it's already set by the time we get inside this function That's what I'm trying to say. I think at least Um, basically the I guess the other another way to phrase it would be it gets generated it gets put together with Code that's in the pr Put that vladak added So I guess yeah, maybe we should find where it gets put together Because it should probably just have an fs put into it there instead of us replacing it right before we use it here, huh? Oh, it's actually none Does get filled in wait a minute Oh, okay, right here is how it gets filled in so auto is true Auto file is none Auto file is none. So we do actually We do actually do this print setting auto File to code dot pi this is gonna happen and then we go down here if not Absolute path auto file this would be false because that file it's http. It doesn't exist in os dot path. This is gonna be false I don't know about this part, but this is gonna happen next. I think changed auto file new val I assume it just needs to use Plus fs. Yeah, whatever. It's built basically changed auto. Yeah, right there so then but uh, but the thing is I think the crux is the different behavior because This same exact code is used for usb We I'll have to switch devices or set my device back to usb in order to test it that way too, but This would be this would be um Slash like in my case, this would be slash home slash tim. Uh, no be slash media slash tim c slash circuit pi And then it's gonna add slash code pi to that And we can't just add the fs here because when it's usb, we don't want that fs So I guess we would need like if web workflow Which we did set up before if using web workflow Let's do it the other way if not using If now using oh, and now I just needed everything I didn't mean to That's fine If we're not using web workflow do this if we are using web workflow Do this but join we want to add an fs in here So do we just you can add another one of these can you I think so We're kind of abusing os.path.join. We're making a url not a local path, but they're both use slashes So I guess it's fine I think this needs a bigger refactor to have A file back end It's used to load and save files Not sure Not sure what you mean exactly See though I mean, it's got that code somewhere There is code handling that already somewhere because it's already knowing how to like read well not read, but uh, right It's it's knowing how to write Files its own way. I don't know exactly how it does that or where The difference is how it figures out like usb versus the other way, but somehow it's already writing So it's already got kind of the back end that knows If we are a web workflow, then we write files by sending this post request here And then if we're you know usb workflow we write files by No, I guess cp or something right os.move. Maybe not sure how it's actually writing but Somehow as a file directly Um, but then this was this this is kind of the only place where circup reads Every other activity circup does is writing to the device. It's always installing libraries this part though with auto We have to read code.py I think is the only time we ever really read anything from the device Other than like I maybe does it read boot pie or something to tell you there's updates um Might read boot pie for something like that, but I mean that would have needed the fs too though, so it would fail on this device. So maybe it doesn't Oh, wait, wait, wait, wait. I added it twice. I I still have my replace down inside there. Yeah, yeah Don't want that anymore. Where'd that go? We don't want this anymore it's actually just um That's back to just code pie There's to be that flag that searches the behavior now now it can work without Specifying the auto file Which is nice because that's the same with usb. I like that. We don't need to have auto file there I thought it was wonky to have fs slash it worked So if it was the you know the end of the day if it has to be that it's not the end of the world You can still use it, but this is nice because now You know the same sub command install auto is now the exact same sub command you use usb or web workflow Does the same thing either way? I mean not the same thing once using poster quests obviously, but copy but installs libraries the same way the higher level thing functions the same way Okay Do I still have we don't actually need this it turns out We should probably get the temp directory I was trying to find where we download bundles to I never did actually come across that though Where do we download bundles? How did I find that before? I've found that before there's only really just a knit. I swear there was download bundle. Is there really not? local on dumps It'll config local datadur Maybe we should put it in datadur Those afters user datadur circa data fruit We should maybe we should say local code pi copy Temp local does it matter? I don't know if we need that everything inside of this It's temp. I guess like the bundles and everything it downloads are all temp because it replaces them every time local codepie copy equals It's really a path, but this is also a path and it doesn't actually say path in the name So i'm going to do the same So it's path join datadur circuit. So this will be code. I'll just use the same one I did before code temp Dot pi and then we'll put a comment like all these have The location to store a local copy of code.pi for use with dash dash auto Use with uh dash dash auto and web workflow together web I don't know what the lines is this too long it does not like this trailing white space What there's no trailing no trailing white space editor doesn't want to Now there's trailing now. There's not it's gone now. Okay. Oh good enough Uh brb. Yep Let's see here. Okay, so now that will save to there. So then instead of code dot temp.pi wherever we put that Now we could say uh open local code pi copy Write the data to it and then code pi is now local code pi copy Okay, do we still have any extra prints? Um, yes, something's printing none. I think that's printing context, right? We also have this setting. We also have this changed Setting auto we can get rid of that We can uh changed auto changed auto we can get rid of that And changed auto new val Something printed none. I think it was printing a context ctx Oh, we have this. Oh, it was auto file. I see. Okay. It was not context fair enough. Now. Do we have any prints? boy that dash e That dash u was like That's a really nice tip That's today's tip of the day if we had a tip of the day on this Livestream it would be dash e with pip install Yeah, almost to the point where my face is gonna green screen What happens when it's too dark and then if I turn on the light it gets to be too light sometimes it gets green screened out from the shadow See if we make it another 20 minutes without it getting there, but oh, you know what? I also have this covered up um Yeah, my apologies over on youtube. I was uh had the youtube chat covered up a while If we made circupython based on micropython. Yes, that looks like it's been over there a little while back um Everything that printed this time is actually just from circup. So I think we got rid of all of our own prints Let's see what our diff is looking like So we have a new variable local codepie copy. We have That's a to do. I didn't change that. It's not actually a diff. It just is also blue in this In here, where's our change? There's a change here. There it is. Okay, so libraries from import. All right, right So we changed this to take context We said if context is not none we made the variable Boolean whether or not we're using web workflow based on whether or not host was there. What happens when you don't pass password Happens when you don't pass password Nice Perfect, honestly. That's like best case scenario Tells you exactly what the problem is Okay, I was worried that would crash and have an error that's not very helpful That could not be farther from the truth actually though. It's already Essentially swallowing the error and giving you a human readable. This is exactly what's wrong We're changing again. So okay there it is Okay context gets passed in if it's not none we have our very our Boolean if our Boolean is true then So, I mean I we could get by with not using a variable instead. We could just put this I suppose I don't know if it matters. I kind of prefer this one because it makes the code kind of documenting right tells you like The reason why you care that this is true is because it signifies you're using web workflow. So it's kind of like Descriptive in that way. It tells you what it's trying to do I like even though you could actually just take this Plop it right here It would work the same. I kind of like giving it a name But I'm also not stuck on it. I could go either way But I do like that's the way I lean so URL is equal to code by basic auth. Whoops basic auth. We set it up by setting password Blank we go get our URL which came from our file We set up our auth we if there's an error we raise so like if user, you know, doesn't have wi-fi not on the internet um Web workflow is not enabled Like they put the wrong ip address Any of that kind of stuff happens. This is going to raise an error And then I think what we saw before is it's going to print the red basically the same way this did Going to show them the error there. Hopefully it will make sense to them like which Thing went wrong. Why because it could be a number of things, you know, your network could be off or your Maybe your web workflow is not set up on your device or maybe your password What does it do if you have the wrong password? It should be a 403 error Should be a 403 error My bad 401 I don't know my http errors by heart turns out except for the best one 418. Is it 418? I'm gonna double check now That's the best http error Slight tangent. Yeah, that's the one right there. You know it Back for 15 more minutes. All right. Yep. That's about uh, it's about how long I'll go as well So I'll be taking off around then too. So let's see we raise Open the temp file right to it write the contents that we got from our request close it And then set the path into codepie that way find imports will find it. It'll do its thing All the rest of the stuff already works correctly. So then the other changes down here, which is Inside of install we get our boolean again You can get rid of this If we're not using web workflow, we do it the old way which is just join the path with the name of the file It makes sense because that's exactly how it works on usb If it is web workflow, so if that's uh, false because we did not there if it is a web workflow, we take path fs and file name Then we make sure not to raise an exception because the local file doesn't exist Right no problem. We're not expecting the local file to exist if we're using web workflow Get our list of libraries right there Context is the change in that line and then everything from then on is all the same Everything there just already works. This contains a list of libraries This already does the looping and the installing and all the stuff We're all good from there What did I do here? Oh, right right context. We passed none for that. So then our And that should be fine test circuit. That should be fine. Let's like I haven't actually run this before I don't know Where is that? Where is this file test circuit tests? This library's from imports. It doesn't have a main though You have to run it as a test right because of our new one Where is that? Tests, I don't know how to run the tests Actions must run the tests right There's docs and there's pre-commit. Does pre-commit run the tests? Let me just run it again so that we have post formatted code Some of these yeah, these all fail on files that aren't part of the repo. This is also not part of the repo So I could delete the local one And then that won't actually come back because now it's going to the datadur. So let's delete that. Let's run this again Reuse these will always fail because it just I don't know it doesn't realize these aren't part of the repo We do have this we're using open without okay. Yeah. Yeah, it doesn't like that. It's me to use with I guess I'll use with with open don't actually like this In tax as much but Grudgingly I'll do it to make pilot happy. Let's see open as f and then we'll go That anymore In this case, it works out. So in this case, I actually don't have a problem with it, but my Issue with this comes when you want to open a file in one function and then in another function, you know, write some stuff to it And then in another function close it The context does not really allow that to happen very easily because they're using with The same thing basically, right Wait, what is open without explicitly encoding? Oh, maybe we actually have a different one there I might need to just tell it utf 8. Is that what it's wanting for that? I don't know how to do that actually I've never done a I'm actually sure how to do that I think I've run across that error before pylons. Is that a new one coding utfa? capitals lowercase Okay reuse fails But black and pylon pass reuse is just always going to fail Everything else passed. I'm going to push and see if the tests are in in the actions Because I don't want to like if it's just my pie charm doesn't know how to run this properly and that's why it's failing Then that's not a problem But if they actually fail Then we'll of course want to fix Commit This is what fixing dash dash auto for web workflow It's it's not really fixing. It's more so implementing. It just didn't used to really do it implementing I'm very good at spelling honestly We got it right the first time though, so that's good I should already be on this correct branch in this case It's actually this flat-ac web workflow because that's what the pr is set to We'll hang out for a minute and see if this passes actions But I will probably wrap it up pretty quick after that if anybody's got questions comments things to say Now it's probably about the time a couple minutes left whenever we see if this passes or not. I'll wrap it up so Yeah, get your comments out now or questions or anything like that We uh go with the suspense way where we just wait here for the colors. Should we actually watch it happen on the checks? I kind of like to watch it sometimes Run test suite it is going to run the tests. It looks like so we'll see if it passes in there I guess as it's just I probably don't have it. It probably needs the right path or it needs something that I haven't configured for it That's my best guess um, I will say Excuse me while we're waiting on this Um, if anybody is interested I will be back around tomorrow morning Uh over on my channel phome guy We'll be back streaming. I think what I'm gonna work on tomorrow is actually something that I Streamed a bit about earlier today, so if any folks were around earlier today on my channel You would have seen this if not. No worries. I was working on some Uh python integration so over on discord one of the community members Micah over on discord had an idea a couple of weeks back that they talked about and asked about and it was kind of making a Link between circuit python code and mine Minecraft so being able to run circuit python code and have it kind of affect blocks inside of minecraft rather than An actual microcontroller right the idea being like in my mind the idea the power of this being A person who wants to learn circuit python But doesn't have the microcontroller, but does have minecraft because like a lot a lot of people have minecraft That person can now Learn some of the basics of circuit python if this thing would exist They could use it to learn the basics of circuit python without having a hardware yet And then once they get their first microcontroller they're actually going to be able to reuse a bunch of their knowledge Um, so I was working on that earlier today if you're interested in that you can find the stream It's on youtube the vod's there, uh, and then tomorrow morning i'll be back at 10 a.m central time Uh, which is my time zone 10 a.m central time I'll be back and i'm going to be working on that again. We did fail here and it does look like the same thing actually so we do Have a problem with our tests Um, do the test paths on main. Let's start there I will still probably wrap up here fairly quick. So if we don't get a solution here super fast Then we'll have to leave this for now And I will pick it up later But we have a few minutes and I'll try at least I went to main Does this run on main Does not run on main for me either, okay Uh, oh this one has one has one failure though. Is that what that means? Aren't these likes passes and then one f in the middle there? I don't know if that's true actually It's and this is around the code we changed, isn't it? Isn't this around the code we changed 10 38? But but but we're on main right now So this is not even having the code that I changed And it does not make it to the line 10 whatever it's failing right up here When I run it local so it's different. It's a different error File not found Okay Yeah, I was not reading I was not reading. I just jumped to conclusion. It's a different error. It's a different error This isn't a search an error. This is a test failing I think Actually, I'm not I'm not convinced this is an error. This might just be telling us that a test happened I don't know if that's actually an error or not this though deprecation One failed Doesn't does it say which one? Other than this or is this telling us 10 38? But why does main fail does main did it fail like the last time anything happened like in here it passed Pass I so I submitted that pr. I actually just have the branch right here I try This fails the same way for me locally Okay, so the reason it's failing locally for me is different than the reason it's failing in actions And it fails for me locally on all the branches Not just the new one But on the new one inside of actions I guess 10 38 Where did that go? No, this was the pass fail And 38 this is telling us we failed the test 10 38 the test failed there So I need to figure out how to get them to succeed locally This test failed. So it was expecting exit code to be two But it wasn't I got one instead circuit install auto file so so I think that means that When you give it a bogus file for auto file it should fail But it's not I think that's what that test failure is trying to tell us I might actually have a not code. So I'm actually going to make not not code I don't know for sure and I'm not going to check Right, right. So you would need to you would not need to have the fs actually now Unauthorized so it does give us the same error as Oh, wait, do I still have the bad password? I do still have the bad password actually Okay 404 it gives us okay Get status maybe maybe you do have changes changes for uh Well, it wouldn't I don't I can't have changes otherwise it wouldn't let me change these things But that's like an ide thing. I mean I have this file like, um project Ide folder, but it's not checked in it's red. So it's not checked in we could add it to ignore I do occasionally add it to ignore when I find it in repos That it's not there. This one happens to not have it lots of them have it listed and ignore Um, but we don't we definitely don't want to need that checked in I do know for sure Okay I will have to figure out how to I'll have to figure out how to Get these tests to run locally That way I can then figure out what this is actually I mean it's returning one instead of two, but I don't know why it would do that or what that really signifies or means And I'll have to be able to run it locally to figure that out. So and I think that will come in a different time. So Uh, I will wrap it up by saying thank you everybody for hanging out Thanks, uh scott for hanging out Uh anybody yeah, like I said, I'll be back tomorrow morning 10 a.m Huge thank you as always to ate a fruit for making circuit python and all the stuff we work on possible Huge thank you to everybody for watching. I hope you all had a nice time Hope you all have a nice rest of your friday evening and a weekend and all of that stuff I will catch you next time. Like I said tomorrow morning 10 a.m. I don't know about next week. We'll see Maybe uh keep an eye out on the meeting or uh, if you want to be notified like The deep diver's roll can be pinged. So if scott's gonna be out he can ping that so Keep an eye out for that. Otherwise that is all for now