Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Spaseman posted:

Can someone explain how to make the line "BaconTest001.Pit001" in the "AreaOne" class run? I'm working on deepening my understanding of classes and their interctions but nothing I do can make this particular line run. I know the code is a mess but that was the point.


Theres more, and deeper, issues that I was too lazy to fix, but maybe this will help.

Python code:
# Subclassing object isn't needed, so I removed those
class BaconTest:
    def __init__(self):
        # It's customary and helpful to define instance attributes in __init__.
        # This makes it clearer to what's going on in the class even if you're 
        # not going to assign anything to them until later methods.
        self.pit_001 = None
        self.stream_001 = None
        pass

    def test(self):
        print("test")
        # This is the Python conventional way of naming variables.  Use underscores.
        # Except for the name of classes.
        self.pit_001 = Pit()
        self.stream_001 = Stream()
        print("test002")


class AreaOne:
    def __init__(self):
        print("uxuxuxuxu")

    def areaonetest(self):
        print("jhjhjhjhjhj")
        # BaconTest001.Pit001  # Cannot Run#
        # BaconTest001 does not exist in this scope.

        # You need to either construct an instance like this:
        bacon_test_001 = BaconTest()
        # but wait, you have to first call the test method to create the pit_001
        # instance on the bacon_test_001 instance
        bacon_test_001.test()

        # this is now the equivalent of what I *think* you were trying to do...
        bacon_test.pit_001
        # but that doesn't do anything.  It's a no-op.  Maybe you want to print it?
        print(bacon_test.pit_001)
        print("4343434343")


class Pit:
    def __init__(self):
        print("test3333")


class Stream:
    def __init__(self):
        pass


class Events:
    def __init__(self):
        print("tertrtrt")
        # See,  here you instantiated an instance, but this instance is not visible in AreaOne.areaonetest.
        # It is only visible within each single instance of Events
        self.BaconTest001 = BaconTest()
        self.BaconTest001.test()
        print("dpdpdpdpd")
        self.AreaOne001 = AreaOne()
        print("sdsdsdsd")
        self.AreaOne001.areaonetest()
        print("po po po ")

    def MainMenu(self):
        self.AreaOne001


Game = Events()

print(Game.BaconTest001)
Game.BaconTest001.test()
print("------")
Game.MainMenu()

Adbot
ADBOT LOVES YOU

Spaseman
Aug 26, 2007

I'm a Securitron
RobCo security model 2060-B.
If you ever see any of my brothers tell them Victor says howdy.
Fallen Rib

Thermopyle posted:

Theres more, and deeper, issues that I was too lazy to fix, but maybe this will help.

Python code:
cut code

This is incredibly helpful and has made many things clearer but I do still have two questions.

First, I noticed that for in the init of BaconTest you used self.pit and self.stream while in the areaonetest method of AreaOne you didn't. What is the significance of that?

Second, is it possible to create an object in CLASS_A and then edit that same instance in a different class?
EDIT:I wanted to clarify this second question a bit. I know you can pass an object from one object to another for editing but can I call an object without passing or is that something that just isn't done?

Spaseman fucked around with this message at 21:15 on Aug 9, 2015

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Spaseman posted:

First, I noticed that for in the init of BaconTest you used self.pit and self.stream while in the areaonetest method of AreaOne you didn't. What is the significance of that?

It signifies laziness on my part.

Spaseman posted:

Second, is it possible to create an object in CLASS_A and then edit that same instance in a different class?
EDIT:I wanted to clarify this second question a bit. I know you can pass an object from one object to another for editing but can I call an object without passing or is that something that just isn't done?

Always pass stuff to code that needs stuff. Otherwise you're dealing with a bunch of global state that is just terrible.

I'm a little unclear where your confusion is, so I'll throw some ugly code at you. This isn't exactly how I'd do this, but maybe it'll clarify something for you?

Python code:
class ClassA:
    def __init__(self):
        self.class_b_instance = ClassB(12)

class ClassB:
    def __init__(self, something):
        self.something = something
        self.fondled = False

    def fondle(self):
        self.fondled = True

