Hey folks, how should I set up a python target tha...
# general
m
Hey folks, how should I set up a python target that has a build step? Specifically, I'm using the Prisma Python Client (
prisma
pypi package). Coming from Poetry, I need to run
prisma generate
in my venv after
poetry install
.
prisma generate
reads the prisma schema, generates python classes, and writes the generated code to the
prisma
site-packages folder. Then application code consumes the generated code from the site package as
from prisma import models
.
1
b
Hmm, interesting question. I think writing to the site-packages folder of the venv is… unexpected behaviour for a code generation step. Pants generally supports code gen where it becomes a “normal” file, more like if it was manually placed adjacent to the normal code. Does prisma have options to change how the codegen works?
m
Yes I can generate to somewhere else, in my repo. I am still not sure how to proceed pants-wise in that case
b
Ah cool. One way would be using https://www.pantsbuild.org/2.19/docs/ad-hoc-tools/integrating-new-tools-without-plugins where the
runnable
is the prisma requirement target (something like
pants list :: | grep prisma
might find it) and you load up
execution_dependencies
with the code required as input, plus
output_files
pointing to the files that need to be exported. You’ll need to wrap this up in https://www.pantsbuild.org/2.19/reference/targets/experimental_wrap_as_python_sources after
Another option would be writing a plugin, which allows more direct control over every detail, but is potentially a bit more fiddly: https://www.pantsbuild.org/2.19/docs/writing-plugins/overview
m
cool, I will try the adhoc approach first. thanks!
Thanks, the adhoc tool did the trick!
Copy code
# The main target for this directory :foo_database.
python_sources(
    dependencies = [
        ":prisma_client",
        ":schema_files",
    ],
)

resources(
    name = "schema_files",
    sources = [
        "schema.prisma",
        "migrations/**/*",
    ],
)

# This generates the prisma client to foo/foo_database_prisma_client.
adhoc_tool(
    name = "prisma_generate",
    args = ["generate"],
    execution_dependencies = ["//components/foo/foo_database:schema_files"],
    log_output = True,
    output_dependencies = ["//:root#prisma"],
    output_directories = ["../foo_database_prisma_client"],
    root_output_directory = "components",
    runnable = "//:root#prisma",
)

experimental_wrap_as_python_sources(
    name = "prisma_client",
    inputs = [":prisma_generate"],

    # Include all files in sources. The generator produces python files and the
    # `schema.prisma` file.
    outputs = ["**"],
)
🎉 1
s
Hello I am sorry to reopen a very old thread. I have a similar issue and I trie de to apply the same solution. I have a service whose code is in a folder
services/foo-service
, inside services/foo-service, I have a file
db/schema.prisma
and the package
foo_service
. Previously, I was using default
prisma
generation and now I tried to modify so that the generated client would be in
foo_service/prisma
:
Copy code
# modified services/foo-service/db/schema.prisma to generate in foo_service
generator client {
  provider             = "prisma-client-py"
  recursive_type_depth = 5
  output               = "../foo_service/prisma"
}

# modified services/foo-service/BUILD file
python_sources()

files(name="db-schema", sources=["db/schema.prisma", "db/migrations/*"])


adhoc_tool(
    name="generate-db-schema",
    runnable="//:reqs#prisma",
    execution_dependencies=[":db-schema", "//:reqs#prisma"],
    args=["generate", "--schema=./db/schema.prisma"],
    output_directories=["foo_service/prisma"],
    root_output_directory=".",
    outputs_match_mode="all",
    log_output=True,
    workdir=".",
)

experimental_wrap_as_python_sources(
    name = "prisma_client",
    inputs = [":generate-db-schema"],

    # Include all files in sources. The generator produces python files and the
    # `schema.prisma` file.
    outputs = ["**"],
)

# modified python code using prisma in foo_service package
from foo_service.prisma import ...

