How to import/reference multiple pytest fixtures without wildcard import? - pytest

Currently I use the following setup to import pytest fixtures from a file called fixtures.py and run tests with them:
from django.contrib.auth.models import User, Group
from django.core import mail
from main.tests.fixtures import user_a, group_dropoff_for_qc
def test_should_check_password(db, user_a: User) -> None:
user_a.set_password("secret")
assert user_a.check_password("secret") is True
# more tests here
As I write more tests and use more fixtures, that import list from main.tests.fixtures grows really long. Is there some built-in pytest way around this? This seems like such a common operation that there should be a more streamlined approach.

Found the answer on my own, so here is the solution in case this helps anyone else.
Solution source: https://www.tutorialspoint.com/pytest/pytest_conftest_py.htm
If you rename an exterior file that contains fixtures to conftest.py, you can reference the fixtures in that file without needing to explicitly import them. So in my case above, I just had to rename my fixtures.py to conftest.py, which allowed me to run the tests as expected, without the import statement:
from django.contrib.auth.models import User, Group
from django.core import mail
def test_should_check_password(db, user_a: User) -> None:
user_a.set_password("secret")
assert user_a.check_password("secret") is True
# more code here

Related

How can I parametrize my fixture and get testdata to parametreize my tests

I'm a starter with pytest. Just learned about fixture and tried to do this:
My tests call functions I wrote, and get test data from a code practicing website.
Each test is from a particular page and has several sets of test data.
So, I want to use #pytest.mark.parametrize to parametrize my single test func.
Also, as the operations of the tests are samelike, I want to made the pageObject instantiation and the steps to get test data from page as a fixture.
# content of conftest.py
#pytest.fixture
def get_testdata_from_problem_page():
def _get_testdata_from_problem_page(problem_name):
page = problem_page.ProblemPage(problem_name)
return page.get_sample_data()
return _get_testdata_from_problem_page
# content of test_problem_a.py
import pytest
from page_objects import problem_page
from problem_func import problem_a
#pytest.mark.parametrize('input,expected', test_data)
def test_problem_a(get_testdata_from_problem_page):
input, expected = get_testdata_from_problem_page("problem_a")
assert problem_a.problem_a(input) == expected
Then I realized, as above, I can't parametrize the test using pytest.mark as the test_data should be given outside the test function....
Are there solutions for this? Thanks very much~~
If I understand you correctly, you want to write one parameterized test per page. In this case you just have to write a function instead of a fixture and use that for parametrization:
import pytest
from page_objects import problem_page
from problem_func import problem_a
def get_testdata_from_problem_page(problem_name):
page = problem_page.ProblemPage(problem_name)
# returns a list of (input, expected) tuples
return page.get_sample_data()
#pytest.mark.parametrize('input,expected',
get_testdata_from_problem_page("problem_a"))
def test_problem_a(input, expected):
assert problem_a.problem_a(input) == expected
As you wrote, a fixture can only be used as a parameter to a test function or to another fixture, not in a decorator.
If you want to use the function to get test data elsewhere, just move it to a common module and import it. This can be just some custom utility module, or you could put it into contest.py, though you still have to import it.
Note also that the fixture you wrote does not do anything - it defines a local function that is not called and returns.

Should classes be import when only used for type hints? PEP 560