class ClassC:
    def __init__(self, class_a_instance):
        self.class_a_instance = class_a_instance

    def fondle_b_in_a(self):
        self.class_a_instance.class_b_instance.fondle()

>>> a = ClassA()
>>> c = ClassC(a)
>>> c.class_a_instance.class_b_instance.fondled
False
>>> c.fondle_b_in_a()
>>> c.class_a_instance.class_b_instance.fondled
True

Spaseman
Aug 26, 2007

I'm a Securitron
RobCo security model 2060-B.
If you ever see any of my brothers tell them Victor says howdy.
Fallen Rib

Thermopyle posted:

It signifies laziness on my part.


Always pass stuff to code that needs stuff. Otherwise you're dealing with a bunch of global state that is just terrible.

I'm a little unclear where your confusion is, so I'll throw some ugly code at you. This isn't exactly how I'd do this, but maybe it'll clarify something for you?

Python code:
code cut

It clears up a lot for me, thank you, but I do have one more question. Say the fondle method of ClassB had an attribute not located in the init that I wanted to access and change. What code would you write to do that? Or is that something that just isn't done?

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Spaseman posted:

It clears up a lot for me, thank you, but I do have one more question. Say the fondle method of ClassB had an attribute not located in the init that I wanted to access and change. What code would you write to do that? Or is that something that just isn't done?

Methods don't have attributes (well they do, but it's not applicable and isn't commonly used). I assume you mean how the fondle method is accessing self.fondle. You can access any attribute you want on self. It doesn't matter if it was assigned to in __init__ or in another method, or whatever.

Have some more code exploring some of this:

Python code:
class ClassB:
    def __init__(self, something):
        self.something = something
        self.fondled = False

    def fondle(self):
        self.fondled = True

    def rub(self):
        self.fondled = True
        self.rubbed = True

    def is_caressed(self):
        return self.caressed

>>> b = ClassB('hi')
>>> b.rubbed
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'ClassB' object has no attribute 'rubbed'
>>> b.rub()
>>> b.rubbed
True
>>> b.is_caressed()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "no.py", line 18, in is_caressed
    return self.caressed
AttributeError: 'ClassB' object has no attribute 'caressed'
>>> b.caressed = True
>>> b.is_caressed()
True
One technique to avoid those AttributeError's is to assign False to them in __init__ like we did with self.fondled. Even if we weren't worry about that, it's a good idea to assign them in __init__ anyway as it helps you keep track what is going on with your class. You will lose track of how the state of your class is put together.

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

I just dabble in Python so someone shout at me if I'm going wrong here... but as far as I'm aware, your scopes are basically dictionaries, so any attributes you use are effectively dictionary entries. Trying to access b.rubbed before it's been assigned is really looking up a key that isn't in the dictionary yet. So assigning your attributes in init means you're adding all the valid entries to your dictionary at the beginning, and anything that accesses them will get a value back.

You can add them later, like how rub() assigns a rubbed entry, but then you have an issue with the dictionary's current state - if you try to get the value of that entry, has it actually been added yet? That can make it hard to reason about the actual state of the object, which is why it's easier to just create its attributes at construction time

keanu
Jul 27, 2013

baka kaba posted:

I just dabble in Python so someone shout at me if I'm going wrong here... but as far as I'm aware, your scopes are basically dictionaries, so any attributes you use are effectively dictionary entries. Trying to access b.rubbed before it's been assigned is really looking up a key that isn't in the dictionary yet. So assigning your attributes in init means you're adding all the valid entries to your dictionary at the beginning, and anything that accesses them will get a value back.

Pretty spot on explanation there.

code:
>>> class Foo(object):
	def __init__(self):
		self.bar = "baz"

		
>>> f = Foo()
>>> f.__dict__
{'bar': 'baz'}
>>> f.__dict__["baz"] = "bar"
>>> f.bar
'baz'
>>> f.baz
'bar'
>>> 

Spaseman
Aug 26, 2007

