Hi team! I’m trying to use context.solid.name to g...
# ask-community
a
Hi team! I’m trying to use context.solid.name to get a unique name for every op run within a run. For example, if I have one op that I’m calling twice within the same run, I want to get the unique string identifying a specific op run. (dagster usually appends a number, like op_2). 1. Am I right to assume context.solid.name is unique within a run? There won’t be any clashes? 2. I’m getting an error if I try to access “solid” from a context built using build_op_context. Whats the best way to do this?
Copy code
E       dagster.core.errors.DagsterInvalidPropertyError: The solid property is not set on the context when a solid is directly invoked.
c
Hi Andy. To answer your question in part, yes, the name of an op is unique across a run (and across a repository). The uniqueness of an op name is what allows Dagster to distinguish between ops that are invoked in many places within a repository that are defined the same otherwise.
a
Yes sorry that makes sense
But I'm trying to get access to the name of the op via the context
So let's say I have an op called “op_a” and I call “op_a” twice within the same job. (This is allowed). Dagster will rename this op to “op_a_1” and “op_a_2”, which is good. My question is “does context.solid.name” the right way to get access to “op_a_1”. I want that and not “op_a” because I want it to be specific for that particular call of that op
Separately, how do I use “context.solid.name” in tests?
If I'm using build_op_context
c
While using
build_op_context
you could
build_op_context().bind(op_def)
. This would pass the op definition to the constructed context and then you could access the op name.
a
Ok sweet. Sorry I've never seen this pattern before. Could you give me a little more code maybe?
Thank you!
c
To answer your question above, yes, in a call to
context.solid.name
dagster will return the aliased name of the op ("op_a_1").
Ah apologies, turns out what I wrote above with binding the op definition won't work. Would it be possible for you to try testing the whole job using
execute_in_process
? This would allow you to get the op name through the context object.
a
hm i havent tried, but I’m sure we could
oh the whole job
no we’re doing unit tests, so testing op by op, not the whole job
theres no way to attach the name from a unit test using build_op_context?
c
Well, dagster will only apply aliasing ("op_a" being called twice -> "op_a_2") in a job invocation. So an op invoked with context from
build_op_context
will simply have the name that it is defined with.
You could write:
Copy code
@op
def my_op(context):
    print(context.solid_def.name)
    return 1

with build_op_context() as context:
    my_op(context)
    print(my_op.name)
a
Wait sorry, In the unit test, I don't need op_2, that's fine that it doesn't append the number. But it doesn't even give me the op name in the unit test, it fails.
I'd be happy with just the op name from context.solid.name in the unit tests
Copy code
E       dagster.core.errors.DagsterInvalidPropertyError: The solid property is not set on the context when a solid is directly invoked.
Copy code
def test_my_test_op()
    context = build_op_context()
    op_result = my_test_op(context)
Copy code
@op
def my_test_op(context):
    <http://context.log.info|context.log.info>(context.solid.name)
pseudoocde, but that will faile
id be perfectly ahppy if the op printed “my_test_op”
c
Try writing
<http://context.log.info|context.log.info>(context.solid_def.name
instead of
context.solid.name
a
wait sorry @claire I need the number when the pipeline is actually running. so when I run the pipeline, I need “op_a_2”. but in tests, I’d be happy with “op_2"
solid_def.name doesn’t do the _2, even in the pipeline right?
or am i misunderstanding?
c
Yes, that's correct. solid_def.name would return
op_2
. I think if you want to test, you could try writing unit tests that run the job through
my_job.execute_in_process()
and then you'll be able to access the aliased name (
op_a_2
).
a
thats not what i’m seeing
solid_def.name returns “op_a”, even when its aliased
are you seeing something different?
is there any chance theres something more robust? like a uuid or something? something that ties to a specific “run” of an op
kinda like run_id but for a specific op
maybe thats an easier route to chase down
c
ah, to clarify, I mean that
solid_def.name
will always return
op_a
. But if you run the job an op that contains
context.solid.name
you'll get the aliased name
a
yeah that doenst work, I need the aliased thing
but i also need it to be testable
c
Why not test via
execute_in_process
? Then you'll be able to access the aliased name
a
because i’m testing specific ops
not the entire job
c
You can provide an op selection via
my_job.execute_in_process(op_selection=["my_op"])
a
I think there’s also another problem I’m seeing where if you have two different graphs using the same op, the name thing doesnt evenwork so lets say you have graph1 that calls op_a, and graph2 that calls op_a. In the ui, it shows up as “graph1.op_a” as the name. but context.solid.name just gives us “op_a”, but I want “graph1.op_a”. Is that how you understand it works?
I basically need a unique identifier for each run of an op in a job. similar to context.run_id but between ops
does that make sense?
c
Yep, that makes sense. One way around that is you could attach a job identifier (either the job name or the run id) to the log:
Copy code
@op
def my_test_op(context):
    <http://context.log.info|context.log.info>(f'{context.solid.name}.{context.run_id}')
Unfortunately that still doesn't solve the testability problem where
context.solid.name
is not available in the test context. We do have an issue tracking this though: https://github.com/dagster-io/dagster/issues/6493
a
i see
i think thats still not unique though
Copy code
(f'{context.solid.name}.{context.run_id}')
thats not unique because an op can be used in two different graphs
within a job
c
Got it. Instead, you could use the step key from the step execution context:
Copy code
@op
def my_op(context):
    print(context.run_id + "." + context.get_step_execution_context().step.key)
which will get you the key within a graph (e.g.
<http://my_graph.my|my_graph.my>_op
).
a
got it, interesting, ill take a look!
thanks
dagster yay 1