What is the benefit of importing from __future__ import annotations? When I understand it right I should stop unnecessary typing import in runtime.
In my example HelloWorld is only needed for typing. But with this code the output always is:
Should this happen?
x = World!
When I remove from hello import HelloWorld the typing help in PyCharm does not longer work (I can understand this, because it does not understand where HelloWorld is from).
from __future__ import annotations
from hello import HelloWorld
if __name__ == '__main__':
def hello(x: str, hello: HelloWorld = None):
if hello is not None:
print('hello.data_01 =', hello.data_01)
print('x =', x)
hello('World!')
hello.py
from dataclasses import dataclass
#dataclass
class HelloWorld:
data_01: str
data_02: str
print("Should this happen?")
So my question is if I still need to do from hello import HelloWorld what benefits do I get from from __future__ import annotations?
The from __future__ import annotations import has one core advantage: it makes using forward references cleaner.
For example, consider this (currently broken) program.
# Error! MyClass has not been defined yet in the global scope
def foo(x: MyClass) -> None:
pass
class MyClass:
# Error! MyClass is not defined yet, in the class scope
def return_copy(self) -> MyClass:
pass
This program will actually crash when you try running it at runtime: you've tried using 'MyClass' before it's actually ever defined. In order to fix this before, you had to either use the type-comment syntax or wrap each 'MyClass' in a string to create a forward reference:
def foo(x: "MyClass") -> None:
pass
class MyClass:
def return_copy(self) -> "MyClass":
pass
Although this works, it feels very janky. Types should be types: we shouldn't need to have to manually convert certain types into strings just to make types play nicely with the Python runtime.
We can fix this by including the from __future__ import annotations import: that line automatically makes all types a string at runtime. This lets us write code that looks like the first example without it crashing: since each type hint is actually a string at runtime, we're no longer referencing something that doesn't exist yet.
And typecheckers like mypy or Pycharm won't care: to them, the type looks the same no matter how Python itself chooses to represent it.
One thing to note is that this import does not, by itself, let us avoid importing things. It simply makes it cleaner when doing so.
For example, consider the following:
from expensive_to_import_module import MyType
def blah(x: MyType) -> None: ...
If expensive_to_import_module does a lot of startup logic, that might mean it takes a non-negligible amount of time to import MyType. This won't really make a difference once the program is actually running, but it does make the time-to-start slower. This can feel particularly bad if you're trying to write short-lived command-line style programs: the act of adding type hints can sometimes make your program feel more sluggish when starting up.
We could fix this by making MyType a string while hiding the import behind an if TYPE_CHECKING guard, like so:
from typing import TYPE_CHECKING
# TYPE_CHECKING is False at runtime, but treated as True by type checkers.
# So the Python interpreters won't do the expensive import, but the type checker
# will still understand where MyType came from!
if TYPE_CHECKING:
from expensive_to_import_module import MyType
# This is a string reference, so we don't attempt to actually use MyType
# at runtime.
def blah(x: "MyType") -> None: ...
This works, but again looks clunky. Why should we need to add quotes around the last type? The annotations future import makes the syntax for doing this a little smoother:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from expensive_to_import_module import MyType
# Hooray, no more quotes!
def blah(x: MyType) -> None: ...
Depending on your point-of-view, this may not seem like a huge win. But it does help make using type hints much more ergonomic, makes them feel more "integrated" into Python, and (once these become enabled by default) removes a common stumbling block newcomers to PEP 484 tend to trip over.

Why am I importing so many classes?

I'm looking at example Spark code and I'm a bit confused as to why the sample code I'm looking at requires two import statements:
import org.apache.spark._
import org.apache.spark.SparkContext._
This is Scala. As I understand it, _ is the wildcard character. So this looks like I'm importing SparkContext twice. Can anybody shed light on this?
This first line says to import all of the classes in the package org.apache.spark. This means you can use all of those classes without prefixing them with the package name.
The second line says to import all of the static members of the class SparkContext. This means you can use those members without prefixing their names with the class name.
Remember import doesn't really do anything at run time; it just lets you write less code. You aren't actually "importing" anything twice. The use of the term import comes from Java, and admittedly it is confusing.
This might help:
Without the first line, you would have to say
org.apache.spark.SparkContext
but the first import line lets you say
SparkContext
If you had only the first line and not the second, you would have to write
SparkContext.getOrCreate
but with both import lines you can just write
getOrCreate

Cats: how to find the specific type from implicits