I'm a Securitron
RobCo security model 2060-B.
If you ever see any of my brothers tell them Victor says howdy.
Fallen Rib
I just wanted to say thanks to everyone for the help, especially Thermopyle. This has cleared up a lot of my misconceptions about classes and Python in particular. I finally feel like I have a firmer grasp of what I am doing in Python.

JetsGuy
Sep 17, 2003

science + hockey
=
LASER SKATES
This discussion got me thinking about a more philosophical question about using classes. I'm writing a routine to pull data of various types from the same place and put them somewhere else.

The core mechanics are:
- For each data type, run the query function with the appropriate arguments
- Once the lists are gathered, check the data lists against what I have, pass a list back of the data I don't already have (for each type)
- Download new data

The way I'm approaching it is within the main function (i.e. if __name__ == 'main') it takes the arguments from the user (which specify which data types they wants to update), and run the queries to be eventually passed to a downloader. I'm just dumping it into a larger dictionary. So the structure of that dictionary is like:

code:
DATA
    |
    | TYPE A
        | QueryResults
        | NewData
        | Downloaded
It occurs to me I could just make this a class instead of a dictionary, but there are small nuances in how the QueryResults must be handled, so it would be more like a DATA class and a subclass for each type.

I'm not really clear what the "best" way to do this is. I guess this may just be a personal preference thing, but I'm also trying to future proof this a bit if that matters.

sharktamer
Oct 30, 2011

Shark tamer ridiculous
Is there a favourite user agent parser? All the ones I've googled for seem to be slightly out of date, they don't seem to detect windows 10 and microsoft edge for example.

sharktamer fucked around with this message at 10:28 on Aug 12, 2015

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

sharktamer posted:

Is there a favourite user agent parser? All the ones I've googled for seem to be slightly out of date, they don't seem to detect windows 10 and microsoft edge for example.

Good.

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



sharktamer posted:

Is there a favourite user agent parser? All the ones I've googled for seem to be slightly out of date, they don't seem to detect windows 10 and microsoft edge for example.

http://www.useragentstring.com/pages/api.php

Blinkz0rz
May 27, 2001

MY CONTEMPT FOR MY OWN EMPLOYEES IS ONLY MATCHED BY MY LOVE FOR TOM BRADY'S SWEATY MAGA BALLS

sharktamer posted:

Is there a favourite user agent parser? All the ones I've googled for seem to be slightly out of date, they don't seem to detect windows 10 and microsoft edge for example.

Don't do that.

SurgicalOntologist
Jun 17, 2004

Given this spec for communicating with a treadmill over serial, what data type should I be sending? I've never done this kind of thing before. I thought it should be b'C0' for example, but that doesn't work. Do I need to do some kind of encoding? I'm a bit out of my element here.

I'm also not entirely confident I've got the device/communication set up correctly with pyserial. I do get
code:
USB COM PS1
T
(no newline after the T)

when I power-cycle the treadmill, but after that I don't seem to get anything, even the error codes, no matter what I send in.

sharktamer
Oct 30, 2011

Shark tamer ridiculous

Blinkz0rz posted:

Don't do that.

Yeah it's a stupid task, given all the browsers lie about who they are. I know it's better to check for browser capabilities or that type of thing, but this is what I've been asked to do.

KernelSlanders
May 27, 2013

Rogue operating systems on occasion spread lies and rumors about me.

SurgicalOntologist posted:

Given this spec for communicating with a treadmill over serial, what data type should I be sending? I've never done this kind of thing before. I thought it should be b'C0' for example, but that doesn't work. Do I need to do some kind of encoding? I'm a bit out of my element here.

I'm also not entirely confident I've got the device/communication set up correctly with pyserial. I do get
code:
USB COM PS1
T
(no newline after the T)

when I power-cycle the treadmill, but after that I don't seem to get anything, even the error codes, no matter what I send in.

Is that all the spec you have? It looks like not really enough. They should also provide you the unit's desired baud rate and parity settings.

To test the communication, you should be able to write 0xA4 and read out 0xB4.