# try to use the `prisma_client` in BUILD at the root of my repo
adhoc_tool(
    name="generate-schema",
    runnable="//services/foo-service/foo_service/custom_openapi_generator.py",
    args=["openapi.json"],
    execution_dependencies=[
        "//services/foo-service:prisma_client",
        "//:reqs",
    ],
    output_files=["openapi.json"],
    root_output_directory=".",
)
And I get the message:
ImportError: cannot import name 'Prisma' from 'foo_service.prisma
. In the sandbox, prisma code is copied at the root of the sandbox in
foo_service/prisma
folder... Thanks for any help 🙏
b
What action/goal/command are you doing that gives that error message?
s
I am executing pants test on a unit test in my service. I am a new user of pants and trying to use it as a build system for our Python mono repo.
b
Cool, thanks for the info. • When you say "in the sandbox", that's the sandbox for that unit test run? • Where's the rest of the "real" code in that sandbox? I.e what's the directory structure?
s
• When you say "in the sandbox", that's the sandbox for that unit test run?
Yes, it is an integration test, and here what the result of
ls
on that sandbox folder:
Copy code
ls pants-sandbox-*    
pants-sandbox-ExuorW:
__run.sh			custom_openapi_generator.pex_bin_python_shim.sh	foo_service		openapi.json			python-default.lock
custom_openapi_generator.pex				custom_openapi_generator.pex_pex_shim.sh		modules				pants-requirements.txt		services
• Where's the rest of the "real" code in that sandbox? I.e what's the directory structure?
foo_service
subfolder contains the
prisma
generated code.
services
subfolder contains the folder hierarchy with only the related real code
services/foo-services/foo_service/...
.
b
okay, I think you might want to try to get the new code generated within that same subfolder
s
Yes, that's already what I tried. But now I removed
root_output_directory="."
and
workdir="."
and it worked better. The code is now copied in the right place
services/foo-service/foo_service/prisma
.
Copy code
# modified services/foo-service/BUILD file
python_sources()

files(name="db-schema", sources=["db/schema.prisma", "db/migrations/*"])


adhoc_tool(
    name="generate-db-schema",
    runnable="//:reqs#prisma",
    execution_dependencies=[":db-schema", "//:reqs#prisma"],
    args=["generate", "--schema=./db/schema.prisma"],
    output_directories=["foo_service/prisma"],
    # root_output_directory=".",
    outputs_match_mode="all",
    log_output=True,
    # workdir=".",
)

experimental_wrap_as_python_sources(
    name = "prisma_client",
    inputs = [":generate-db-schema"],

    # Include all files in sources. The generator produces python files and the
    # `schema.prisma` file.
    outputs = ["**"],
)
Now, I have another issue with explicit requirements: if you import a 3rd party dependency and this dependency is not explicitly mentionned in the requirements, even if it is in the lock file, it will not be found by Pants. But this is definitely another issue. Thanks for the help
Oups, now I still have an import issue when I try to use the
prisma_client
source in the code below:
Copy code
# try to use the `prisma_client` in BUILD at the root of my repo
adhoc_tool(
    name="generate-schema",
    runnable="//services/foo-service/foo_service/custom_openapi_generator.py",
    args=["openapi.json"],
    execution_dependencies=[
        "//services/foo-service:prisma_client",
        "//:reqs",
    ],
    output_files=["openapi.json"],
    root_output_directory=".",
)
I get the error:
Copy code
File "/private/var/folders/_p/xy0kvhr934x35sqgprmvrz3h0000gp/T/pants-sandbox-LlGI1m/services/foo-service/foo_service/prisma/_config.py", line 9, in <module>
    import tomlkit
ModuleNotFoundError: No module named 'tomlkit'
I already added tomlkit explicitly in my requirements.txt. I checked
pants dependencies --transitive :generate-schema
and
:reqs#tomlkit
is present. What could be missing?
b
That's a dependency for running the code-generation, but not a dependency of the generated code. Potentially
output_dependencies=["//:reqs#tomlkit"]
is what you need (https://www.pantsbuild.org/prerelease/reference/targets/adhoc_tool#output_dependencies)
s
I tried that but it is not working either: in
$ROOT_FOLDER/services/foo-service/BUILD
I have:
Copy code
files(name="db-schema", sources=["db/schema.prisma", "db/migrations/*"])


adhoc_tool(
    name="generate-db-schema",
    runnable="//:reqs#prisma",
    execution_dependencies=[":db-schema", "//:reqs#prisma"],
    output_dependencies=["//:reqs#tomlkit"],
    args=["generate", "--schema=./db/schema.prisma"],
    output_directories=["foo_service/prisma"],
    outputs_match_mode="all",
    log_output=True,
)

experimental_wrap_as_python_sources(
    name = "prisma_client",
    inputs = [":generate-db-schema"],

    # Include all files in sources. The generator produces python files and the
    # `schema.prisma` file.
    outputs = ["**"],
)
Then in
$ROOT_FOLDER/BUILD
, I have
Copy code
adhoc_tool(
    name="generate-schema",
    runnable="//services/inference/inference_service/controller/api/export_openapi.py",
    args=["openapi.json"],
    execution_dependencies=[
        "//services/inference:prisma_client",
        "//:reqs",
    ],
    output_files=["openapi.json"],
    root_output_directory=".",
)

run_shell_command(
    name="run-generate-schema",
    execution_dependencies=[":generate-schema"],
    command="exit 0",  # if you just want to run shell command
)
When I run
pants run :run-generate-schema
it failed with the same error. When I run
pants dependencies :generate-schema
I get:
Copy code
//:reqs#tomlkit
services/inference:prisma_client
b
I'm not sure sorry. If you can create a standalone reduced example that demonstrates your problem and you can share, it'll be easier for me to help you.
🙏 1