sqlobject-cvs Mailing List for SQLObject (Page 161)
SQLObject is a Python ORM.
Brought to you by:
ianbicking,
phd
You can subscribe to this list here.
2003 |
Jan
|
Feb
|
Mar
(9) |
Apr
(74) |
May
(29) |
Jun
(16) |
Jul
(28) |
Aug
(10) |
Sep
(57) |
Oct
(9) |
Nov
(29) |
Dec
(12) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2004 |
Jan
(7) |
Feb
(14) |
Mar
(6) |
Apr
(3) |
May
(12) |
Jun
(34) |
Jul
(9) |
Aug
(29) |
Sep
(22) |
Oct
(2) |
Nov
(15) |
Dec
(52) |
2005 |
Jan
(47) |
Feb
(78) |
Mar
(14) |
Apr
(35) |
May
(33) |
Jun
(16) |
Jul
(26) |
Aug
(63) |
Sep
(40) |
Oct
(96) |
Nov
(96) |
Dec
(123) |
2006 |
Jan
(159) |
Feb
(144) |
Mar
(64) |
Apr
(31) |
May
(88) |
Jun
(48) |
Jul
(16) |
Aug
(64) |
Sep
(87) |
Oct
(92) |
Nov
(56) |
Dec
(76) |
2007 |
Jan
(94) |
Feb
(103) |
Mar
(126) |
Apr
(123) |
May
(85) |
Jun
(11) |
Jul
(130) |
Aug
(47) |
Sep
(65) |
Oct
(70) |
Nov
(12) |
Dec
(11) |
2008 |
Jan
(30) |
Feb
(55) |
Mar
(88) |
Apr
(20) |
May
(50) |
Jun
|
Jul
(38) |
Aug
(1) |
Sep
(9) |
Oct
(5) |
Nov
(6) |
Dec
(39) |
2009 |
Jan
(8) |
Feb
(16) |
Mar
(3) |
Apr
(33) |
May
(44) |
Jun
(1) |
Jul
(10) |
Aug
(33) |
Sep
(74) |
Oct
(22) |
Nov
|
Dec
(15) |
2010 |
Jan
(28) |
Feb
(22) |
Mar
(46) |
Apr
(29) |
May
(1) |
Jun
(1) |
Jul
(27) |
Aug
(8) |
Sep
(5) |
Oct
(33) |
Nov
(24) |
Dec
(41) |
2011 |
Jan
(4) |
Feb
(12) |
Mar
(35) |
Apr
(29) |
May
(19) |
Jun
(16) |
Jul
(32) |
Aug
(25) |
Sep
(5) |
Oct
(11) |
Nov
(21) |
Dec
(12) |
2012 |
Jan
(3) |
Feb
(4) |
Mar
(20) |
Apr
(4) |
May
(25) |
Jun
(13) |
Jul
|
Aug
|
Sep
(2) |
Oct
(25) |
Nov
(9) |
Dec
(1) |
2013 |
Jan
(6) |
Feb
(8) |
Mar
|
Apr
(10) |
May
(31) |
Jun
(7) |
Jul
(18) |
Aug
(33) |
Sep
(4) |
Oct
(16) |
Nov
|
Dec
(27) |
2014 |
Jan
(2) |
Feb
|
Mar
|
Apr
(11) |
May
(39) |
Jun
(8) |
Jul
(11) |
Aug
(4) |
Sep
|
Oct
(27) |
Nov
|
Dec
(71) |
2015 |
Jan
(17) |
Feb
(47) |
Mar
(33) |
Apr
|
May
|
Jun
(9) |
Jul
(7) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(8) |
2016 |
Jan
(4) |
Feb
(4) |
Mar
|
Apr
|
May
(12) |
Jun
(7) |
Jul
(9) |
Aug
(31) |
Sep
(8) |
Oct
(3) |
Nov
(15) |
Dec
(1) |
2017 |
Jan
(13) |
Feb
(7) |
Mar
(14) |
Apr
(8) |
May
(10) |
Jun
(4) |
Jul
(2) |
Aug
(1) |
Sep
|
Oct
(8) |
Nov
(4) |
Dec
(5) |
2018 |
Jan
(2) |
Feb
(8) |
Mar
|
Apr
(4) |
May
|
Jun
(6) |
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
(1) |
Dec
|
2019 |
Jan
(1) |
Feb
(16) |
Mar
(1) |
Apr
(3) |
May
(5) |
Jun
(1) |
Jul
|
Aug
|
Sep
(2) |
Oct
|
Nov
(1) |
Dec
(3) |
2020 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
(1) |
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
(2) |
Nov
|
Dec
(2) |
2021 |
Jan
|
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
(1) |
Dec
|
2022 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(6) |
Oct
(1) |
Nov
(1) |
Dec
(4) |
2023 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
(3) |
Sep
(2) |
Oct
(2) |
Nov
(4) |
Dec
|
2024 |
Jan
|
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
(1) |
Oct
|
Nov
|
Dec
(9) |
2025 |
Jan
|
Feb
(4) |
Mar
(2) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <sub...@co...> - 2005-08-27 09:39:09
|
Author: ianb Date: 2005-08-27 09:39:04 +0000 (Sat, 27 Aug 2005) New Revision: 958 Added: SQLObject/tags/0.7b1/ Log: Tagging 0.7b1 version Copied: SQLObject/tags/0.7b1 (from rev 957, SQLObject/trunk) |
From: <sub...@co...> - 2005-08-27 09:39:05
|
Author: ianb Date: 2005-08-27 09:38:58 +0000 (Sat, 27 Aug 2005) New Revision: 957 Added: SQLObject/tags/ Log: Tag dir |
From: <sub...@co...> - 2005-08-27 09:35:51
|
Author: ianb Date: 2005-08-27 09:35:46 +0000 (Sat, 27 Aug 2005) New Revision: 956 Modified: SQLObject/trunk/docs/web/repository.txt Log: Moved repository Modified: SQLObject/trunk/docs/web/repository.txt =================================================================== --- SQLObject/trunk/docs/web/repository.txt 2005-08-27 09:28:58 UTC (rev 955) +++ SQLObject/trunk/docs/web/repository.txt 2005-08-27 09:35:46 UTC (rev 956) @@ -2,12 +2,12 @@ ==================== SQLObject is kept in a `Subversion <http://subversion.tigris.org/>`_ -repository at http://svn.colorstudy.com/trunk/SQLObject +repository at http://svn.colorstudy.com/SQLObject/trunk If you are using a command-line Subversion client, you can check it out like:: - svn co http://svn.colorstudy.com/trunk/SQLObject + svn co http://svn.colorstudy.com/SQLObject/trunk SQLObject If you are on Windows you may want to use `TortoiseSVN <http://tortoisesvn.tigris.org/>`_. |
From: <sub...@co...> - 2005-08-27 09:28:52
|
Author: ianb Date: 2005-08-27 09:28:49 +0000 (Sat, 27 Aug 2005) New Revision: 954 Removed: branches/SQLObject/ Log: Removed empty dir |
From: <sub...@co...> - 2005-08-27 09:28:46
|
Author: ianb Date: 2005-08-27 09:28:33 +0000 (Sat, 27 Aug 2005) New Revision: 953 Added: SQLObject/branches/0.5/ Removed: branches/SQLObject/0.5/ Log: Moved Copied: SQLObject/branches/0.5 (from rev 952, branches/SQLObject/0.5) |
From: <sub...@co...> - 2005-08-27 09:28:24
|
Author: ianb Date: 2005-08-27 09:28:20 +0000 (Sat, 27 Aug 2005) New Revision: 952 Added: SQLObject/branches/0.6/ Removed: branches/SQLObject/0.6/ Log: rearrange Copied: SQLObject/branches/0.6 (from rev 951, branches/SQLObject/0.6) |
From: <sub...@co...> - 2005-08-27 09:27:58
|
Author: ianb Date: 2005-08-27 09:27:56 +0000 (Sat, 27 Aug 2005) New Revision: 951 Added: SQLObject/branches/ Log: branch dir |
From: <sub...@co...> - 2005-08-27 09:27:19
|
Author: ianb Date: 2005-08-27 09:27:15 +0000 (Sat, 27 Aug 2005) New Revision: 950 Added: SQLObject/trunk/ Removed: trunk/SQLObject/ Log: Moved SQLObject into more normal hierarchy Copied: SQLObject/trunk (from rev 949, trunk/SQLObject) |
From: <sub...@co...> - 2005-08-27 09:26:36
|
Author: ianb Date: 2005-08-27 09:26:33 +0000 (Sat, 27 Aug 2005) New Revision: 949 Added: SQLObject/ Log: New hierarchy |
From: <sub...@co...> - 2005-08-27 09:23:55
|
Author: ianb Date: 2005-08-27 09:23:51 +0000 (Sat, 27 Aug 2005) New Revision: 948 Added: trunk/SQLObject/docs/sqlobject-admin.txt Modified: trunk/SQLObject/docs/rebuild Log: Added preliminary document on sqlobject-admin Modified: trunk/SQLObject/docs/rebuild =================================================================== --- trunk/SQLObject/docs/rebuild 2005-08-27 09:22:54 UTC (rev 947) +++ trunk/SQLObject/docs/rebuild 2005-08-27 09:23:51 UTC (rev 948) @@ -8,7 +8,7 @@ NORMAL="Authors DeveloperGuide FAQ Inheritance News SQLBuilder SQLObject TODO web/index web/links web/repository web/community - index" + index sqlobject-admin" for NAME in $NORMAL ; do if [ -e "$NAME.html" -a ! "$NAME.html" -ot "$NAME.txt" ] ; then Added: trunk/SQLObject/docs/sqlobject-admin.txt =================================================================== --- trunk/SQLObject/docs/sqlobject-admin.txt 2005-08-27 09:22:54 UTC (rev 947) +++ trunk/SQLObject/docs/sqlobject-admin.txt 2005-08-27 09:23:51 UTC (rev 948) @@ -0,0 +1,189 @@ +++++++++++++++++++++++++ +The sqlobject-admin Tool +++++++++++++++++++++++++ + +:author: Ian Bicking <ia...@co...> +:revision: $Rev$ +:date: $LastChangedDate$ + +.. contents:: + +.. warning:: + + This document isn't entirely accurate; some of what it describes + are the intended features of the tool, not the actual features. + + Particularly inaccurate is how modules and classes are found. + +Introduction +------------ + +The ``sqlobject-admin`` tool included with SQLObject allows you to +manage your database as defined with SQLObject classes. + +Some of the features include creating tables, checking the status of +the database, recording a version of a schema, and updating the +database to match the version of the schema in your code. + +To see a list of commands run ``sqlobject-admin help``. Each +sub-command has ``-h`` option which explains the details of that +command. + +Common Options +============== + +Many of the commands share some common options, mostly for finding the +database and classes. + +``-c CONNECTION`` or ``--connection=CONNECTION``: + + This takes an argument, the connection string for the database. + This overrides any connection the classes have (if they are + hardwired to a connection). + +``-f FILENAME`` or ``--config-file=FILENAME``: + + This is a configuration file from which to get the connection. + This configuration file should be a Python-syntax file that + defines a global variable ``database``, which is the connection + string for the database. + +``-m MODULE`` or ``--module=MODULE``: + + A module to look in for classes. ``MODULE`` is something like + ``myapp.amodule``. Remember to set your ``$PYTHONPATH`` if the + module can't be imported. You can provide this argument multiple + times. + +``-p PACKAGE`` or ``--package=PACKAGE``: + + A package to look in. This looks in all the modules in this class + and subclasses for SQLObject classes. + +``--class=CLASSMATCH``: + + This *restricts* the classes found to the matching classes. You + may use wildcards. You can provide multiple ``--class`` + arguments, and if any pattern matches the class will be included. + +When finding SQLObject classes, we look in the modules for classes +that belong to the module -- so if you import a class from another +module it won't be "matched". You have to indicate its original +module. + +If classes have to be handled in a specific order, create a +``soClasses`` global variable that holds a list of the classes. This +overrides the module restrictions. This is important in databases +with referential integrity, where dependent tables can't be created +before the tables they depend on. + +Simple Commands +=============== + +The ``create`` Command +---------------------- + +This finds the tables and creates them. Any tables that exist are +simply skipped. + +The ``sql`` Command +------------------- + +This shows the SQL to create all the tables. + +The ``drop`` Command +-------------------- + +Drops tables! Missing tables are skipped. + +The ``execute`` Command +----------------------- + +This executes an arbitrary SQL expression. This is mostly useful if +you want to run a query against a database described by a SQLObject +connection string. Use ``--stdin`` if you want to pipe commands in; +otherwise you give the commands as arguments. + +The ``list`` Command +-------------------- + +Lists out all the classes found. This can help you figure out +what classes you are dealing with, and if there's any missing that you +expected. + +The ``status`` Command +---------------------- + +This shows if tables are present in the database. If possible (it +depends on the database) it will also show if the tables are missing +any columns, or have any extra columns, when compared to the table the +SQLObject class describes. It doesn't check column types, indexes, or +constraints. This feature may be added in the future. + +Versioning & Upgrading +====================== + +There's two commands related to storing the schema and upgrading the +database: ``record`` and ``upgrade``. + +The idea is that you record each iteration of your schema, and this +gets a version number. Something like ``2003-05-04a``. If you are +using source control you'll check all versions into your repository; +you don't overwrite one with the next. + +In addition to the on-disk record of the different schemas you have +gone through, the database itself contains a record of what version it +is at. By having all the versions available at once, we can upgrade +from any version. But more on that `later <the-upgrade-command>`_ + +Basic Usage +----------- + +Here's a quick summary of how you use these commands: + +1. In project where you've never used ``sqlobject-admin`` before, you + run ``sqlobject-admin record --output-dir=sqlobject-history``. + If your active database is up-to-date with the code, then the tool + will add a ``sqlobject_db_version`` table to the database with the + current version. + +2. Now, make some updates to your code. Don't update the database! + (You could, but for now it's more fun if you don't.) + +3. Run ``sqlobject-admin record --edit``. A new version will be + created, and an editor will be opened up. + +The ``record`` Command +---------------------- + +Record will take the SQL ``CREATE`` statements for your tables, and +output them in new version. It creates the version by using the +ISO-formatted date (YYYY-MM-DD) and a suffix to make it unique. It +puts each table in its own file. + +This normally doesn't touch the database at all -- it only records the +schema as defined in your code, regardless of the database. In fact, +I recommend calling ``record`` *before* you update your database. + +The ``upgrade`` Command +----------------------- + +Future +====== + +* Get ``record`` to do ``svn cp`` when creating a new version, then + write over those files; this way the version control system will + have nice diffs. + +* An option to ``record`` the SQL for multiple database backends at + once (now only the active backend is recorded). + +* An option to upgrade databases with Python scripts instead of SQL + commands. Or a little of both. + +* Review all the verbosity, maybe add logging, review simulation. + +* Generate simple ``ALTER`` statements for upgrade scripts, to give + people something to work with. Maybe. + +* A command to trim versions, by merging upgrade scripts. Property changes on: trunk/SQLObject/docs/sqlobject-admin.txt ___________________________________________________________________ Name: svn:keywords + LastChangedDate LastChangedRevision |
From: <sub...@co...> - 2005-08-27 09:22:57
|
Author: ianb Date: 2005-08-27 09:22:54 +0000 (Sat, 27 Aug 2005) New Revision: 947 Modified: trunk/SQLObject/ trunk/SQLObject/setup.py Log: use distutils for python2.2 with setup.py Property changes on: trunk/SQLObject ___________________________________________________________________ Name: svn:ignore - MANIFEST data build dist *.pyc *.pyo *.tmp + MANIFEST data build dist *.pyc *.pyo *.tmp SQLObject.egg-info Modified: trunk/SQLObject/setup.py =================================================================== --- trunk/SQLObject/setup.py 2005-08-27 09:20:16 UTC (rev 946) +++ trunk/SQLObject/setup.py 2005-08-27 09:22:54 UTC (rev 947) @@ -1,6 +1,11 @@ -from ez_setup import use_setuptools -use_setuptools() -from setuptools import setup, find_packages +# ez_setup doesn't work with Python 2.2, so we use distutils +# in that case: +try: + from ez_setup import use_setuptools + use_setuptools() + from setuptools import setup +except ImportError: + from distutils.core import setup subpackages = ['firebird', 'inheritance', 'mysql', 'postgres', 'sqlite', 'sybase', 'maxdb', 'util', 'manager'] @@ -13,7 +18,7 @@ DistributionMetadata.download_url = None setup(name="SQLObject", - version="0.7", + version="0.7b1", description="Object-Relational Manager, aka database wrapper", long_description="""\ Classes created using SQLObject wrap database rows, presenting a |
From: <sub...@co...> - 2005-08-27 09:20:28
|
Author: ianb Date: 2005-08-27 09:20:16 +0000 (Sat, 27 Aug 2005) New Revision: 946 Modified: trunk/SQLObject/docs/News.txt trunk/SQLObject/sqlobject/sresults.py Log: Made select results aggressively fetch objects, instead of lazily Modified: trunk/SQLObject/docs/News.txt =================================================================== --- trunk/SQLObject/docs/News.txt 2005-08-25 16:54:35 UTC (rev 945) +++ trunk/SQLObject/docs/News.txt 2005-08-27 09:20:16 UTC (rev 946) @@ -17,7 +17,16 @@ .. _Inheritance.html: Inheritance.html +Other Changes +------------- +* When iterating over select results, a list is now immediately + created with the full list of instances being selected. Before + instances were created on demand, as select results were + pulled out row-by-row. The previous lazy behavior is available with + the method ``lazyIter``, used like ``for obj in + MyClass.select().lazyIter(): ...``. + SQLObject 0.6.1 =============== Modified: trunk/SQLObject/sqlobject/sresults.py =================================================================== --- trunk/SQLObject/sqlobject/sresults.py 2005-08-25 16:54:35 UTC (rev 945) +++ trunk/SQLObject/sqlobject/sresults.py 2005-08-27 09:20:16 UTC (rev 946) @@ -143,6 +143,16 @@ return list(self.clone(start=start, end=start+1))[0] def __iter__(self): + # @@: This could be optimized, using a simpler algorithm + # since we don't have to worry about garbage collection, + # etc., like we do with .lazyIter() + return iter(list(self.lazyIter())) + + def lazyIter(self): + """ + Returns an iterator that will lazily pull rows out of the + database and return SQLObject instances + """ conn = self._getConnection() return conn.iterSelect(self) |
From: <sub...@co...> - 2005-08-25 16:54:48
|
Author: phd Date: 2005-08-25 16:54:35 +0000 (Thu, 25 Aug 2005) New Revision: 945 Modified: trunk/SQLObject/sqlobject/col.py trunk/SQLObject/sqlobject/postgres/pgconnection.py trunk/SQLObject/sqlobject/sqlbuilder.py Log: Removed debugging prints. Modified: trunk/SQLObject/sqlobject/col.py =================================================================== --- trunk/SQLObject/sqlobject/col.py 2005-08-25 13:54:49 UTC (rev 944) +++ trunk/SQLObject/sqlobject/col.py 2005-08-25 16:54:35 UTC (rev 945) @@ -1076,19 +1076,16 @@ """ def to_python(self, value, state): - print str(value) if value is None: return None if isinstance(value, unicode): value = value.encode("ascii") if isinstance(value, str): - print repr(value) return pickle.loads(value) raise validators.Invalid("expected a pickle string in the PickleCol '%s', got %s instead" % \ (self.name, type(value)), value, state) def from_python(self, value, state): - print "IN/OUT", [value, pickle.dumps(value)] if value is None: return None return pickle.dumps(value) Modified: trunk/SQLObject/sqlobject/postgres/pgconnection.py =================================================================== --- trunk/SQLObject/sqlobject/postgres/pgconnection.py 2005-08-25 13:54:49 UTC (rev 944) +++ trunk/SQLObject/sqlobject/postgres/pgconnection.py 2005-08-25 16:54:35 UTC (rev 945) @@ -102,7 +102,6 @@ q = self._insertSQL(table, names, values) if self.debug: self.printDebug(conn, q, 'QueryIns') - print [q] c.execute(q) if self.debugOutput: self.printDebug(conn, id, 'QueryIns', 'result') Modified: trunk/SQLObject/sqlobject/sqlbuilder.py =================================================================== --- trunk/SQLObject/sqlobject/sqlbuilder.py 2005-08-25 13:54:49 UTC (rev 944) +++ trunk/SQLObject/sqlobject/sqlbuilder.py 2005-08-25 16:54:35 UTC (rev 945) @@ -766,7 +766,6 @@ join = "%s %s ON %s" % (self.op, self.table2, on_condition) if self.table1: join = "%s %s" % (self.table1, join) - print [self.table1, self.table2, join] return join elif self.using_columns: using_columns = [] |
From: <sub...@co...> - 2005-08-25 13:54:59
|
Author: phd Date: 2005-08-25 13:54:49 +0000 (Thu, 25 Aug 2005) New Revision: 944 Modified: trunk/SQLObject/sqlobject/inheritance/__init__.py Log: Fixed a bug with inherited ForeignKeys. Modified: trunk/SQLObject/sqlobject/inheritance/__init__.py =================================================================== --- trunk/SQLObject/sqlobject/inheritance/__init__.py 2005-08-25 08:26:12 UTC (rev 943) +++ trunk/SQLObject/sqlobject/inheritance/__init__.py 2005-08-25 13:54:49 UTC (rev 944) @@ -75,6 +75,7 @@ for col in soClass._parentClass.sqlmeta.columnList: cname = col.name if cname == 'childName': continue + if cname.endswith("ID"): cname = cname[:-2] setattr(soClass, getterName(cname), eval( 'lambda self: self._parent.%s' % cname)) if not col.immutable: |
From: <sub...@co...> - 2005-08-25 08:26:22
|
Author: ianb Date: 2005-08-25 08:26:12 +0000 (Thu, 25 Aug 2005) New Revision: 943 Modified: trunk/SQLObject/docs/web/links.txt Log: Added a bunch of links Modified: trunk/SQLObject/docs/web/links.txt =================================================================== --- trunk/SQLObject/docs/web/links.txt 2005-08-24 19:47:11 UTC (rev 942) +++ trunk/SQLObject/docs/web/links.txt 2005-08-25 08:26:12 UTC (rev 943) @@ -35,6 +35,13 @@ * `Anemon <http://anemon.org/wikini/wakka.php?wiki=FirstPage>`_ DHCP server. +* `Planet Plus <http://planetplus.python-hosting.com/>`_; a `CherryPy + <http://cherrypy.org>`_ public feed aggregator. + +* `Guten <http://guten.sourceforge.net/>`_; an application for + browsing, reading, and managing books from `Project Gutenberg + <http://www.gutenberg.org/>`_. + Articles and Documentation -------------------------- @@ -54,3 +61,8 @@ * `Connecting databases to Python with SQLObject <http://www-128.ibm.com/developerworks/library/os-pythonsqlo/index.html?ca=drs>`_; an article at DeveloperWorks. + +* `Handling Form data with Formencode + SQLObject + <http://www.groovie.org/articles/2005/08/24/handling-form-data-with-formencode-sqlobject>`_; + a post by Ben Bangert about using SQLObject with `FormEncode + <http://formencode.org>`_. |
From: <sub...@co...> - 2005-08-24 19:47:30
|
Author: phd Date: 2005-08-24 19:47:11 +0000 (Wed, 24 Aug 2005) New Revision: 942 Modified: trunk/SQLObject/docs/FAQ.txt trunk/SQLObject/docs/News.txt trunk/SQLObject/docs/TODO.txt trunk/SQLObject/docs/default.css trunk/SQLObject/docs/interface.py trunk/SQLObject/scripts/sqlobject-admin trunk/SQLObject/sqlobject/boundattributes.py trunk/SQLObject/sqlobject/classregistry.py trunk/SQLObject/sqlobject/col.py trunk/SQLObject/sqlobject/index.py trunk/SQLObject/sqlobject/main.py trunk/SQLObject/sqlobject/manager/command.py trunk/SQLObject/sqlobject/postgres/pgconnection.py trunk/SQLObject/sqlobject/sresults.py trunk/SQLObject/sqlobject/sybase/sybaseconnection.py trunk/SQLObject/sqlobject/tests/test_NoneValuedResultItem.py trunk/SQLObject/sqlobject/tests/test_auto.py trunk/SQLObject/sqlobject/tests/test_auto_old.py trunk/SQLObject/sqlobject/tests/test_basic.py trunk/SQLObject/sqlobject/tests/test_boundattributes.py trunk/SQLObject/sqlobject/tests/test_constraints.py trunk/SQLObject/sqlobject/tests/test_create_drop.py trunk/SQLObject/sqlobject/tests/test_delete.py trunk/SQLObject/sqlobject/tests/test_joins_old.py trunk/SQLObject/sqlobject/tests/test_select.py trunk/SQLObject/sqlobject/tests/test_unicode.py Log: Removed trailing spaces. Modified: trunk/SQLObject/docs/FAQ.txt =================================================================== --- trunk/SQLObject/docs/FAQ.txt 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/docs/FAQ.txt 2005-08-24 19:47:11 UTC (rev 942) @@ -15,7 +15,7 @@ contacts. Not all customers have a contact, some have several. The left join would look like:: - SELECT customer.id, customer.first_name, customer.last_name, + SELECT customer.id, customer.first_name, customer.last_name, contact.id, contact.address FROM customer LEFT JOIN contact ON contact.customer_id = customer.id @@ -335,7 +335,7 @@ data = StringCol() height = IntCol() width = IntCol() - + def _set_data(self, value): self._SO_set_data(value.encode('base64')) Modified: trunk/SQLObject/docs/News.txt =================================================================== --- trunk/SQLObject/docs/News.txt 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/docs/News.txt 2005-08-24 19:47:11 UTC (rev 942) @@ -86,7 +86,7 @@ rows (like class instantiation used to do). * We're now using a Subversion repository instead of CVS. It is - located at http://svn.colorstudy.com/trunk/SQLObject + located at http://svn.colorstudy.com/trunk/SQLObject * If you pass ``forceDBName=True`` to the ``*Col`` constructors, then your column name doesn't have to be restricted to a-z, 0-9, and _. @@ -297,25 +297,25 @@ * MySQL uses ``localhost`` as the default host, and the empty string as the default password. -* Added functions for use with queries: `ISNULL`, `ISNOTNULL`. ``==`` - and ``!=`` can be used with None, and is translated into `ISNULL`, +* Added functions for use with queries: `ISNULL`, `ISNOTNULL`. ``==`` + and ``!=`` can be used with None, and is translated into `ISNULL`, `ISNOTNULL`. -* Classes can be part of a specific registry. Since classes are +* Classes can be part of a specific registry. Since classes are referred to by name in several places, the names have to be unique. This can be problematic, so you can add a class variable `_registry`, - the value of which should be a string. Classes references are + the value of which should be a string. Classes references are assumed to be inside that registry, and class names need only be unique among classes in that registry. -* ``SomeClass.select()`` selects all, instead of using +* ``SomeClass.select()`` selects all, instead of using ``SomeClass.select('all')``. You can also use None instead of ``'all'``. * Trying to fetch non-existent objects raises `SQLObjectNotFound`, which is a subclass of the builtin exception `LookupError`. This may not be raised if `_cacheValues` is False and you use - the ID to fetch an object (but alternateID fetches will raise + the ID to fetch an object (but alternateID fetches will raise the exception in either case). * Can order by descending order, with the `reversed` option to @@ -328,7 +328,7 @@ ~~~~~~~~~~~~ * `Join` constructors have an argument `orderBy`, which is the name - of a Python attribute to sort results by. If not given, the + of a Python attribute to sort results by. If not given, the appropriate class's `_defaultOrder` will be used. None implies no sorting (and ``orderBy=None`` will override `_defaultOrder`). @@ -369,7 +369,7 @@ * SomeClass.q.colName now does proper translation to database names, using dbName, etc., instead of being entirely algorithm-driven. -* Raise `TypeError` if you pass an unknown argument to the `new` +* Raise `TypeError` if you pass an unknown argument to the `new` method. * You can override the _get_* or _set_* version of a property without @@ -377,7 +377,7 @@ * Python 2.3 compatible. -* Trying to use ``Col('id')`` or ``id = Col()`` will raise an +* Trying to use ``Col('id')`` or ``id = Col()`` will raise an exception, instead of just acting funky. * ``ForeignKey`` columns return None if the associated column is Modified: trunk/SQLObject/docs/TODO.txt =================================================================== --- trunk/SQLObject/docs/TODO.txt 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/docs/TODO.txt 2005-08-24 19:47:11 UTC (rev 942) @@ -8,7 +8,7 @@ the progress for Oracle, Sybase, and MS-SQL support. * Better transaction support -- right now you can use transactions for the database, but the object isn't transaction-aware, so - non-database persistence won't be able to be rolled back. + non-database persistence won't be able to be rolled back. * Optimistic locking and other techniques to handle concurrency. * Profile of SQLObject performance, so that I can identify bottlenecks. * Increase hooks with FormEncode (unreleased) validation and form Modified: trunk/SQLObject/docs/default.css =================================================================== --- trunk/SQLObject/docs/default.css 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/docs/default.css 2005-08-24 19:47:11 UTC (rev 942) @@ -130,7 +130,7 @@ border: medium solid black; } -h1 a:link, h2 a:link { +h1 a:link, h2 a:link { color: #ffffff; } @@ -139,7 +139,7 @@ color: #000000; } -h3 a:link, h4 a:link, h5 a:link, h6 a:link { +h3 a:link, h4 a:link, h5 a:link, h6 a:link { color: #000000; } @@ -286,4 +286,4 @@ .stmlfunction {color: #000077; font-weight: bold} .stmlattr {color: #000000;} .stmlstring {color: #006600;} -.stmlexpr {color: #004444;} \ No newline at end of file +.stmlexpr {color: #004444;} Modified: trunk/SQLObject/docs/interface.py =================================================================== --- trunk/SQLObject/docs/interface.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/docs/interface.py 2005-08-24 19:47:11 UTC (rev 942) @@ -66,7 +66,7 @@ Join tables (mapping tables for many-to-many joins) are created if this class comes alphabetically before the other join class, and if ``createJoinTables`` is true. - + If ``createIndexes`` is true, indexes are also created. """ @@ -254,7 +254,7 @@ Adds the index to the class. """ - + class ICol(Interface): def __init__(name=None, **kw): @@ -307,7 +307,7 @@ """ constraints = """ - A list of ... @@? + A list of ... @@? """ notNone = """ Modified: trunk/SQLObject/scripts/sqlobject-admin =================================================================== --- trunk/SQLObject/scripts/sqlobject-admin 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/scripts/sqlobject-admin 2005-08-24 19:47:11 UTC (rev 942) @@ -33,4 +33,3 @@ from sqlobject.manager import command command.the_runner.run(sys.argv) - Modified: trunk/SQLObject/sqlobject/boundattributes.py =================================================================== --- trunk/SQLObject/sqlobject/boundattributes.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/boundattributes.py 2005-08-24 19:47:11 UTC (rev 942) @@ -88,12 +88,12 @@ def set_object(cls, added_class, attr_name, obj): setattr(added_class, attr_name, obj) - + set_object = classmethod(set_object) def make_object(cls, added_class, attr_name, *args, **attrs): raise NotImplementedError - + make_object = classmethod(make_object) class BoundFactory(BoundAttribute): Modified: trunk/SQLObject/sqlobject/classregistry.py =================================================================== --- trunk/SQLObject/sqlobject/classregistry.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/classregistry.py 2005-08-24 19:47:11 UTC (rev 942) @@ -21,7 +21,7 @@ ... pass >>> registry.addClass(MyClass) Class finally exists: MyClass - + """ class ClassRegistry(object): @@ -33,7 +33,7 @@ with classes by name, and after each class is created we try to fix up any references by replacing the names with actual classes. - + Here we keep a dictionaries of class names to classes -- note that the classes might be spread among different modules, so since we pile them together names need to be globally unique, Modified: trunk/SQLObject/sqlobject/col.py =================================================================== --- trunk/SQLObject/sqlobject/col.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/col.py 2005-08-24 19:47:11 UTC (rev 942) @@ -800,7 +800,7 @@ raise "Enum type is not supported" class EnumValidator(validators.Validator): - + def to_python(self, value, state): if value in self.enumValues: return value Modified: trunk/SQLObject/sqlobject/index.py =================================================================== --- trunk/SQLObject/sqlobject/index.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/index.py 2005-08-24 19:47:11 UTC (rev 942) @@ -95,7 +95,7 @@ return 'ALTER TABLE %s ADD %s %s (%s)' % \ (soClass.sqlmeta.table, uniqueOrIndex, - self.name, + self.name, ', '.join(spec)) @@ -122,9 +122,9 @@ The class also take the keyword argument `unique`; if true then a UNIQUE index is created. """ - + baseClass = SODatabaseIndex - + def __init__(self, *columns, **kw): kw['columns'] = columns self.kw = kw Modified: trunk/SQLObject/sqlobject/main.py =================================================================== --- trunk/SQLObject/sqlobject/main.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/main.py 2005-08-24 19:47:11 UTC (rev 942) @@ -557,7 +557,7 @@ index = indexDef.withClass(cls.soClass) cls.indexes.append(index) addIndex = classmethod(addIndex) - + sqlhub = dbconnection.ConnectionHub() class _sqlmeta_attr(object): @@ -604,9 +604,9 @@ 1) Deprecated in current version (0.7). Will be removed in next version (0.8) - + 2) Planned to deprecate in next version, remove later. - + 3) Planned to deprecate sometime, remove sometime much later ;) As the SQLObject versions progress, the deprecation level of Modified: trunk/SQLObject/sqlobject/manager/command.py =================================================================== --- trunk/SQLObject/sqlobject/manager/command.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/manager/command.py 2005-08-24 19:47:11 UTC (rev 942) @@ -181,7 +181,7 @@ # This abstract base class return register(cls) - + def __init__(self, invoked_as, command_name, args, runner): self.invoked_as = invoked_as self.command_name = command_name @@ -419,8 +419,8 @@ if v >= 1: print '%i tables created (%i already exist)' % ( created, existing) - + class CommandDrop(Command): name = 'drop' @@ -526,8 +526,8 @@ if self.options.verbose: print '%i in sync; %i out of sync; %i not in database' % ( good, bad, missing_tables) - + class CommandHelp(Command): name = 'help' @@ -622,7 +622,7 @@ 'database is currently at. Use the upgrade command to ' 'sync databases with code.' % SQLObjectVersionTable.sqlmeta.table) - + parser = standard_parser() parser.add_option('--output-dir', help="Base directory for recorded definitions", @@ -665,7 +665,7 @@ if self.options.force_db_version: self.command_force_db_version() return - + v = self.options.verbose sim = self.options.simulate classes = self.classes() @@ -801,7 +801,7 @@ def strip_comments(self, sql): lines = [l for l in sql.splitlines() if not l.strip().startswith('--')] - return '\n'.join(lines) + return '\n'.join(lines) def base_dir(self): base = self.options.output_dir @@ -812,7 +812,7 @@ def find_output_dir(self): today = time.strftime('%Y-%m-%d', time.localtime()) if self.options.version_name: - dir = os.path.join(self.base_dir(), today + '-' + + dir = os.path.join(self.base_dir(), today + '-' + self.options.version_name) if os.path.exists(dir): print ("Error, directory already exists: %s" @@ -828,7 +828,7 @@ extra = 'a' else: extra = chr(ord(extra)+1) - + def find_last_version(self): names = [] for fn in os.listdir(self.base_dir()): @@ -921,7 +921,6 @@ raise self.update_db(next_version, conn) print 'Done.' - def current_version(self): conn = self.connection() @@ -982,8 +981,8 @@ print 'No upgraders found in %s' % current_dir return None, None upgraders.sort() - return upgraders[-1] - + return upgraders[-1] + def update_sys_path(paths, verbose): if isinstance(paths, (str, unicode)): paths = [paths] Modified: trunk/SQLObject/sqlobject/postgres/pgconnection.py =================================================================== --- trunk/SQLObject/sqlobject/postgres/pgconnection.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/postgres/pgconnection.py 2005-08-24 19:47:11 UTC (rev 942) @@ -179,7 +179,7 @@ keyData = self.queryAll(keyQuery % self.sqlrepr(tableName)) keyRE = re.compile(r"\((.+)\) REFERENCES (.+)\(") keymap = {} - + for (condef,) in keyData: match = keyRE.search(condef) if match: Modified: trunk/SQLObject/sqlobject/sresults.py =================================================================== --- trunk/SQLObject/sqlobject/sresults.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/sresults.py 2005-08-24 19:47:11 UTC (rev 942) @@ -157,7 +157,7 @@ def count(self): """ Counting elements of current select results """ - assert not (self.ops.get('distinct') and (self.ops.get('start') + assert not (self.ops.get('distinct') and (self.ops.get('start') or self.ops.get('end'))), \ "distinct-counting of sliced objects is not supported" if self.ops.get('distinct'): Modified: trunk/SQLObject/sqlobject/sybase/sybaseconnection.py =================================================================== --- trunk/SQLObject/sqlobject/sybase/sybaseconnection.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/sybase/sybaseconnection.py 2005-08-24 19:47:11 UTC (rev 942) @@ -52,7 +52,6 @@ database=self.db, auto_commit=self.autoCommit, locking=self.locking) - HAS_IDENTITY = """ SELECT col.name, col.status, obj.name FROM syscolumns col @@ -60,7 +59,6 @@ ON obj.id = col.id WHERE obj.name = '%s' AND (col.status & 0x80) = 0x80 - """ def _hasIdentity(self, conn, table): query = self.HAS_IDENTITY % table @@ -68,7 +66,7 @@ c.execute(query) r = c.fetchone() return r is not None - + def _queryInsertID(self, conn, soInstance, id, names, values): table = soInstance.sqlmeta.table idName = soInstance.sqlmeta.idName Modified: trunk/SQLObject/sqlobject/tests/test_NoneValuedResultItem.py =================================================================== --- trunk/SQLObject/sqlobject/tests/test_NoneValuedResultItem.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/tests/test_NoneValuedResultItem.py 2005-08-24 19:47:11 UTC (rev 942) @@ -1,4 +1,4 @@ -'''Test that selectResults handle NULL values +'''Test that selectResults handle NULL values from, for example, outer joins.''' from sqlobject import * from sqlobject.tests.dbtest import * @@ -23,6 +23,6 @@ # but don't add any works for Bruckner # do a left join, a common use case that often involves NULL results - s = TestWork.select(join=sqlbuilder.LEFTJOINOn(TestComposer, TestWork, - TestComposer.q.id==TestWork.q.composerID)) + s = TestWork.select(join=sqlbuilder.LEFTJOINOn(TestComposer, TestWork, + TestComposer.q.id==TestWork.q.composerID)) assert tuple(s)==(w, None) Modified: trunk/SQLObject/sqlobject/tests/test_auto.py =================================================================== --- trunk/SQLObject/sqlobject/tests/test_auto.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/tests/test_auto.py 2005-08-24 19:47:11 UTC (rev 942) @@ -6,7 +6,7 @@ now = datetime.now except ImportError: from mx.DateTime import now - + ######################################## ## Dynamic column tests ######################################## Modified: trunk/SQLObject/sqlobject/tests/test_auto_old.py =================================================================== --- trunk/SQLObject/sqlobject/tests/test_auto_old.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/tests/test_auto_old.py 2005-08-24 19:47:11 UTC (rev 942) @@ -6,7 +6,7 @@ now = datetime.now except ImportError: from mx.DateTime import now - + deprecated_module() ######################################## Modified: trunk/SQLObject/sqlobject/tests/test_basic.py =================================================================== --- trunk/SQLObject/sqlobject/tests/test_basic.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/tests/test_basic.py 2005-08-24 19:47:11 UTC (rev 942) @@ -146,7 +146,7 @@ def test_foreignKeyDestroySelfCascade(): setupClass([TestSO7, TestSO6, TestSO5]) - + tc5 = TestSO5(name='a') tc6a = TestSO6(name='1') tc5.other = tc6a @@ -275,4 +275,3 @@ assert dep1.other is None assert dep2.other is None assert dep3.other is obj2 - Modified: trunk/SQLObject/sqlobject/tests/test_boundattributes.py =================================================================== --- trunk/SQLObject/sqlobject/tests/test_boundattributes.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/tests/test_boundattributes.py 2005-08-24 19:47:11 UTC (rev 942) @@ -54,4 +54,3 @@ assert A1.v.attrs == {'arg1': 'nothing', 'arg2': ['something']} assert A1.inline is v3 assert A1.inline.attrs == {'arg3': 'again', 'arg4': 'so there'} - Modified: trunk/SQLObject/sqlobject/tests/test_constraints.py =================================================================== --- trunk/SQLObject/sqlobject/tests/test_constraints.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/tests/test_constraints.py 2005-08-24 19:47:11 UTC (rev 942) @@ -9,7 +9,7 @@ # @@: Should this really be an error? raises(BadValue, isString, obj, col, u'test!') #isString(obj, col, u'test!') - + raises(BadValue, notNull, obj, col, None) raises(BadValue, isInt, obj, col, 1.1) isInt(obj, col, 1) @@ -31,4 +31,3 @@ maxlen(obj, col, '12') maxlen(obj, col, (1,)) raises(BadValue, maxlen, obj, col, 1) - Modified: trunk/SQLObject/sqlobject/tests/test_create_drop.py =================================================================== --- trunk/SQLObject/sqlobject/tests/test_create_drop.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/tests/test_create_drop.py 2005-08-24 19:47:11 UTC (rev 942) @@ -11,7 +11,6 @@ short = StringCol(length=10) blobcol = BLOBCol() - def test_create_drop(): conn = getConnection() TestCreateDrop.setConnection(conn) @@ -25,5 +24,3 @@ assert not conn.tableExists(TestCreateDrop.sqlmeta.table) TestCreateDrop.dropTable(ifExists=True) assert not conn.tableExists(TestCreateDrop.sqlmeta.table) - - Modified: trunk/SQLObject/sqlobject/tests/test_delete.py =================================================================== --- trunk/SQLObject/sqlobject/tests/test_delete.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/tests/test_delete.py 2005-08-24 19:47:11 UTC (rev 942) @@ -26,4 +26,3 @@ value = NoCache(name='test') value.destroySelf() NoCache._connection.cache = old - Modified: trunk/SQLObject/sqlobject/tests/test_joins_old.py =================================================================== --- trunk/SQLObject/sqlobject/tests/test_joins_old.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/tests/test_joins_old.py 2005-08-24 19:47:11 UTC (rev 942) @@ -1,6 +1,6 @@ from sqlobject import * from sqlobject.tests.dbtest import * - + deprecated_module() ######################################## Modified: trunk/SQLObject/sqlobject/tests/test_select.py =================================================================== --- trunk/SQLObject/sqlobject/tests/test_select.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/tests/test_select.py 2005-08-24 19:47:11 UTC (rev 942) @@ -54,7 +54,6 @@ test = all[i] count += 1 assert count == len(names) - def test_04_indexed_ended_by_exception(): all = IterTest.select() Modified: trunk/SQLObject/sqlobject/tests/test_unicode.py =================================================================== --- trunk/SQLObject/sqlobject/tests/test_unicode.py 2005-08-24 19:18:48 UTC (rev 941) +++ trunk/SQLObject/sqlobject/tests/test_unicode.py 2005-08-24 19:47:11 UTC (rev 942) @@ -19,7 +19,7 @@ def test_create(): setupClass(Unicode1) data = [u'\u00f0', u'test', 'ascii test'] - + items = [] for i, n in enumerate(data): items.append(Unicode1(count=i, col1=n, col2=n)) |
From: <sub...@co...> - 2005-08-24 19:19:02
|
Author: phd Date: 2005-08-24 19:18:48 +0000 (Wed, 24 Aug 2005) New Revision: 941 Modified: trunk/SQLObject/docs/FAQ.txt trunk/SQLObject/docs/SQLObject.txt Log: Documentation update. Modified: trunk/SQLObject/docs/FAQ.txt =================================================================== --- trunk/SQLObject/docs/FAQ.txt 2005-08-24 17:52:20 UTC (rev 940) +++ trunk/SQLObject/docs/FAQ.txt 2005-08-24 19:18:48 UTC (rev 941) @@ -73,15 +73,17 @@ SQL-wise ~~~~~~~~ -Use LEFTJOIN() from sqlobject.sqlbuilder. +Use LEFTJOIN() from SQLBuilder_. How can I join a table with itself? ----------------------------------- -Use Alias from sqlobject.sqlbuilder. +Use Alias from SQLBuilder_. +.. _SQLBuilder: SQLBuilder.html + How Does Inheritance Work? -------------------------- Modified: trunk/SQLObject/docs/SQLObject.txt =================================================================== --- trunk/SQLObject/docs/SQLObject.txt 2005-08-24 17:52:20 UTC (rev 940) +++ trunk/SQLObject/docs/SQLObject.txt 2005-08-24 19:18:48 UTC (rev 941) @@ -24,10 +24,12 @@ Introduction ============ -SQLObject is an *object-relational mapper*. It allows you to -translate RDBMS table rows into Python objects, and manipulate those -objects to transparently manipulate the database. +SQLObject is an *object-relational mapper* for Python_ programming +language. It allows you to translate RDBMS table rows into Python objects, +and manipulate those objects to transparently manipulate the database. +.. _Python: http://python.org + In using SQLObject, you will create a class definition that will describe how the object translates to the database table. SQLObject will produce the code to access the database, and update the database @@ -41,12 +43,21 @@ Requirements ============ -Currently SQLObject supports MySQL_, PostgreSQL_ (via ``psycopg``), -SQLite_, Firebird_, Sybase_, and `MAX DB`_ (also known as SAP DB). +Currently SQLObject supports MySQL_ via MySQLdb_ aka MySQL-python, +PostgreSQL_ via psycopg_, SQLite_ via PySQLite_, Firebird_ via kinterbasdb_, +Sybase via Sybase_, and `MAX DB`_ (also known as SAP DB) via sapdb_. +.. _MySQL: http://mysql.com +.. _MySQLdb: http://sourceforge.net/projects/mysql-python/ .. _PostgreSQL: http://postgresql.org +.. _psycopg: http://initd.org/projects/psycopg1 .. _SQLite: http://sqlite.org +.. _PySQLite: http://initd.org/projects/pysqlite .. _Firebird: http://firebird.sourceforge.net +.. _kinterbasdb: http://kinterbasdb.sourceforge.net/ +.. _Sybase: http://www.object-craft.com.au/projects/sybase/ +.. _`MAX DB`: http://www.mysql.com/products/maxdb/ +.. _sapdb: http://www.sapdb.org/sapdbPython.html Python 2.2 or higher is required. SQLObject makes extensive use of new-style classes. @@ -84,7 +95,7 @@ .. _PyDO: http://skunkweb.sourceforge.net/pydo.html SQLObject is, to my knowledge, unique in using metaclasses to -facilitate this seemless integration. Some other ORMs use code +facilitate this seamless integration. Some other ORMs use code generation to create an interface, expressing the schema in a CSV or XML file (for example, MiddleKit, part of Webware_). By using metaclasses you are able to comfortably define your schema in the @@ -136,7 +147,7 @@ let's have SQLObject do that work. First, the class: >>> class Person(SQLObject): - ... + ... ... firstName = StringCol() ... middleInitial = StringCol(length=1, default=None) ... lastName = StringCol() @@ -287,7 +298,7 @@ ------------ By default SQLObject sends an ``UPDATE`` to the database for every -attribute you set, or everytime you call ``.set()``. If you want to +attribute you set, or every time you call ``.set()``. If you want to avoid this many updates, add ``_lazyUpdate = True`` to your class definition. Then updates will only be written to the database when you call ``inst.syncUpdate()`` or ``obj.sync()``: ``.sync()`` also @@ -307,7 +318,7 @@ addresses, of course:: >>> class Address(SQLObject): - ... + ... ... street = StringCol() ... city = StringCol() ... state = StringCol(length=2) @@ -320,7 +331,7 @@ (with a string). In the database there will be a ``person_id`` column, type ``INT``, which points to the ``person`` column. -.. note:: +.. note:: The reason SQLObject uses strings to refer to other classes is because the other class often does not yet exist. Classes in @@ -332,7 +343,7 @@ below ``A`` in the module, then when the ``A`` class was created (including creating all its column attributes) the ``B`` class simply wouldn't exist. By referring to classes by name, we can - wait until all the requird classes exist before creating the links + wait until all the required classes exist before creating the links between classes. We want an attribute that gives the addresses for a person. In a @@ -345,7 +356,7 @@ But we already have the class. We can add this to the class in-place:: - >>> Person.sqlmeta.addJoin(MultipleJoin('Address', + >>> Person.sqlmeta.addJoin(MultipleJoin('Address', ... joinMethodName='addresses')) .. note:: @@ -374,22 +385,22 @@ `RelatedJoin`. >>> class User(SQLObject): - ... + ... ... class sqlmeta: ... # user is a reserved word in some databases, so we won't ... # use that for the table name: ... table = "user_table" - ... + ... ... username = StringCol(alternateID=True, length=20) ... # We'd probably define more attributes, but we'll leave - ... # that excersize to the reader... - ... + ... # that exercise to the reader... + ... ... roles = RelatedJoin('Role') >>> class Role(SQLObject): - ... + ... ... name = StringCol(alternateID=True, length=20) - ... + ... ... users = RelatedJoin('User') >>> User.createTable() @@ -544,7 +555,7 @@ total = query.count() print "Showing page %i of %i" % (start/size + 1, total/size + 1) -.. note:: +.. note:: There are several factors when considering the efficiency of this kind of batching, and it depends very much how the batching is @@ -570,8 +581,6 @@ For more information on the where clause in the queries, see the `SQLBuilder documentation`_. -.. _`SQLBuilder documentation`: SQLBuilder.html - Select-By Method ~~~~~~~~~~~~~~~~ @@ -594,7 +603,7 @@ Initializing the Objects ~~~~~~~~~~~~~~~~~~~~~~~~ -There are two ways SQLObject instances can come into existance: they +There are two ways SQLObject instances can come into existence: they can be fetched from the database, or they can be inserted into the database. In both cases a new Python object is created. This makes the role of `__init__` a little confusing. @@ -736,7 +745,7 @@ `dbName`: This is the name of the column in the database. If you don't - give a name, your Pythonic name will be converted from + give a name, your Pythonic name will be converted from mixed-case to underscore-separated. `default`: The default value for this column. Used when creating a new row. @@ -754,7 +763,7 @@ ``byUsername`` which will return that object. Use `alternateMethodName` if you don't like the ``by*`` name (e.g. ``alternateMethodName="username"``). - + The column should be declared ``UNIQUE`` in your table schema. `unique`: If true, when SQLObject creates a table it will declare this @@ -782,16 +791,23 @@ There are some other subclasses of `Col`. These are used to indicate different types of columns, when SQLObject creates your tables. +`BLOBCol`: + A column for binary data. Presently works only with MySQL, PostgreSQL + and SQLite backends. + `BoolCol`: Will create a ``BOOLEAN`` column in Postgres, or ``INT`` in other - databses. It will also convert values to ``"t"/"f"`` or ``0/1`` + databases. It will also convert values to ``"t"/"f"`` or ``0/1`` according to the database backend. `CurrencyCol`: Equivalent to ``DecimalCol(size=10, precision=2)``. +`DateCol`: + A date (usually returned as an datetime or mxDateTime object). + `DateTimeCol`: - A date and time (usually returned as an mxDateTime object). + A date and time (usually returned as an datetime or mxDateTime object). `DecimalCol`: Base-10, precise number. Uses the keyword arguments `size` for @@ -814,6 +830,11 @@ `IntCol`: Integers. +`PickleCol`: + An extension of BLOBCol; this column can store/retrieve any Python object; + it actually (un)pickle the object from/to string and store/retrieve the + string. + `StringCol`: A string (character) column. Extra keywords: @@ -825,7 +846,7 @@ ``CHAR`` and ``VARCHAR``, default True, i.e., use ``VARCHAR``. -`UnicodeCol`: +`UnicodeCol`: A subclass of `StringCol`. Also accepts a dbEncoding keyword argument, which defaults to ``"UTF-8"``. Values coming in and out from the database will be encoded and decoded. **Note**: @@ -857,7 +878,7 @@ `_cacheValues`: If set to ``False`` then values for attributes from the database - won't be cached. So everytime you access an attribute in the + won't be cached. So every time you access an attribute in the object the database will be queried for a value. If you want to handle concurrent access to the database from multiple processes then this is probably the way to do so. You should also use @@ -904,7 +925,7 @@ `joinMethodName`: When adding joins dynamically (using the class method `addJoin`_), you can give the name of the accessor for the join. It can also be - created automatically, and is normally implied (i.e., ``addresses = + created automatically, and is normally implied (i.e., ``addresses = MultipleJoin(...)`` implies ``joinMethodName="addresses"``). RelatedJoin: Many-to-Many @@ -921,7 +942,7 @@ `intermediateTable`: The name of the intermediate table which references both classes. `addRemoveName`: - In the `user/role example`__, the methods `addRole(role)` and + In the `user/role example`__, the methods `addRole(role)` and `removeRole(role)` are created. The ``Role`` portion of these method names can be changed by giving a string value here. @@ -949,11 +970,11 @@ class Person(SQLObject): username = StringCol(length=100, alternateID=True) - roles = RelatedJoin('Role', joinColumn='person', otherColumn='role', + roles = RelatedJoin('Role', joinColumn='person', otherColumn='role', intermediateTable='assigned_roles') class Role(SQLObject): name = StringCol(length=50, alternateID=True) - roles = RelatedJoin('Person', joinColumn='role', otherColumn='person', + roles = RelatedJoin('Person', joinColumn='role', otherColumn='person', intermediateTable='assigned_roles') SingleJoin: One-to-One @@ -990,44 +1011,10 @@ Automatic Schema Generation --------------------------- -All the connections support creating and droping tables based on the +All the connections support creating and dropping tables based on the class definition. First you have to prepare your class definition, which means including type information in your columns. -Columns Types -~~~~~~~~~~~~~ - -A column type is indicated by using a subclass of `Col`: - -`StringCol`: - StringCol represents ``CHAR``, ``VARCHAR``, and ``TEXT``. The - `length` keyword argument indicates the ``CHAR`` or ``VARCHAR`` - length -- if not given, then ``TEXT`` is assumed. If you use - ``varchar=False`` then ``CHAR`` will be used, otherwise - ``VARCHAR`` is the default. -`IntCol`: - The ``INT`` type. -`FloatCol`: - The ``FLOAT`` type. -`DecimalCol`: - The ``DECIMAL`` SQL type, i.e., base 10 number. The keyword - arguments `size` and `precision` indicate the scope. So - ``DecimalCol(size=5, precision=2)`` is a number like ###.##, - i.e., 5 digits, two of them past the decimal point. -`CurrencyCol`: - Like ``DecimalCol(size=10, precision=2)``. -`EnumCol`: - A MySQL ``ENUM``, i.e., one of a finite number of strings. - For other databases this will be a ``VARCHAR``. -`DateTimeCol`: - A moment in time. ``TIMESTAMP`` in Postgres, and ``DATETIME`` - in MySQL. Note the names of these columns match the *Python* - type names, not the SQL names. -`ForeignKey`: - This is a reference to another table. You typically need to - only give the name of the foreign class that is referenced. - `ForeignKey` implies an ``INT`` column. - Indexes ~~~~~~~ @@ -1068,10 +1055,10 @@ To create a table call `createTable`. It takes two arguments: -`ifNotExists`: +`ifNotExists`: If the table already exists, then don't try to create it. Default False. -`createJoinTables`: +`createJoinTables`: If you used `Many-to-Many relationships`_, then the intermediate tables will be created (but only for one of the two involved classes). Default True. @@ -1098,7 +1085,7 @@ _fromDatabase = True You can still specify columns (in `_columns`), and only missing -columns will be added. +columns will be added. *This is not supported in SQLite* @@ -1122,7 +1109,7 @@ .. _addJoin: -You can also add Joins__, like +You can also add Joins__, like ``MyClass.addJoin(MultipleJoin("MyOtherClass"))``, and remove joins with `delJoin`. `delJoin` does not take strings, you have to get the join object out of the `_joins` attribute. @@ -1153,12 +1140,10 @@ SQLite: ``INTEGER PRIMARY KEY`` -SQLObject does not support non-integer keys (that may change). It -does not support sequences in Postgres (that will change -- ``SERIAL`` -uses an implicit sequence). It does not support primary keys made up -of multiple columns (that probably won't change). It does not -generally support tables with primary keys with business meaning -- -i.e., primary keys are assumed to be immutable (that won't change). +SQLObject does not support primary keys made up of multiple columns (that +probably won't change). It does not generally support tables with primary +keys with business meaning -- i.e., primary keys are assumed to be +immutable (that won't change). At the moment foreign key column names must end in ``"ID"`` (case-insensitive). This restriction will probably be removed in the @@ -1235,7 +1220,7 @@ ================================== The `DBConnection` module currently has four external classes, -`MySQLConnection`, `PostgresConnection`, `SQLiteConnection`, +`MySQLConnection`, `PostgresConnection`, `SQLiteConnection`, `SybaseConnection`, and `MaxdbConnection`. You can pass the keyword argument `debug` to any connector. If set to @@ -1245,7 +1230,7 @@ MySQL ----- -`MySQLConnection` takes the keyword arguments `host`, `db`, `user`, +`MySQLConnection` takes the keyword arguments `host`, `port`, `db`, `user`, and `passwd`, just like `MySQLdb.connect` does. MySQLConnection supports all the features, though MySQL only supports @@ -1267,7 +1252,7 @@ ------ `SQLiteConnection` takes the a single string, which is the path to the -database file. +database file. SQLite puts all data into one file, with a journal file that is opened in the same directory during operation (the file is deleted when the @@ -1381,17 +1366,17 @@ First look in the FAQ_, question "How can I do a LEFT JOIN?" Still here? Well. To perform a JOIN use one of the JOIN helpers from -sqlobject.sqlbuilder. Pass an instance of the helper to .select() +SQLBuilder_. Pass an instance of the helper to .select() method. For example:: from sqlobject.sqlbuilder import LEFTJOINOn MyTable.select( - join=LEFTJOINOn(Table1, Table2, + join=LEFTJOINOn(Table1, Table2, Table1.q.name == Table2.q.value)) will generate the query:: - SELECT * FROM my_table, table1 + SELECT * FROM my_table, table1 LEFT JOIN table2 ON table1.name = table2.value; .. _FAQ: FAQ.html#how-can-i-do-a-left-join @@ -1400,12 +1385,12 @@ None:: MyTable.select( - join=LEFTJOINOn(None, Table1, + join=LEFTJOINOn(None, Table1, MyTable.q.name == Table1.q.value)) will generate the query:: - SELECT * FROM my_table + SELECT * FROM my_table LEFT JOIN table2 ON my_table.name = table1.value; The join argument for .select() can be a JOIN() or a list/tuples of @@ -1415,7 +1400,7 @@ How can I join a table with itself? ----------------------------------- -Use Alias from sqlobject.sqlbuilder. Example:: +Use Alias from SQLBuilder_. Example:: from sqlobject.sqlbuilder import Alias alias = Alias(MyTable, "my_table_alias") @@ -1423,7 +1408,7 @@ will generate the query:: - SELECT * FROM my_table, my_table AS my_table_alias + SELECT * FROM my_table, my_table AS my_table_alias WHERE my_table.name = my_table_alias.value; Can I use LEFTJOIN() with aliases? @@ -1450,7 +1435,7 @@ You can run queries with subqueries (subselects) on those DBMS that can do subqueries (MySQL supports subqueries from version 4.1). -Use corresponding classess and functions from sqlbuilder:: +Use corresponding classes and functions from SQLBuilder_:: from sqlobject.sqlbuilder import EXISTS, Select select = Test1.select(EXISTS(Select(Test2.q.col2, where=(Outer(Test1).q.col1 == Test2.q.col2)))) @@ -1460,13 +1445,13 @@ SELECT test1.id, test1.col1 FROM test1 WHERE EXISTS (SELECT test2.col2 FROM test2 WHERE (test1.col1 = test2.col2)) -Note the usage of Outer - this is the helper to allow refering to a table +Note the usage of Outer - this is the helper to allow referring to a table in the outer query. Select() is used instead of .select() because you need to control what columns and in what order the inner query returns. -Avalable queries are IN(), NOTIN(), EXISTS(), NOTEXISTS(), SOME(), ANY() +Available queries are IN(), NOTIN(), EXISTS(), NOTEXISTS(), SOME(), ANY() and ALL(). The last 3 are used with comparison operators, like this: "somevalue = ANY(Select(...))". @@ -1476,4 +1461,5 @@ For more information on SQLBuilder, read the `SQLBuilder Documentation`_. +.. _SQLBuilder: SQLBuilder.html .. _`SQLBuilder Documentation`: SQLBuilder.html |
From: <sub...@co...> - 2005-08-24 17:52:33
|
Author: phd Date: 2005-08-24 17:52:20 +0000 (Wed, 24 Aug 2005) New Revision: 940 Modified: trunk/SQLObject/sqlobject/tests/test_blob.py Log: Removed an outdated comment - the problem was fixed in BLOBCol long ago. Modified: trunk/SQLObject/sqlobject/tests/test_blob.py =================================================================== --- trunk/SQLObject/sqlobject/tests/test_blob.py 2005-08-24 17:15:06 UTC (rev 939) +++ trunk/SQLObject/sqlobject/tests/test_blob.py 2005-08-24 17:52:20 UTC (rev 940) @@ -19,7 +19,4 @@ ImageData._connection.cache.clear() prof2 = ImageData.get(iid) - # @@: This seems to fail in SQLite, which trims off the - # first and last character (\x00 and \xff). We should write - # a test for the upstream driver, as the error might be there. assert prof2.image == data |
From: <sub...@co...> - 2005-08-24 14:36:40
|
Author: phd Date: 2005-08-24 14:36:35 +0000 (Wed, 24 Aug 2005) New Revision: 937 Modified: trunk/SQLObject/sqlobject/sqlite/sqliteconnection.py Log: Stop PySQLite2 converting strings to unicode. Modified: trunk/SQLObject/sqlobject/sqlite/sqliteconnection.py =================================================================== --- trunk/SQLObject/sqlobject/sqlite/sqliteconnection.py 2005-08-24 13:59:26 UTC (rev 936) +++ trunk/SQLObject/sqlobject/sqlite/sqliteconnection.py 2005-08-24 14:36:35 UTC (rev 937) @@ -1,5 +1,6 @@ from sqlobject.dbconnection import DBAPI from sqlobject.col import popKey + sqlite = None using_sqlite2 = False @@ -29,6 +30,10 @@ if 'encoding' in kw: import warnings warnings.warn(DeprecationWarning("pysqlite2 does not support the encoding option")) + opts["detect_types"] = sqlite.PARSE_DECLTYPES + for col_type in "text", "char", "varchar": + sqlite.register_converter(col_type, stop_pysqlite2_converting_strings_to_unicode) + sqlite.register_converter(col_type.upper(), stop_pysqlite2_converting_strings_to_unicode) else: opts['autocommit'] = autoCommit if 'encoding' in kw: @@ -124,3 +129,6 @@ def createIndexSQL(self, soClass, index): return index.sqliteCreateIndexSQL(soClass) + +def stop_pysqlite2_converting_strings_to_unicode(s): + return s |
From: <sub...@co...> - 2005-08-24 13:59:31
|
Author: phd Date: 2005-08-24 13:59:26 +0000 (Wed, 24 Aug 2005) New Revision: 936 Modified: trunk/SQLObject/sqlobject/tests/test_decimal.py Log: Fixed a bug - assertion were reversed. Modified: trunk/SQLObject/sqlobject/tests/test_decimal.py =================================================================== --- trunk/SQLObject/sqlobject/tests/test_decimal.py 2005-08-22 06:31:09 UTC (rev 935) +++ trunk/SQLObject/sqlobject/tests/test_decimal.py 2005-08-24 13:59:26 UTC (rev 936) @@ -23,6 +23,6 @@ setupClass(DecimalTable) d = DecimalTable(col1=Decimal("21.12")) if isinstance(d.col1, Decimal): + assert d.col1 == Decimal("21.12") + else: assert d.col1 == 21.12 - else: - assert d.col1 == Decimal("21.12") |
From: <sub...@co...> - 2005-08-22 06:31:17
|
Author: phd Date: 2005-08-22 06:31:09 +0000 (Mon, 22 Aug 2005) New Revision: 935 Added: trunk/SQLObject/sqlobject/tests/test_decimal.py Modified: trunk/SQLObject/sqlobject/converters.py Log: Added Decimal converter; added tests. Modified: trunk/SQLObject/sqlobject/converters.py =================================================================== --- trunk/SQLObject/sqlobject/converters.py 2005-08-22 06:02:19 UTC (rev 934) +++ trunk/SQLObject/sqlobject/converters.py 2005-08-22 06:31:09 UTC (rev 935) @@ -43,6 +43,11 @@ from types import InstanceType, ClassType, TypeType +try: + from decimal import Decimal +except ImportError: + Decimal = None + ######################################## ## Quoting ######################################## @@ -191,6 +196,12 @@ registerConverter(datetime.date, DateConverter) +if Decimal: + def DecimalConverter(value, db): + return value.to_eng_string() + + registerConverter(Decimal, DecimalConverter) + def sqlrepr(obj, db=None): try: reprFunc = obj.__sqlrepr__ @@ -202,4 +213,3 @@ return converter(obj, db) else: return reprFunc(db) - Added: trunk/SQLObject/sqlobject/tests/test_decimal.py =================================================================== --- trunk/SQLObject/sqlobject/tests/test_decimal.py 2005-08-22 06:02:19 UTC (rev 934) +++ trunk/SQLObject/sqlobject/tests/test_decimal.py 2005-08-22 06:31:09 UTC (rev 935) @@ -0,0 +1,28 @@ +from sqlobject import * +from sqlobject.tests.dbtest import * + +try: + from decimal import Decimal +except ImportError: + Decimal = None + +######################################## +## Deciaml columns +######################################## + +class DecimalTable(SQLObject): + col1 = DecimalCol(size=6, precision=4) + +def test_1decimal(): + setupClass(DecimalTable) + d = DecimalTable(col1=21.12) + assert d.col1 == 21.12 + +if Decimal: + def test_2Decimal(): + setupClass(DecimalTable) + d = DecimalTable(col1=Decimal("21.12")) + if isinstance(d.col1, Decimal): + assert d.col1 == 21.12 + else: + assert d.col1 == Decimal("21.12") |
From: <sub...@co...> - 2005-08-22 06:02:21
|
Author: phd Date: 2005-08-22 06:02:19 +0000 (Mon, 22 Aug 2005) New Revision: 934 Modified: trunk/SQLObject/sqlobject/dbconnection.py Log: Fixed a case where id is in kw but there are also other keywords. Modified: trunk/SQLObject/sqlobject/dbconnection.py =================================================================== --- trunk/SQLObject/sqlobject/dbconnection.py 2005-08-22 06:01:34 UTC (rev 933) +++ trunk/SQLObject/sqlobject/dbconnection.py 2005-08-22 06:02:19 UTC (rev 934) @@ -625,16 +625,15 @@ data = {} if 'id' in kw: data[soClass.sqlmeta.idName] = kw['id'] - else: - for key, col in soClass.sqlmeta.columns.items(): - if key in kw: - data[col.dbName] = kw[key] - elif col.foreignName in kw: - obj = kw[col.foreignName] - if obj is None: - data[col.dbName] = None - else: - data[col.dbName] = obj.id + for key, col in soClass.sqlmeta.columns.items(): + if key in kw: + data[col.dbName] = kw[key] + elif col.foreignName in kw: + obj = kw[col.foreignName] + if obj is None: + data[col.dbName] = None + else: + data[col.dbName] = obj.id return ' AND '.join( ['%s %s %s' % (dbName, ops.get(value, "="), self.sqlrepr(value)) |
From: <sub...@co...> - 2005-08-22 06:01:37
|
Author: phd Date: 2005-08-22 06:01:34 +0000 (Mon, 22 Aug 2005) New Revision: 933 Modified: trunk/SQLObject/setup.py Log: Removed 'include' from the list of subpackages. Modified: trunk/SQLObject/setup.py =================================================================== --- trunk/SQLObject/setup.py 2005-08-22 05:47:48 UTC (rev 932) +++ trunk/SQLObject/setup.py 2005-08-22 06:01:34 UTC (rev 933) @@ -2,7 +2,7 @@ use_setuptools() from setuptools import setup, find_packages -subpackages = ['firebird', 'include', 'inheritance', 'mysql', 'postgres', +subpackages = ['firebird', 'inheritance', 'mysql', 'postgres', 'sqlite', 'sybase', 'maxdb', 'util', 'manager'] import sys |
From: <sub...@co...> - 2005-08-22 05:47:52
|
Author: phd Date: 2005-08-22 05:47:48 +0000 (Mon, 22 Aug 2005) New Revision: 932 Modified: trunk/SQLObject/sqlobject/postgres/pgconnection.py Log: Fixed a problem: varchar without length in Postgres means any length. Modified: trunk/SQLObject/sqlobject/postgres/pgconnection.py =================================================================== --- trunk/SQLObject/sqlobject/postgres/pgconnection.py 2005-08-21 00:10:12 UTC (rev 931) +++ trunk/SQLObject/sqlobject/postgres/pgconnection.py 2005-08-22 05:47:48 UTC (rev 932) @@ -221,7 +221,10 @@ if t.count('int'): return col.IntCol, {} elif t.count('varying'): - return col.StringCol, {'length': int(t[t.index('(')+1:-1])} + if '(' in t: + return col.StringCol, {'length': int(t[t.index('(')+1:-1])} + else: # varchar without length in Postgres means any length + return col.StringCol, {} elif t.startswith('character('): return col.StringCol, {'length': int(t[t.index('(')+1:-1]), 'varchar': False} |
From: <sub...@co...> - 2005-08-19 17:54:48
|
Author: test Date: 2005-08-19 17:54:45 +0000 (Fri, 19 Aug 2005) New Revision: 928 Modified: trunk/SQLObject/sqlobject/main.py Log: Make subclass deleting columns work properly Modified: trunk/SQLObject/sqlobject/main.py =================================================================== --- trunk/SQLObject/sqlobject/main.py 2005-08-19 17:54:17 UTC (rev 927) +++ trunk/SQLObject/sqlobject/main.py 2005-08-19 17:54:45 UTC (rev 928) @@ -750,10 +750,10 @@ # _columns where the attribute has been set to None in this # class. If so, then we need to remove that column from # _columns. - for key in cls.sqlmeta.columnDefinitions: + for key in cls.sqlmeta.columnDefinitions.keys(): if (key in new_attrs and new_attrs[key] is None): - del cls.sqlmeta.columnsDefinitions[key] + del cls.sqlmeta.columnDefinitions[key] for column in cls.sqlmeta.columnDefinitions.values(): cls.sqlmeta.addColumn(column) |