Python code:
ser.write(0xA3)
r = ser.read()
print(hex(r))
Remember, though, any time you have moving parts controlled by a computer you need to have an emergency stop button that physically disconnects power from the unit. University labs like to skip this step, but it can go really, really badly.

SurgicalOntologist
Jun 17, 2004

KernelSlanders posted:

Is that all the spec you have? It looks like not really enough. They should also provide you the unit's desired baud rate and parity settings.

There's another page of commands, and a cover sheet, but I think that stuff is at the top of the page I linked. Baudrate is 4800, no parity.

KernelSlanders posted:

To test the communication, you should be able to write 0xA4 and read out 0xB4.

Python code:
ser.write(0xA3)
r = ser.read()
print(hex(r))

Ah, I didn't know there were hex literals. I'll try this later today.

KernelSlanders posted:

Remember, though, any time you have moving parts controlled by a computer you need to have an emergency stop button that physically disconnects power from the unit. University labs like to skip this step, but it can go really, really badly.

It comes with its own emergency stop button that overrides the computer control. Plus one of those cord things you put around the person's wrist so it stops if they fall.

Thanks for the advice!

lord of the files
Sep 4, 2012

i'm still in the process of learning python at an intermediate level and i am running out of ideas of what to make. where can i get some good ideas for things to build and contribute to github? something actually useful, too.

SurgicalOntologist
Jun 17, 2004

Figured out the bytes thing. It had to be dev.write([0xA1]) (i.e. it expected an iterable).

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Fractale posted:

i'm still in the process of learning python at an intermediate level and i am running out of ideas of what to make. where can i get some good ideas for things to build and contribute to github? something actually useful, too.

I was just wanting a little side project so I'm writing a thing for scraping my banks website. It's probably against their ToS or whatever, but it's been enjoyable figuring out how their website works and writing the right code to scrape it and setting up nice looking classes and well structured code.

mononvc
Nov 20, 2012

Fractale posted:

i'm still in the process of learning python at an intermediate level and i am running out of ideas of what to make. where can i get some good ideas for things to build and contribute to github? something actually useful, too.

