Skip to content

Conversation

@ezd1000
Copy link
Collaborator

@ezd1000 ezd1000 commented Feb 2, 2024

Updated a series of errors so that dbprocessing code works for both sqlalchemy 2.0 and sqlalchemy 1.4. Closes #135.

PR Checklist

  • Pull request has descriptive title
  • Pull request gives overview of changes
  • (N/A) New code has inline comments where necessary
  • (N/A) Any new modules, functions or classes have docstrings consistent with dbprocessing style
  • (N/A) Major new functionality has appropriate Sphinx documentation
  • (N/A) Added an entry to release notes if fixing a major bug or providing a major new feature
  • (See below) New features and bug fixes should have unit tests
  • Relevant issues are linked in the description (use Closes # if this PR closes the issue, or some other reference, such as See # if it is related in some other way)

*We don't yet have unit tests to make sure warnings aren't raised, the tests now pass without warnings on Python 3.10, sqlalchemy 1.4, and 2.0.

@jtniehof
Copy link
Member

jtniehof commented Feb 6, 2024

This would close #135, so should edit the PR description to say that. (Last item in the PR checklist, see #120 for an example, also some information here.)

Copy link
Member

@jtniehof jtniehof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functionality looks good. Just to make history less arduous, can you do some rebasing and squash some commits together?

  • the four commits, three "added bind to drop_all" and "removed self from dbu_engine" should be one
  • "fixed warning message" and "fixed all warning messages" should be one
  • the "added bind=self.engine" and "took out bind=self.engine" should be combined; really this is "move the bind from Metadata constructor to table creation"
  • probably the two "fixed another join" should be one

Copy link
Member

@jtniehof jtniehof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a few quick checks for places which aren't in the unit tests but show a similar pattern to what we had to change.

create_all requiring the bind now: CreateDBsabrs line 321 (@dnadeau-lanl , is CreateDBsabrs now out of date, or is it superseded now that we can create postgres databases? Maybe we should be removing it instead.)

execute no longer taking a direct SQL string: scrubber line 27, clean_test_db line 119. To test the scrubber, we're actually kind of short on canned test databases (the psp one is enormous now). You can get an old one from history by git show e3c67f3feabdc62bec2ffabba78bceb3d8dd5d89:./functional_test/testDB.sqlite > foo.sqlite. You can get the old mageis database for testing clean_test_db with git show 18469404b10ece57051b9b2391c1ea3c0741aefe:./unit_tests/RBSP_MAGEIS.sqlite > RBSP_MAGEIS.sqlite

MetaData no longer taking a bind argument (having to bind separately): CreateDBsabrs line 40 (like in other places where we've made that change, that line needs to be fixed and specifying the bind may have to happen in multiple places) EDIT: bind needs to be added to the reflect call in init_db (right after it was removed from the instantiation of self.metadata, and somewhat related the create_all call around line 321 already has the bind, but should be self.engine not engine.

The functional test is also not running. Unfortunately it doesn't run in the CI (#68) so it's possible this has just drifted out of date. Running it is pretty simple, run python ./functionalTest.py in the functional_test directory. Unfortunately debugging it is going to be harder; it makes a temp directory where all the scripts and such live, and for some reason when the codes fail to run, the moveToError that copies the error log to the error directory is also failing.

For finding these various scripts, use find in the dbprocessing checkout.

@ezd1000 ezd1000 added the admin Administrative issue not related to the codebase (e.g. access requests) label Jan 9, 2025
@jtniehof jtniehof removed the admin Administrative issue not related to the codebase (e.g. access requests) label Mar 10, 2025
@ezd1000 ezd1000 force-pushed the sqlalchemy20 branch 2 times, most recently from f7ef949 to 66df48d Compare March 18, 2025 09:51
@ezd1000 ezd1000 force-pushed the sqlalchemy20 branch 2 times, most recently from 77c64fb to e5c4e55 Compare March 18, 2025 10:44
Copy link
Member

@jtniehof jtniehof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few fairly minor changes suggested

Comment on lines 22 to 23
print "infiles", infiles
print "outfile", outfile
print("infiles + ", infiles)
print("outfile + ", outfile)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plus should be outside the quote here, since it's concatanation...this will put in an extra comma and parens.

output.write(infile.read().encode('rot13'))

output.write(codecs.encode(infile.read(), 'rot_13'))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra whitespace here

Comment on lines 21 to 23
print "infile", infile
print "outfile", outfile
print("infile + ", infile)
print("outfile + ", outfile)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as for the L0 to L1 (concatenate, not print a literal +)

infile = args[0]

print "infile", infile
print("infile + ", infile)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Comment on lines 91 to 102
if sys.version_info < (3, 4):
import imp # Depracated in Python 3.4
inspect = imp.load_source('inspect', os.path.join(dbp_testing.testsdir, 'inspector', 'rot13_L1_dlevel.py'))
else:
import importlib.util
import importlib.machinery
loader = importlib.machinery.SourceFileLoader('inspect', os.path.join(dbp_testing.testsdir, 'inspector', 'rot13_L1_dlevel.py'))
spec = importlib.util.spec_from_file_location('inspect', os.path.join(dbp_testing.testsdir, 'inspector', 'rot13_L1_dlevel.py'), loader=loader)
inspect = importlib.util.module_from_spec(spec)
loader.exec_module(inspect)
with warnings.catch_warnings(record=True) as w:
self.assertEqual(repr(Diskfile.Diskfile(goodfile, self.dbu)), repr(inspect.Inspector(goodfile, self.dbu, 1,)()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we break this out into a function, or static method, that gets called both here and the setup? Or I wonder about putting the function in dbprocessing/Utils.py, since this is also used by the code in dbprocessing/dbprocessing.py.

Comment on lines 261 to 270
if sys.version_info < (3,4):
import imp # imp is deprecated at python 3.4
inspect = imp.load_source('inspect', code)
else:
import importlib.util # used in python 3.4 and above
import importlib.machinery
loader = importlib.machinery.SourceFileLoader('inspect', code)
spec = importlib.util.spec_from_file_location('inspect', code, loader=loader)
inspect = importlib.util.module_from_spec(spec)
loader.exec_module(inspect)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used in several places, see comments below.

I'm always wary of explicit self.version_info checks and would prefer we check, say, if importlib.util exists. However, the very next thing we're going to do is rip out support for old versions of Python, so I'm inclined to leave this as you wrote it.

Copy link
Member

@jtniehof jtniehof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small stuff, can probably just do a single cleanup commit and call it good.

else:
ans[section][item] = (ans[section][item], 0, 0)
return ans
def load_source(modname, filepath, module):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PEP8 specifies space (i.e. one empty line) between the functions.

Can you document parameters/returns as in the other functions?

The module argument doesn't appear to be used--can it be removed? (And then update calls to it, of course).

for code, desc, arg, product in act_insp:
try:
inspect = imp.load_source('inspect', code)
fname = code
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this assignment necessary? Can't we just pass "code" directly to load_source?

inspect = imp.load_source('inspect', code)
fname = code
inspect = None
inspect = Utils.load_source('inspect',fname, inspect)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

space after the comma per PEP-8

Comment on lines -7 to +8
output.write(infile.read().encode('rot13'))

output.write(codecs.encode(infile.read(), 'rot_13'))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

go ahead and retain the empty line at the end of the function

Comment on lines -89 to +90
self.assertEqual(
'{}: error: {}'.format(os.path.basename(sys.argv[0]), msg), err)


running_script = os.path.basename(sys.argv[0])
self.assertTrue(err.startswith("{}: error: argument".format(running_script)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per PEP 8, keep two blank lines after the class definition

dbp_testing.testsdir, 'inspector', 'rot13_L1.py'))

filename = os.path.join(dbp_testing.testsdir, 'inspector', 'rot13_L1.py')
self.inspect = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you update load_source not to take the module argument, all these None assignments can go away (several in this file)

Comment on lines +307 to +315
def test_load_source(self):
"""Testing load_source in Utils.py"""
filename = "temp_testfile.py"
with open(filename, "w") as f:
f.write("def hello():\n return 'Hello, world!'\n")
inspect = None
module = Utils.load_source("temp_testfile", filename, inspect)
self.assertEqual(module.hello(), 'Hello, world!')

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice test. Do leave a blank line before it, and two after (because it's the end of the class). Use tempfile to make a temporary directory and put your test file in there, then clean it up after (with a try/finally)--that way you're not leaving it in the current directory.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Port dbp to SQLAlchemy 1.4/2.0

2 participants