Am I being dumb here?
I would like to know if I have a list called cons=['gps-ops', 'beidou'] and in my code there are different names for the same thing. i.e: 'gps-ops' = 'GPS' and 'beidou'='BDS'.
Some parts of the code (class) takes 'gps-ops' and some parts take 'GPS'. At the moment I have been using if and elif statements at different sections of the code.
Is there a way to say 'gps-ops' is also 'GPS' and vice versa, depending on how the user inputs the string throughout the code?
You could put every word for each valid name in a set like {'gps-ops', 'GPS'} and then go through your list in a for loop and check if that word is in the set:
gps_set = {'gps-ops', 'GPS'}
for name in cons:
if name in gps_set:
# do somehthing if true
Read the python docs for sets, they're quite an amazing data structure
Related
I have only been programing or coding or whatever it is that I am doing for a few days and could use a hand figuring out what I need to research to figure out what I am trying to do. I am working on a project for charity so I dont really want to learn all kinds of things I will probably never use again so I was hoping someone could tell me how to do this or point me in the direction of what I need to learn to make this happen.
So I have created a crawler that goes and types text into a search bar, Eggs for example and then takes me to the eggs results and captures the data, brand, price, count ect.
searchBox.send_keys(v.S1)
My problem is I can not figure out how to change v.S1 into V.S2 so I can automate going thru many searches without having to copy an paste the code over and over again.
I am working with a main.py to call the functions, a functions.py to store the functions and a variables.py to store the list of variables as S1-S2-S3 ect.
I have been able to to get searchBox.send_keys(v.S1) to work as searchBox.send_keys(X) with a variable X = v.S1
but for the life of me I can not figure out how to add +1 to make X = v.S2 after the function completes the first search.
So far all the information I have needed has been under the same By.CLASS_NAME but I have set those to a variable as well since I may need to change some of those on a per case basis as I go as well.
Well any help or someone pointing me in the right direction would be appreciated. Thanks.
To pass a character sequence e.g. v.S1, v.S2, v.S3, etc you can use the range() function and use argument-unpacking operator i.e. * and finally append it to the constant string v.S
elements = [*range(1,6,1)]
elements = ['v.S{0}'.format(element) for element in elements]
print(elements)
# prints -> ['v.S1', 'v.S2', 'v.S3', 'v.S4', 'v.S5']
I suggest you to add all the S1,S2.... variables in a list or tuple and then iterate using a simple for loop like,
# varlist is a list containing all variables
for i in varlist:
searchBox.send_keys(i)
Let's say I have a list of text files (song lyrics) to return based on the user input:
song_1.txt
song_2.txt
...
song_n.txt
I'm not happy with the idea of listing all of them at once for the user to choose from, so my initial thought was to create a simple function that takes user input as an argument, performs a search against a list of pre-defined keywords per song and returns the "best matching song" as a response.
I'm fairly new to python and programming in general and best thing I could think of so far is something like that:
keywords = {'song_1': ['hate', 'bad'], 'song_2': ['love', 'good']}
def find_song_by_keyword(user_input):
for song, keyword in keywords.items():
if user_input in keyword:
return song + '.txt'
result = find_song_by_keyword('love')
print(result)
song_2.txt
Then I'm going to read a song from file and return it to the user, but my question is:
What's the best way to match a string to keywords considering the fact I need to trace back the "key"? I have a feeling there's a better solution to match something to keywords instead of using for loop + dictionary with list as a value. Just looking for some directions on that matter in general (I'd appreciate a link to something related to "search" in general, maybe something deeper than that).
There's nothing wrong with using a for-loop, especially since you exit when you find the first match and that appears to be what you need.
However, you could get the key like this as well:
result = next((song for song, words in keywords.items() if 'love' in words), None)
Or, if you don't want to repeat yourself and you need to use this in several places, just wrap that in a function definition of course:
def find_song_by_keyword(user_input):
return next((song for song, words in keywords.items() if user_input in words), None)
result = find_song_by_keyword('love')
Solutions like inverting the dictionary can be a good idea if you have to do this very frequently, since you're trading space for better performance, but of course the action of inverting takes some time as well, so it doesn't appear to match your use case very well.
User #Barmar does make a good point that the original dictionary could be created as a dictionary of 'search term -> file name' instead of the current 'file name -> search term'. You could likely construct a dictionary with search terms as keys about as possibly as you construct the current dictionary, depending on how you plan to construct it.
I have the following parameters in a Python file that is used to send commands pertaining to boundary conditions to Abaqus:
u1=0.0,
u2=0.0,
u3=0.0,
ur1=UNSET,
ur2=0.0,
ur3=UNSET
I would like to place these values inside a list and print that list to a .txt file. I figured I should convert all contents to strings:
List = [str(u1), str(u2), str(u3), str(ur1), str(ur2), str(ur3)]
This works only as long as the list does not contain "UNSET", which is a command used by Abaqus and is neither an int or str. Any ideas how to deal with that? Many thanks!
UNSET is an Abaqus/cae defined symbolic constant. It has a member name that returns the string representation, so you might do something like this:
def tostring(v):
try:
return(v.name)
except:
return(str(v))
then do for example
bc= [0.,1,UNSET]
print "u1=%s u2=%s u3=%s\n"%tuple([tostring(b) for b in bc])
u1=0. u2=1 u3=UNSET
EDIT simpler than that. After doing things the hard way I realize the symbolic constant is handled properly by the string conversion so you can just do this:
print "u1=%s u2=%s u3=%s\n"%tuple(['%s'%b for b in bc])
Sometimes, you need to define values dynamically, (like datetime now, random strings, random integers, file contents, etc.) and use them across different steps without being explicit or hard-coding the value.
So, my question is how could I define variables inside of steps (the correct way to do it) to use these variables in the following steps.
Some example
Given A random string of length "100" as "my_text"
And I log in to my platform
And I ask to add the following post:
| title | description |
| Some example of title | {{my_text}} |
When I submit the post form
Then The posts table shows these posts:
| title | description |
| Some example of title | {{my_text}} |
And I delete any post containing in the description "{{my_text}}"
This is a basic example trying to explain why I would like to define variables in steps and save them in the context to use it in the following steps.
My idea was to modify before_step and after_step methods... to set a variable in context to store my custom variables like this:
def before_step(context):
if not hasattr(context, 'vars'):
context.vars = {}
if hasattr(context, table) and context.table:
parse_table(context)
def parse_table(context):
# Here use a regex to check each cell and look for `"{{<identifier>}}"` and if match, replace the cell value by context.vars[identifier] so the step "the posts table shows these posts will never know what is `{{my_text}}` it will be abstract seeing the random string.
Scenarios Outline, use something like this defining variables like "<some_identifier>" and then for each example replace the value in the step.
It's basically to reproduce the behaviour but for any kind of step, simple or using tables.
Is it the right way to do something like this?
From Behave docs on the context:
When behave launches into a new feature or scenario it adds a new layer to the context, allowing the new activity level to add new values, or overwrite ones previously defined, for the duration of that activity. These can be thought of as scopes:
#given('I request a new widget for an account via SOAP')
def step_impl(context):
client = Client("http://127.0.0.1:8000/soap/")
// method client.Allocate(...) returns a dict
context.response = client.Allocate(customer_first='Firstname',
customer_last='Lastname', colour='red')
// context vars can be set more directly
context.new_var = "My new variable!"
#then('I should receive an OK SOAP response')
def step_impl(context):
eq_(context.response['ok'], 1)
cnv = str(context.new_var)
print (f"This is my new variable:'{cnv}'"
So, the value can be set using dot notation and retrieved the same.
To answer this question, one needs note:
Does the test data needs to be controlled externally? For example, test data can be inputed from command line so that the value can be chosen explicitly.
If the answer is no, then probably we should not bother hard coding anything in the feature file. And we can leave the data generated in one step, save it in context, and accessed again in any followed step.
The example I can think is exactly like what the question described. Do we care what the random text content we generated, posted and verified? Probably not. Then we should not expose such detail to user (i.e. feature file) since it is not important to the behaviour we are testing.
If the answer is yes, we do need a bit hack to make it happen. I am experiencing a case like this. What I want is to change the test data when I run the test so I don't have to hard code them in the feature files as in a table or scenario outline. How can I do this?
I can use -D option in command line to pass in as many user data as possible, which can then be accessed in context.config.userdata dictionary in any steps. If the number of test data is very limited. This approach is an easy way to go. But if the test data set contains many data that no one want type one by one in command line, it can be stored externally, for example, a ini file with section names like testdata_1...testdata_n, and thus a string can be passed in from command line to be used to address the section name in this config file. And the test data can be read out in either before_all, or before_scenario, etc., and get used in all steps.
In my experience , you cannot create a dynamic value in feature file.
for example, this step :
Given A random string of length "100" as "my_text"
I dont see any way to change {my_text} each time you run the scenario. (not consider to use behave -D to parse the value to context.config.userdata,I think it is also a wrong approach)
Even Scenario Outline, it actually splits to many scenarios. each scenario will have
different value but the value of {my_text} is already defined in Examples table for each scenario.
The way makes a step dynamic is using Step definition (Code layer).
You can generate a random number in step definition #given('A random string of length "100" as "{my_text}"')
And use context.my_text to store the created number and using it arround.
I also agree with Murphy Meng that you don't need to expose the generated random number
explicitly in feature file. You know which step will use that number, simply use context.my_text in that step to get the value. That's it.
I'm fairly new to python and have found that I need to query a list about whether it contains a certain item.
The majority of the postings I have seen on various websites (including this similar stackoverflow question) have all suggested something along the lines of
for i in list
if i == thingIAmLookingFor
return True
However, I have also found from one lone forum that
if thingIAmLookingFor in list
# do work
works.
I am wondering if the if thing in list method is shorthand for the for i in list method, or if it is implemented differently.
I would also like to which, if either, is more preferred.
In your simple example it is of course better to use in.
However... in the question you link to, in doesn't work (at least not directly) because the OP does not want to find an object that is equal to something, but an object whose attribute n is equal to something.
One answer does mention using in on a list comprehension, though I'm not sure why a generator expression wasn't used instead:
if 5 in (data.n for data in myList):
print "Found it"
But this is hardly much of an improvement over the other approaches, such as this one using any:
if any(data.n == 5 for data in myList):
print "Found it"
the "if x in thing:" format is strongly preferred, not just because it takes less code, but it also works on other data types and is (to me) easier to read.
I'm not sure how it's implemented, but I'd expect it to be quite a lot more efficient on datatypes that are stored in a more searchable form. eg. sets or dictionary keys.
The if thing in somelist is the preferred and fastest way.
Under-the-hood that use of the in-operator translates to somelist.__contains__(thing) whose implementation is equivalent to: any((x is thing or x == thing) for x in somelist).
Note the condition tests identity and then equality.
for i in list
if i == thingIAmLookingFor
return True
The above is a terrible way to test whether an item exists in a collection. It returns True from the function, so if you need the test as part of some code you'd need to move this into a separate utility function, or add thingWasFound = False before the loop and set it to True in the if statement (and then break), either of which is several lines of boilerplate for what could be a simple expression.
Plus, if you just use thingIAmLookingFor in list, this might execute more efficiently by doing fewer Python level operations (it'll need to do the same operations, but maybe in C, as list is a builtin type). But even more importantly, if list is actually bound to some other collection like a set or a dictionary thingIAmLookingFor in list will use the hash lookup mechanism such types support and be much more efficient, while using a for loop will force Python to go through every item in turn.
Obligatory post-script: list is a terrible name for a variable that contains a list as it shadows the list builtin, which can confuse you or anyone who reads your code. You're much better off naming it something that tells you something about what it means.