there's myriad things you can do. kinda depends what you're interested in. ofc scraping seems pretty popular. graphics (vispy), game stuff, audio synthesis (dsp) or parsing, django Web stuff, procedural crap, chat clients, encryption or secure things... networking , number crunching (?? ???) mathsy poo poo ,algos (fortunes algorithm I'm working on atm for example) .. learn concurrency like asyncio or twisted .. Some thing like decorators if u don't know that poo poo.. stuff to automate ur life, track poo poo.. plugins? esolang interpreter ,nlp/nlg

like I said depends what ur into

mononvc fucked around with this message at 09:13 on Aug 14, 2015

duck monster
Dec 15, 2004

Spaseman posted:

A class is the constructor or blueprint that is used to create instances that can be edited but the constructor itself is not actually changed in any way, correct?

Not quite but close

Think of it as the difference between a concept and an object. The class *defines* something. The object is an *instance* of it.

Dog is a class. Fido is an object of type Dog.

A constructor is specifically code that runs when the an instance of the class is made. Its a function that sets the new object up. Conversely a destructor pulls it down, but we dont really use destructors in python typically.

KernelSlanders
May 27, 2013

Rogue operating systems on occasion spread lies and rumors about me.

SurgicalOntologist posted:

Figured out the bytes thing. It had to be dev.write([0xA1]) (i.e. it expected an iterable).

Yeah that makes sense. Glad you got it working.

Fluue
Jan 2, 2008
It's been a bit since I've used Python for CSV parsing, so this might be a stupid design issue I'm overlooking:

I have a CSV file formatted like this:
pre:
time    value    par    frame
1       111                          
1.1     h        
1.12    e        
1.13    y
Meaning that each character is on its own row in the value column. I want to iterate over the CSV file and make a human-readable format of the CSV output. I really only want to deal with the value column, so what I think I need to do is:

1. Iterate over the rows and build a list of entries in a list
2. Somehow concatenate the entries in the list to make a human-readable string

Is there some idiomatic way I'm overlooking? I'm thinking it's a simple iteration problem, but it seems like there is a more efficient way I'm not thinking about.

SurgicalOntologist
Jun 17, 2004

KernelSlanders posted:

Yeah that makes sense. Glad you got it working.

Thanks! Controlling a treadmill from the command line is kind of cool.


Fluue posted:

It's been a bit since I've used Python for CSV parsing, so this might be a stupid design issue I'm overlooking:

I have a CSV file formatted like this:
pre:
time    value    par    frame
1       111                          
1.1     h        
1.12    e        
1.13    y
Meaning that each character is on its own row in the value column. I want to iterate over the CSV file and make a human-readable format of the CSV output. I really only want to deal with the value column, so what I think I need to do is:

1. Iterate over the rows and build a list of entries in a list
2. Somehow concatenate the entries in the list to make a human-readable string

Is there some idiomatic way I'm overlooking? I'm thinking it's a simple iteration problem, but it seems like there is a more efficient way I'm not thinking about.

I think what you want is this pandas operation. Although you will have to get a column that has all the same values of time.
Python code:
data = pd.read_table(filename, ...)
data['time_with_index'] = data['time']
data['time'] = data['time'].astype(int)
data['index'] = data['time_with_index'] - data['time']

unstacked_data = data.pivot(index='time', columns='index', values='value')
concatenated_by_row = unstacked_data.sum(axis=1)
With your example data this gives a Series with
code:
time
1           111hey
If you don't want the 111 in there you could change this line
Python code:
unstacked_data = data.pivot(index='time', columns='index', values='value').drop(0, axis=1)

SurgicalOntologist fucked around with this message at 03:25 on Aug 15, 2015

salisbury shake
Dec 27, 2011
Continuum guys: how do you like it over there

Cingulate
Oct 23, 2012

by Fluffdaddy

Fluue posted:

It's been a bit since I've used Python for CSV parsing, so this might be a stupid design issue I'm overlooking:

I have a CSV file formatted like this:
pre:
time    value    par    frame
1       111                          
1.1     h        
1.12    e        
1.13    y
Meaning that each character is on its own row in the value column. I want to iterate over the CSV file and make a human-readable format of the CSV output. I really only want to deal with the value column, so what I think I need to do is:

1. Iterate over the rows and build a list of entries in a list
2. Somehow concatenate the entries in the list to make a human-readable string

Is there some idiomatic way I'm overlooking? I'm thinking it's a simple iteration problem, but it seems like there is a more efficient way I'm not thinking about.
I'm not sure I get the question, but: do you want to make a single string out of the whole value column?

import pandas as pd
df = pd.read_csv(csv_filename)
print("".join(df["value"]))

Sure, you could do it without pandas, but if you ever deal with csv, you're gonna use pandas eventually.

The Fool
Oct 16, 2003


Cingulate posted:

Sure, you could do it without pandas, but if you ever deal with csv, you're gonna use pandas eventually.

What does pandas do that the built in csv module doesn't ?

I just did a small project working with a set of csv files and dictreader handled the job perfectly.

Cingulate
Oct 23, 2012

by Fluffdaddy

The Fool posted:

What does pandas do that the built in csv module doesn't ?
Is that literally the question you want to ask? Because if yes: a billion things. Pandas is the primary Python way of dealing with (empirical) data below the actual big data scale. If the only thing you want to do with a csv is literally what Fluee asked about, Pandas would be overkill, but if you actually want to work with data (ie., clean it, reorganize it, operate on it, analyse it, plot it ...), Pandas is the standard module for that.

(Also, I don't understand how I managed to miss SO's post ...)

Fluue
Jan 2, 2008

SurgicalOntologist posted:


I think what you want is this pandas operation. Although you will have to get a column that has all the same values of time.


Yep this was perfect. Thanks for the intro to Panda, it'll be handy when doing more CSV parsing later.

Hadlock
Nov 9, 2004

I want to write a really simple python application, that is listening for certain keypresses (arrow keys, space bar) in the console, and based on input executes a function. It's a 2 wheeled R2D2 type robot.

initial loading parameters so far is

code:
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(5, GPIO.OUT)
GPIO.setup(6, GPIO.OUT)
GPIO.setup(13, GPIO.OUT)
GPIO.setup(19, GPIO.OUT)
GPIO.setup(26, GPIO.OUT)
GPIO.setup(12, GPIO.OUT)
A = GPIO.PWM(5, 200)  # create an object p for PWM on port 25 at 50 Hertz
h1 = GPIO.output(6, 1)
h2 = GPIO.output(13, 0)
h3 = GPIO.output(19, 1)
h4 = GPIO.output(26, 0)
B = GPIO.PWM(12, 200)
Pushing the up key would execute

code:
A.start(50) 
B.start(50) 
Pushing it again would execute

code:
A.start(80) 
B.start(80) 
Pushing left would execute
code:
A.start(30) 
B.start(70) 
etc etc and space bar would end

code:
A.stop() 
B.stop() 
What kind of framework do I need to use here? Some sort of curses/clint thing? I will probably write a node.js front end with mouse control down the road but I'm more interested in driving my robot around and enjoying it without it running in to a wall before I can type in the relevant commands to turn it manually. I don't need any fancy GUI, just a blank screen that maybe writes out "LEFT" or "RIGHT" when I push those buttons.

Hadlock fucked around with this message at 08:42 on Aug 17, 2015

The March Hare
Oct 15, 2006

Je rêve d'un
Wayne's World 3
Buglord
Curses will do that yeah, it's in the stdlib.

1000101
May 14, 2003

BIRTHDAY BIRTHDAY BIRTHDAY BIRTHDAY BIRTHDAY BIRTHDAY FRUITCAKE!
I'm working with VMware's vRealize API and to provision VMs I need to send it a pretty hefty chunk of JSON. I figured if I could just make a class I could stuff in an import and just have it build the JSON for me then I could avoid my actual scripts that build VMs having shitloads of JSON in them. I'm basically trying to assemble a class I can feed a dict of values and have it spit out the JSON.

I'd want usage to look something like this:


Python code:
# create an instance
x = MyClass(inputs)

# grab the data and stuff it into input_json
input_json = x.input_json

# feed it to another function to make the required REST calls. 
build_vm(input_json)

My concern is that I may be abusing @property in a way it wasn't meant to be abused. I'm also wondering if there are better ways to do this. I've only been working with Python on and off for a couple of months now so I'm doing a bit of guessing here. Does this class make sense?

Python code:
class CatalogRequest(object):

    def __init__(self, build_input, username):

        self.username = username
        self.build_input = build_input

    @property
    def build_input(self):
        return json.dumps(self._build_input)

    @build_input.setter
    def build_input(self, jsondata):
        username = self.username
        offering = jsondata['offering']
        label = jsondata['label']
        vcpucount = jsondata['vcpucount']
        ramcount = jsondata['ramcount']
        leaseduration = jsondata['leaseduration']
        instancecount = jsondata['instancecount']
        description = jsondata['description']
        blueprintid = jsondata['blueprintid']
        data = {"@type": "CatalogItemRequest",
                             "state": "SUBMITTED",
                             "description": description,
                             "reasons": description,
                             "requestedFor": username,
                             "requestedBy": username,
                             "organization": {
                                 "tenantRef": "fooco",
                                 "tenantLabel": "fooco",
                                 "subtenantRef": "f41a35f5-040e-42e0-a5c2-6ca4e7bf328b",
                                 "subtenantLabel": "SubTenantGoesHere"
                             },
                             "requestData": {
                                 "entries": [
                                     {
                                         "key": "provider-blueprintId",
                                         "value": {
                                             "type": "string",
                                             "value": blueprintid
                                         }
                                     },
                                     {
                                         "key": "provider-Cafe.Shim.VirtualMachine.MaxCost",
                                         "value": {
                                             "type": "string",
                                             "value": "0"
                                         }
                                     },
                                     {
                                         "key": "provider-Cafe.Shim.VirtualMachine.TotalStorageSize",
                                         "value": {
                                             "type": "decimal",
                                             "value": 60.0
                                         }
                                     },
                                     {
                                         "key": "provider-provisioningGroupId",
                                         "value": {
                                             "type": "string",
                                             "value": "f41a35f5-040e-42e0-a5c2-6ca4e7bf328b"
                                         }
                                     },
                                     {
                                         "key": "provider-Cafe.Shim.VirtualMachine.AssignToUser",
                                         "value": {
                                             "type": "string",
                                             "value": username
                                         }
                                     },
                                     {
                                         "key": "provider-VirtualMachine.LeaseDays",
                                         "value": {
                                             "type": "integer",
                                             "value": leaseduration
                                         }
                                     },
                                     {
                                         "key": "provider-Cafe.Shim.VirtualMachine.Description",
                                         "value": {
                                             "type": "string",
                                             "value": description
                                         }
                                     },
                                     {
                                         "key": "provider-VirtualMachine.Disk0.IsClone",
                                         "value": {
                                             "type": "string",
                                             "value": "true"
                                         }
                                     },
                                     {
                                         "key": "provider-Cafe.Shim.VirtualMachine.Reason",
                                         "value": {
                                             "type": "string",
                                             "value": description
                                         }
                                     },
                                     {
                                         "key": "provider-Cafe.Shim.VirtualMachine.NumberOfInstances",
                                         "value": {
                                             "type": "integer",
                                             "value": instancecount
                                         }
                                     },
                                     {
                                         "key": "provider-VirtualMachine.CPU.Count",
                                         "value": {
                                             "type": "integer",
                                             "value": vcpucount
                                         }
                                     },
                                     {
                                         "key": "provider-__Notes",
                                         "value": {
                                             "type": "string",
                                             "value": description
                                         }
                                     },
                                     {
                                         "key": "provider-VirtualMachine.Disk0.Size",
                                         "value": {
                                             "type": "string",
                                             "value": "60"
                                         }
                                     },
                                     {
                                         "key": "provider-Cafe.Shim.VirtualMachine.MinCost",
                                         "value": {
                                             "type": "string",
                                             "value": "0"
                                         }
                                     },
                                     {
                                         "key": "provider-VirtualMachine.Memory.Size",
                                         "value": {
                                             "type": "integer",
                                             "value": ramcount
                                         }
                                     }
                                 ]
                             },
                             "retriesRemaining": 3,
                             "requestedItemName": label,
                             "requestedItemDescription": description,
                             "stateName": "Successful",
                             "executionStatus": "STOPPED",
                             "waitingStatus": "NOT_WAITING",
                             "approvalStatus": "POST_APPROVED",
                             "phase": "SUCCESSFUL",
                             "catalogItemRef": {
                                 "id": offering,
                                 "label": label
                             }}

        self._build_input = data

SurgicalOntologist
Jun 17, 2004

What does that gain you over just using a function?

Emacs Headroom
Aug 2, 2003
Second SurgicalOntologist's question about why not just use a normal method call.

I also have to ask why you have so much boilerplate data in the build_input method. Wouldn't it be cleaner and more maintainable to put that into a config or something, and read that into the class when you instantiate it?

1000101
May 14, 2003

BIRTHDAY BIRTHDAY BIRTHDAY BIRTHDAY BIRTHDAY BIRTHDAY FRUITCAKE!

Emacs Headroom posted:

Second SurgicalOntologist's question about why not just use a normal method call.

I also have to ask why you have so much boilerplate data in the build_input method. Wouldn't it be cleaner and more maintainable to put that into a config or something, and read that into the class when you instantiate it?

Probably so, I have no idea what I'm doing if I'm honest. I can't find much info on the best ways to do these things and the closest analogue to what I want is using XML but doesn't make much sense to me (I can't find XML templates for that particular library anywhere in the tree, it just seems like magic) The big reason that ugly mess of JSON is in the class right now is I'm not 100% sure the best way to just stuff it in a file somewhere and then easily replace the fields I want with the values I want. When I noodled on it it seemed like I might need to use something like jinja2 which I'm open to but i just want to make sure I'm in the right ballpark.

As to why a class and not just a function; there's a few methods I left out that were relatively straightforward to me (related to managing catalog items) and I wanted the option potentially recycle the object elsewhere. It's also partially an exercise to get a better understanding of when/where to use classes. I'm actually replacing functions that currently exist and trying to get a better understanding for how https://github.com/vmware/pyvcloud/ works. It's pretty much my first class beyond the samples people would copy/paste from a couple google searches.

Emacs Headroom
Aug 2, 2003

1000101 posted:

I'm actually replacing functions that currently exist and trying to get a better understanding for how https://github.com/vmware/pyvcloud/ works. It's pretty much my first class beyond the samples people would copy/paste from a couple google searches.

Ah I see. Well tbh, I'm not sure this code is the best example of the way to do production Python. In particular, there are a lot of magic strings all over the place, including urls, which is annoying to maintain.

A couple of principles I could see helping are:
(1) avoid magic values wherever possible
(2) try to make explicit data schemas as much as possible

Using Avro or something like that is probably overkill (although it would give you some real benefits if this is to be production-ized), but one simple option could be to actually put all that magic boilerplate into a json-formatted file, with all the missing fields set to null. Then refactor your class to expect a dictionary for the skeleton output json (maybe check that it contains expected keys). Nix your current property annotations, and just have a single non-__init__ method called 'format_request(self, request_dict, output="json")' or something. Have that method deepcopy the skeleton json, then slide in the new values from the request_dict, and return the json-serialized result.

1000101
May 14, 2003

BIRTHDAY BIRTHDAY BIRTHDAY BIRTHDAY BIRTHDAY BIRTHDAY FRUITCAKE!

Emacs Headroom posted:

Ah I see. Well tbh, I'm not sure this code is the best example of the way to do production Python. In particular, there are a lot of magic strings all over the place, including urls, which is annoying to maintain.

A couple of principles I could see helping are:
(1) avoid magic values wherever possible
(2) try to make explicit data schemas as much as possible

Using Avro or something like that is probably overkill (although it would give you some real benefits if this is to be production-ized), but one simple option could be to actually put all that magic boilerplate into a json-formatted file, with all the missing fields set to null. Then refactor your class to expect a dictionary for the skeleton output json (maybe check that it contains expected keys). Nix your current property annotations, and just have a single non-__init__ method called 'format_request(self, request_dict, output="json")' or something. Have that method deepcopy the skeleton json, then slide in the new values from the request_dict, and return the json-serialized result.

I appreciate this insight as I really start to get lost trying to follow that code (I really just need to start looking at standard library code instead of poo poo from vendors I'm integrating the products with). I've never heard the term 'magic strings' or 'magic values' before so I'll go poking around to understand that more to avoid doing it in the future.

I think I'm going to go ahead with what you're suggesting. To make sure I understand you right, dump the actual json somewhere in the module path (say in a templates directory); when I need it, read it in as a dict then just set the values I need like I was setting them in a dictionary. Then return the final JSON just like before.

I'm also going to read about Avro since that sounds kind of interesting. It won't make this go-round but maybe in 6 months.

Cingulate
Oct 23, 2012

by Fluffdaddy
I very often find myself doing something like this:

code:
def expensive_computation(input):
    more_stuff = do_something_simple(input)
    a_thing = do_something_complicated_with_stuff(input, more_stuff)
    return more_stuff, a_thing

list_of_tuples = [expensive_computation(thing) for thing in things]
things = [thing for _, thing in list_of_tuples]
stuff = [stuff for stuff, _ in list_of_tuples]
I don't assume I could somehow have something like
code:
things, stuff = [expensive_computation(thing) for thing in things]
?

Adbot
ADBOT LOVES YOU

KICK BAMA KICK
Mar 2, 2009

things, stuff = zip(*list_of_tuples)

  • Locked thread