I have this code which compiles and works fine
import cats.implicits._
Cartesian[ValidResponse].product(
getName(map).toValidated,
readAge(map).toValidated
).map(User.tupled)
However I don't like the import of cats.implicits._ because there is just too many classes there. I tried importing specific things related to Cartesians like
import cats.implicits.catsSyntaxCartesian
import cats.implicits.catsSyntaxUCartesian
import cats.implicits.catsSyntaxTuple2Cartesian
But these did not work. As a newbie I find the implicit imports very confusing because there are simply 1000s of them and the names are not very obvious. My only alternative is to import the entire universe by import cats.implicits._ and stop thinking about it.
In fact I have a broader confusion about cats.implicits, cats.instances._ and cats.syntax._. So far I am just importing these via trial and error. I am not really sure of when to import what.
Do not try to pick out specific things from cats.implicits. You either import the entire thing, or you don't use it at all. Further, there's no reason to be afraid of importing it all. It can't interfere with anything.
Ok, I lied. It will interfere if you import cats.instances.<x>._ and/or cats.syntax.<x>._ alongside cats.implicits._. These groups are meant to be mutually exclusive: you either import everything and forget about it with cats.implicits._, or you specifically select what you want to import with cats.instances and cats.syntax.
These two packages are not meant to be imported completely like cats.implicits. Instead, they include a bunch of objects. Each object contains some implicit instances/syntax, and you are meant to import from those.
import cats.implicits._ // Good, nothing to fear
// RESET IMPORTS
import cats.implicits.catsSyntaxCartesian // Bad, don't pick and choose
// RESET IMPORTS
import cats.instances._ // Bad, is useless
import cats.syntax._ // Ditto
// RESET IMPORTS
import cats.instances.list._ // ok
import cats.syntax.cartesian._ // ok
// RESET IMPORTS
import cats.implicits._
import cats.syntax.monad._ // Bad, don't mix these two
Additionally each of cats.{ instances, syntax } contains an all object, with the obvious function. The import cats.implicits._ is really a shortcut for import cats.syntax.all._, cats.instances.all._.
I'll start by saying that import cats.implicits._ is safe, reasonable and the recommended approach when starting. So if the only reason for this question is that you don't like importing too many classes, then I think you should just bite the bulled at leave that as is.
Additionally, I recommend you take a look at the official cats import guide. It tries to explain the package/logical structure of cats code and might make it easier to understand.
The "cats" library is organized in several "areas" that can be easily distinguished by their package name:
cats._ - This is where most of the typeclasses live (e.g. Monad, Foldable etc.)
cats.data._ - This is the home of data structures like Validated and State.
cats.instances._ - This is where the instances for the typeclasses defined in 1 are. For example if you import cats.instances.list._ you'll bring into scope the Show, Monad etc. instances for the standard List. This is what you're most likely interested in.
cats.syntax._ - has some syntax enrichment that makes code easier to write and read.
An example of ussing cats.syntax._ would be:
import cats.Applicative
import cats.syntax.applicative._
val listOfInt = 5.pure[List]
//instead of
val otherList = Applicative[List[Int]].pure(5)

Managing imports in Scalaz7

I am using scalaz7 in a project and sometimes I run into issues with imports. The simplest way get started is
import scalaz._
import Scalaz._
but sometimes this can lead to conflicts. What I have been doing until now the following slightly painful process:
work out a minimal example that needs the same imports as my actual code
copy that example in a separate project
compile it with the option -Xprint:typer to find out how the code looks after implicit resolution
import the needed implicits in the original project.
Although this works, I would like to streamline it. I see that scalaz7 has much more fine-grained imports, but I do not fully understand how they are organized. For instance, I see one can do
import scalaz.std.option._
import scalaz.std.AllInstances._
import scalaz.std.AllFunctions._
import scalaz.syntax.monad._
import scalaz.syntax.all._
import scalaz.syntax.std.boolean._
import scalaz.syntax.std.all._
and so on.
How are these sub-imports organized?
As an example, say I want to work with validations. What would I need, for instance to inject validation implicits and make the following compile?
3.fail[String]
What about making ValidationNEL[A, B] an instance of Applicative?
This blog post explains the package structure and imports a la carte in scalaz7 in detail: http://eed3si9n.com/learning-scalaz-day13
For your specific examples, for 3.failure[String] you'd need:
import scalaz.syntax.validation._
Validation already has a method ap:
scala> "hello".successNel[Int] ap ((s: String) => "x"+s).successNel[Int]
res1: scalaz.Validation[scalaz.NonEmptyList[Int],java.lang.String] = Success(xhello)
To get the <*> operator, you need this import:
import scalaz.syntax.applicative._
Then you can do:
"hello".successNel[Int] <*> ((s: String) => "x"+s).successNel[Int]