-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix/changes current working dir when using a dbt project dir #9596
Fix/changes current working dir when using a dbt project dir #9596
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding this @rariyama
I wonder what if you can add the __enter__
and __exit__
to just the base task so we only do it once?
Also tagging @MichelleArk to see if there are any thoughts on starting this with
pattern. It looks good to me.
Hi @ChenyuLInx . Thanks for your comments.
I would like to add test code for this update. I feel like it's good enough to add the following code to integration test but what do you think about?
|
@rariyama I saw your message in #8997 (comment) and checked the comments in this PR. Could you do these two things? After that we can have one of our engineers take another look:
def test_runner_invoke(self, project):
project_dir = project.project_root
runner = dbtRunner()
commands = ["deps", "clean", "init"]
# TODO: change to some other directory other than the dbt project root
for command in commands:
before_dir = os.getcwd()
res = runner.invoke([command, "--project-dir", project_dir, "--profiles-dir", project_dir])
self.assertEqual(res.success, True)
self.assertEqual(before_dir, os.getcwd()) The key thing will be to make sure the test actually captures the scenario in the bug report. i.e., you'll want to make sure that the test fails without your changes, but the test passes after you changes. |
Hi @dbeatty10. Thank you for checking my comment. I confirmed the results of both unittest and integration test are as expected by following ways.
I run the test code by the command If there's no remaining tasks I have to do, could you please have the engineers review it? |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #9596 +/- ##
==========================================
- Coverage 88.93% 88.92% -0.02%
==========================================
Files 180 180
Lines 22735 22760 +25
==========================================
+ Hits 20220 20239 +19
- Misses 2515 2521 +6
Flags with carried forward coverage won't be shown. Click here to find out more.
|
Hello Team. Could someone please review my PR? |
core/dbt/tests/util.py
Outdated
|
||
before_dir = os.getcwd() | ||
res = dbt.invoke(args) | ||
after_dir = os.getcwd() | ||
# The directory has not been changed after running dbt command. | ||
assert before_dir == after_dir |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like this assertion would be better if it were directly within a test rather than here. Maybe here instead?
What do you think @ChenyuLInx?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is great!! Also makes it checking all future commands.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added test code to tests/functional/dbt_runner/test_dbt_runner.py
in this commit.
26ec953
core/dbt/task/deps.py
Outdated
project.project_root = str(Path(project.project_root).resolve()) | ||
super().__init__(args=args) | ||
# N.B. This is a temporary fix for a bug when using relative paths via | ||
# --project-dir with deps. A larger overhaul of our path handling methods | ||
# is needed to fix this the "right" way. | ||
# See GH-7615 | ||
project.project_root = str(Path(project.project_root).resolve()) | ||
self.project = project | ||
|
||
move_to_nearest_project_dir(project.project_root) | ||
self.cli_vars = args.vars | ||
self.project = project |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rariyama Did you happen to check if preserving this order worked or not?
I'm wondering if you changed the ordering intentionally or if it was just an accidental side-effect when resolving merge conflicts.
i.e., I'm curious if this would work (which is basically identical to here except for removing the move_to_nearest_project_dir(project.project_root)
line):
super().__init__(args=args)
# N.B. This is a temporary fix for a bug when using relative paths via
# --project-dir with deps. A larger overhaul of our path handling methods
# is needed to fix this the "right" way.
# See GH-7615
project.project_root = str(Path(project.project_root).resolve())
self.project = project
self.cli_vars = args.vars
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed the order of variables as you wrote in this commit.
4191735
I confirmed integration test passed on my local environment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @rariyama for thinking through this and submit this PR. This change makes sense to me!
Since this is something that modifies the behavior of directory I would like to play with it a bit more locally before giving it the approve and merge.
…t_dir1' of https://github.com/rariyama/dbt-core into fix/changes_current_working_dir_when_using_a_dbt_project_dir1
@ChenyuLInx |
@@ -202,6 +200,7 @@ def lock(self) -> None: | |||
fire_event(DepsLockUpdating(lock_filepath=lock_filepath)) | |||
|
|||
def run(self) -> None: | |||
move_to_nearest_project_dir(self.args.project_dir) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did move_to_nearest_project_dir(self.args.project_dir)
need to move to this location in order for things to work?
Or was it "nice-to-have" for some reason?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a reason for moving the move_to_nearest_project_dir()
function. The DepsTask
class inherits from the BaseTask
class and is designed to behave as a context manager. In BaseTask
, the current directory is obtained within __enter__()
, and os.chdir()
is called within __exit__()
to return to the previously obtained directory.
Normally, since __init__()
is executed before __enter__()
, if move_to_nearest_project_dir()
is called inside __init__()
, the directory after the move will be recorded, and it will not return correctly to the original directory.
The sequence of events can be described as follows:
__init__().move_to_nearest_project_dir()
# Moves to the project directory.__enter__().os.getcwd()
# Gets the current directory, which is the project directory.__exit__().os.chdir()
# Moves back to the project directory obtained in step 2.
By moving the move_to_nearest_project_dir()
function to the run()
function, the order of execution changes as follows:
__enter__().os.getcwd()
# Gets the current directory, i.e., the directory wheredbt run
is executed.DepsTask.run().move_to_nearest_project_dir()
# Moves to the project directory to executedbt deps
.__exit__().os.chdir()
# Returns to the directory obtained in step 1.
This is why it was necessary to move the move_to_nearest_project_dir()
function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is an amazing explanation -- thank you!
@rariyama looks like the new test you just introduced is failing on the deps command.(I think this is due to missing |
@rariyama I went ahead and merged this change! Thank you so much for fixing it! |
Hi @ChenyuLInx |
resolves #8997
I closed the previous PR by mistake, then I submit this one.
Problem
There is a difference in behaviour between
dbt cli
anddbt.invoke
.For example, When executing
dbtRunner().invoke(["deps", "--project-dir", "project_dir"])
in python, directorychanges to
project_dir
, even though it doesn't affect when executingdbt deps
.Solution
The reason why directory changes is
dbt.task.base.move_to_nearest_project_dir()
is called inCleanTask
,DepsTask
andInitTask
. Directory changes to the argument of the function.It'll be possible to resolve this problem by using those classes as a context manager. The change will happen only in with statement.
Checklist