├── .gitignore ├── BACKERS.md ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── docs └── README ├── pony ├── __init__.py ├── converting.py ├── flask │ ├── __init__.py │ └── example │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── app.py │ │ ├── config.py │ │ ├── models.py │ │ ├── templates │ │ ├── index.html │ │ ├── login.html │ │ └── reg.html │ │ └── views.py ├── javascript │ └── pony.js ├── options.py ├── orm │ ├── __init__.py │ ├── asttranslation.py │ ├── core.py │ ├── dbapiprovider.py │ ├── dbproviders │ │ ├── __init__.py │ │ ├── cockroach.py │ │ ├── mysql.py │ │ ├── oracle.py │ │ ├── postgres.py │ │ └── sqlite.py │ ├── dbschema.py │ ├── decompiling.py │ ├── examples │ │ ├── __init__.py │ │ ├── bottle_example.py │ │ ├── compositekeys.py │ │ ├── demo.py │ │ ├── estore.py │ │ ├── inheritance1.py │ │ ├── numbers.py │ │ ├── university1.py │ │ └── university2.py │ ├── integration │ │ ├── __init__.py │ │ └── bottle_plugin.py │ ├── ormtypes.py │ ├── serialization.py │ ├── sqlbuilding.py │ ├── sqlsymbols.py │ ├── sqltranslation.py │ └── tests │ │ ├── __init__.py │ │ ├── aggregate_count_queries.txt │ │ ├── coverage.bat │ │ ├── coverage.sh │ │ ├── fixtures.py │ │ ├── model1-database.sql │ │ ├── model1.py │ │ ├── poster_queries.txt │ │ ├── queries.txt │ │ ├── sql_tests.py │ │ ├── test_array.py │ │ ├── test_attribute_options.py │ │ ├── test_autostrip.py │ │ ├── test_buffer.py │ │ ├── test_bug_170.py │ │ ├── test_bug_182.py │ │ ├── test_bug_331.py │ │ ├── test_bug_386.py │ │ ├── test_cascade.py │ │ ├── test_cascade_delete.py │ │ ├── test_collections.py │ │ ├── test_conversions.py │ │ ├── test_core_find_in_cache.py │ │ ├── test_core_multiset.py │ │ ├── test_crud.py │ │ ├── test_crud_raw_sql.py │ │ ├── test_datetime.py │ │ ├── test_db_session.py │ │ ├── test_declarative_attr_set_monad.py │ │ ├── test_declarative_exceptions.py │ │ ├── test_declarative_func_monad.py │ │ ├── test_declarative_join_optimization.py │ │ ├── test_declarative_object_flat_monad.py │ │ ├── test_declarative_orderby_limit.py │ │ ├── test_declarative_query_set_monad.py │ │ ├── test_declarative_sqltranslator.py │ │ ├── test_declarative_sqltranslator2.py │ │ ├── test_declarative_strings.py │ │ ├── test_decompiler.py │ │ ├── test_deduplication.py │ │ ├── test_diagram.py │ │ ├── test_diagram_attribute.py │ │ ├── test_diagram_keys.py │ │ ├── test_distinct.py │ │ ├── test_entity_init.py │ │ ├── test_entity_proxy.py │ │ ├── test_exists.py │ │ ├── test_f_strings.py │ │ ├── test_filter.py │ │ ├── test_flush.py │ │ ├── test_frames.py │ │ ├── test_generator_db_session.py │ │ ├── test_get_pk.py │ │ ├── test_getattr.py │ │ ├── test_hooks.py │ │ ├── test_hybrid_methods_and_properties.py │ │ ├── test_indexes.py │ │ ├── test_inheritance.py │ │ ├── test_inner_join_syntax.py │ │ ├── test_int_converter.py │ │ ├── test_interleave.py │ │ ├── test_isinstance.py │ │ ├── test_json.py │ │ ├── test_lambda.py │ │ ├── test_lazy.py │ │ ├── test_list_monad.py │ │ ├── test_mapping.py │ │ ├── test_objects_to_save_cleanup.py │ │ ├── test_prefetching.py │ │ ├── test_prop_sum_orderby.py │ │ ├── test_query.py │ │ ├── test_random.py │ │ ├── test_raw_sql.py │ │ ├── test_relations_m2m.py │ │ ├── test_relations_one2many.py │ │ ├── test_relations_one2one1.py │ │ ├── test_relations_one2one2.py │ │ ├── test_relations_one2one3.py │ │ ├── test_relations_one2one4.py │ │ ├── test_relations_symmetric_m2m.py │ │ ├── test_relations_symmetric_one2one.py │ │ ├── test_seeds.py │ │ ├── test_select_from_select_queries.py │ │ ├── test_show.py │ │ ├── test_sqlbuilding_formatstyles.py │ │ ├── test_sqlbuilding_sqlast.py │ │ ├── test_sqlite_shared_memory_db.py │ │ ├── test_sqlite_str_functions.py │ │ ├── test_time_parsing.py │ │ ├── test_to_dict.py │ │ ├── test_tracked_value.py │ │ ├── test_transaction_lock.py │ │ ├── test_validate.py │ │ ├── test_volatile.py │ │ └── testutils.py ├── py23compat.py ├── thirdparty │ ├── __init__.py │ └── decorator.py └── utils │ ├── __init__.py │ ├── properties.py │ └── utils.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.sqlite 3 | .idea 4 | pony/orm/tests/.coverage 5 | pony/orm/tests/coverage.bat 6 | pony/orm/tests/htmlcov/*.* 7 | MANIFEST 8 | docs/_build/ 9 | pony.egg-info/ 10 | -------------------------------------------------------------------------------- /BACKERS.md: -------------------------------------------------------------------------------- 1 | # Sponsors & Backers 2 | 3 | Pony ORM is Apache 2.0 licensed open source project. If you would like to support Pony ORM development, please consider: 4 | 5 | [Become a backer or sponsor](https://ponyorm.org/donation.html) 6 | 7 | ## Backers 8 | 9 | - [Vincere](https://vince.re) 10 | - Sergio Aguilar Guerrero 11 | - David ROUBLOT 12 | - Elijas Dapšauskas 13 | - Dan Swain 14 | - Christian Macht 15 | - Johnathan Nader 16 | - Andrei Rachalouski 17 | - Juan Pablo Scaletti 18 | - Marcus Birkenkrahe 19 | - Vincent Le Goff 20 | - Niklas Rosenstein 21 | - Xucong Zhan 22 | - Christian Does 23 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include pony/orm/tests/queries.txt 2 | include pony/flask/example/templates *.html 3 | include LICENSE 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Downloads 2 | [![Downloads](https://pepy.tech/badge/pony)](https://pepy.tech/project/pony) [![Downloads](https://pepy.tech/badge/pony/month)](https://pepy.tech/project/pony/month) [![Downloads](https://pepy.tech/badge/pony/week)](https://pepy.tech/project/pony/week) 3 | 4 | 5 | Pony Object-Relational Mapper 6 | ============================= 7 | 8 | Pony is an advanced object-relational mapper. The most interesting feature of Pony is its ability to write queries to the database using Python generator expressions and lambdas. Pony analyzes the abstract syntax tree of the expression and translates it into a SQL query. 9 | 10 | Here is an example query in Pony: 11 | 12 | ```python 13 | select(p for p in Product if p.name.startswith('A') and p.cost <= 1000) 14 | ``` 15 | 16 | Pony translates queries to SQL using a specific database dialect. Currently Pony works with SQLite, MySQL, PostgreSQL and Oracle databases. 17 | 18 | By providing a Pythonic API, Pony facilitates fast app development. Pony is an easy-to-learn and easy-to-use library. It makes your work more productive and helps to save resources. Pony achieves this ease of use through the following: 19 | 20 | * Compact entity definitions 21 | * The concise query language 22 | * Ability to work with Pony interactively in a Python interpreter 23 | * Comprehensive error messages, showing the exact part where an error occurred in the query 24 | * Displaying of the generated SQL in a readable format with indentation 25 | 26 | All this helps the developer to focus on implementing the business logic of an application, instead of struggling with a mapper trying to understand how to get the data from the database. 27 | 28 | See the example [here](https://github.com/ponyorm/pony/blob/orm/pony/orm/examples/estore.py) 29 | 30 | 31 | Support Pony ORM Development 32 | ---------------------------- 33 | 34 | Pony ORM is Apache 2.0 licensed open source project. If you would like to support Pony ORM development, please consider: 35 | 36 | [Become a backer or sponsor](https://ponyorm.org/donation.html) 37 | 38 | 39 | Online tool for database design 40 | ------------------------------- 41 | 42 | Pony ORM also has the Entity-Relationship Diagram Editor which is a great tool for prototyping. You can create your database diagram online at [https://editor.ponyorm.com](https://editor.ponyorm.com), generate the database schema based on the diagram and start working with the database using declarative queries in seconds. 43 | 44 | 45 | Documentation 46 | ------------- 47 | 48 | Documentation is available at [https://docs.ponyorm.org](https://docs.ponyorm.org) 49 | The documentation source is available at [https://github.com/ponyorm/pony-doc](https://github.com/ponyorm/pony-doc). 50 | Please create new documentation related issues [here](https://github.com/ponyorm/pony-doc/issues) or make a pull request with your improvements. 51 | 52 | 53 | License 54 | ------- 55 | 56 | Pony ORM is released under the Apache 2.0 license. 57 | 58 | 59 | PonyORM community 60 | ----------------- 61 | 62 | Please post your questions on [Stack Overflow](http://stackoverflow.com/questions/tagged/ponyorm). 63 | Meet the PonyORM team, chat with the community members, and get your questions answered on our community [Telegram group](https://t.me/ponyorm). 64 | Join our newsletter at [ponyorm.org](https://ponyorm.org). 65 | Reach us on [Twitter](https://twitter.com/ponyorm). 66 | 67 | Copyright (c) 2013-2022 Pony ORM. All rights reserved. info (at) ponyorm.org 68 | -------------------------------------------------------------------------------- /docs/README: -------------------------------------------------------------------------------- 1 | See docs at https://docs.ponyorm.com 2 | The source is at https://github.com/ponyorm/pony-doc -------------------------------------------------------------------------------- /pony/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function 2 | 3 | import os, sys 4 | from os.path import dirname 5 | 6 | __version__ = '0.7.19' 7 | 8 | def detect_mode(): 9 | try: import google.appengine 10 | except ImportError: pass 11 | else: 12 | if os.getenv('SERVER_SOFTWARE', '').startswith('Development'): 13 | return 'GAE-LOCAL' 14 | return 'GAE-SERVER' 15 | 16 | try: from mod_wsgi import version 17 | except: pass 18 | else: return 'MOD_WSGI' 19 | 20 | main = sys.modules['__main__'] 21 | 22 | if not hasattr(main, '__file__'): # console 23 | return 'INTERACTIVE' 24 | 25 | if os.getenv('IPYTHONENABLE', '') == 'True': 26 | return 'INTERACTIVE' 27 | 28 | if getattr(main, 'INTERACTIVE_MODE_AVAILABLE', False): # pycharm console 29 | return 'INTERACTIVE' 30 | 31 | if 'flup.server.fcgi' in sys.modules: return 'FCGI-FLUP' 32 | if 'uwsgi' in sys.modules: return 'UWSGI' 33 | if 'flask' in sys.modules: return 'FLASK' 34 | if 'cherrypy' in sys.modules: return 'CHERRYPY' 35 | if 'bottle' in sys.modules: return 'BOTTLE' 36 | return 'UNKNOWN' 37 | 38 | MODE = detect_mode() 39 | 40 | MAIN_FILE = None 41 | if MODE == 'MOD_WSGI': 42 | for module_name, module in sys.modules.items(): 43 | if module_name.startswith('_mod_wsgi_'): 44 | MAIN_FILE = module.__file__ 45 | break 46 | elif MODE != 'INTERACTIVE': 47 | MAIN_FILE = sys.modules['__main__'].__file__ 48 | 49 | if MAIN_FILE is not None: MAIN_DIR = dirname(MAIN_FILE) 50 | else: MAIN_DIR = None 51 | 52 | PONY_DIR = dirname(__file__) 53 | -------------------------------------------------------------------------------- /pony/flask/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import importlib 4 | 5 | from pony.orm import db_session 6 | 7 | 8 | flask_lib = importlib.import_module('flask') 9 | request = getattr(flask_lib, 'request', None) 10 | 11 | 12 | def _enter_session(): 13 | session = db_session() 14 | request.pony_session = session 15 | session.__enter__() 16 | 17 | def _exit_session(exception): 18 | session = getattr(request, 'pony_session', None) 19 | if session is not None: 20 | session.__exit__(exc=exception) 21 | 22 | class Pony(object): 23 | def __init__(self, app=None): 24 | self.app = None 25 | if app is not None: 26 | self.init_app(app) 27 | 28 | def init_app(self, app): 29 | self.app = app 30 | self.app.before_request(_enter_session) 31 | self.app.teardown_request(_exit_session) -------------------------------------------------------------------------------- /pony/flask/example/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ponyorm/pony/b9375605edacde9e68e3fc5c578a4b090a36cb8d/pony/flask/example/__init__.py -------------------------------------------------------------------------------- /pony/flask/example/__main__.py: -------------------------------------------------------------------------------- 1 | from .views import * 2 | from .app import app 3 | 4 | if __name__ == '__main__': 5 | db.bind(**app.config['PONY']) 6 | db.generate_mapping(create_tables=True) 7 | app.run() -------------------------------------------------------------------------------- /pony/flask/example/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from flask_login import LoginManager 3 | from pony.flask import Pony 4 | from .config import config 5 | from .models import db 6 | 7 | app = Flask(__name__) 8 | app.config.update(config) 9 | 10 | Pony(app) 11 | login_manager = LoginManager(app) 12 | login_manager.login_view = 'login' 13 | 14 | @login_manager.user_loader 15 | def load_user(user_id): 16 | return db.User.get(id=user_id) 17 | -------------------------------------------------------------------------------- /pony/flask/example/config.py: -------------------------------------------------------------------------------- 1 | config = dict( 2 | DEBUG = False, 3 | SECRET_KEY = 'secret_xxx', 4 | PONY = { 5 | 'provider': 'sqlite', 6 | 'filename': 'db.db3', 7 | 'create_db': True 8 | } 9 | ) -------------------------------------------------------------------------------- /pony/flask/example/models.py: -------------------------------------------------------------------------------- 1 | from pony.orm import Database, Required, Optional 2 | from flask_login import UserMixin 3 | from datetime import datetime 4 | 5 | db = Database() 6 | 7 | class User(db.Entity, UserMixin): 8 | login = Required(str, unique=True) 9 | password = Required(str) 10 | last_login = Optional(datetime) -------------------------------------------------------------------------------- /pony/flask/example/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello! 4 | 5 | 6 | 7 | 8 |
9 | {% with messages = get_flashed_messages() %} 10 | {% if messages %} 11 | {% for message in messages %} 12 | 13 | {% endfor %} 14 | {% endif %} 15 | {% endwith %} 16 | {% if not current_user.is_authenticated %} 17 |

Hi, please log in or register


18 | {% else %} 19 |

Hi, {{ current_user.login }}. Your last login: {{ current_user.last_login.strftime('%Y-%m-%d') }}

20 | Logout 21 |

List of users

22 | 33 | {% endif %} 34 |
35 | 36 | -------------------------------------------------------------------------------- /pony/flask/example/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Login page 4 | 5 | 6 | 7 | 8 |
9 | {% with messages = get_flashed_messages() %} 10 | {% if messages %} 11 | {% for message in messages %} 12 | 13 | {% endfor %} 14 | {% endif %} 15 | {% endwith %} 16 |

Please login

17 |
18 |
19 | 21 | 23 | 24 |
25 | {% if error %} 26 |

Error: {{ error }} 27 | {% endif %} 28 |

29 | 30 | -------------------------------------------------------------------------------- /pony/flask/example/templates/reg.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Login page 4 | 5 | 6 | 7 | 8 |
9 | {% with messages = get_flashed_messages() %} 10 | {% if messages %} 11 | {% for message in messages %} 12 | 13 | {% endfor %} 14 | {% endif %} 15 | {% endwith %} 16 |

Register

17 |
18 |
19 | 21 | 23 | 24 |
25 | {% if error %} 26 |

Error: {{ error }} 27 | {% endif %} 28 |

29 | 30 | -------------------------------------------------------------------------------- /pony/flask/example/views.py: -------------------------------------------------------------------------------- 1 | from .app import app 2 | from .models import db 3 | from flask import render_template, request, flash, redirect, abort 4 | from flask_login import current_user, logout_user, login_user, login_required 5 | from datetime import datetime 6 | from pony.orm import flush 7 | 8 | @app.route('/') 9 | def index(): 10 | users = db.User.select() 11 | return render_template('index.html', user=current_user, users=users) 12 | 13 | @app.route('/login', methods=['GET', 'POST']) 14 | def login(): 15 | if request.method == 'POST': 16 | username = request.form['username'] 17 | password = request.form['password'] 18 | possible_user = db.User.get(login=username) 19 | if not possible_user: 20 | flash('Wrong username') 21 | return redirect('/login') 22 | if possible_user.password == password: 23 | possible_user.last_login = datetime.now() 24 | login_user(possible_user) 25 | return redirect('/') 26 | 27 | flash('Wrong password') 28 | return redirect('/login') 29 | else: 30 | return render_template('login.html') 31 | 32 | @app.route('/reg', methods=['GET', 'POST']) 33 | def reg(): 34 | if request.method == 'POST': 35 | username = request.form['username'] 36 | password = request.form['password'] 37 | exist = db.User.get(login=username) 38 | if exist: 39 | flash('Username %s is already taken, choose another one' % username) 40 | return redirect('/reg') 41 | 42 | user = db.User(login=username, password=password) 43 | user.last_login = datetime.now() 44 | flush() 45 | login_user(user) 46 | flash('Successfully registered') 47 | return redirect('/') 48 | else: 49 | return render_template('reg.html') 50 | 51 | @app.route('/logout') 52 | @login_required 53 | def logout(): 54 | logout_user() 55 | flash('Logged out') 56 | return redirect('/') -------------------------------------------------------------------------------- /pony/options.py: -------------------------------------------------------------------------------- 1 | DEBUG = True 2 | 3 | STATIC_DIR = None 4 | 5 | CUT_TRACEBACK = True 6 | 7 | #postprocessing options: 8 | STD_DOCTYPE = '' 9 | STD_STYLESHEETS = [ 10 | ("/pony/static/blueprint/screen.css", "screen, projection"), 11 | ("/pony/static/blueprint/print.css", "print"), 12 | ("/pony/static/blueprint/ie.css.css", "screen, projection", "if IE"), 13 | ("/pony/static/css/default.css", "screen, projection"), 14 | ] 15 | BASE_STYLESHEETS_PLACEHOLDER = '' 16 | COMPONENT_STYLESHEETS_PLACEHOLDER = '' 17 | SCRIPTS_PLACEHOLDER = '' 18 | 19 | # reloading options: 20 | RELOADING_CHECK_INTERVAL = 1.0 # in seconds 21 | 22 | # logging options: 23 | LOG_TO_SQLITE = None 24 | LOGGING_LEVEL = None 25 | LOGGING_PONY_LEVEL = None 26 | 27 | #auth options: 28 | MAX_SESSION_CTIME = 60*24 # one day 29 | MAX_SESSION_MTIME = 60*2 # 2 hours 30 | MAX_LONGLIFE_SESSION = 14 # 14 days 31 | COOKIE_SERIALIZATION_TYPE = 'json' # may be 'json' or 'pickle' 32 | COOKIE_NAME = 'pony' 33 | COOKIE_PATH = '/' 34 | COOKIE_DOMAIN = None 35 | HASH_ALGORITHM = None # sha-1 by default 36 | # HASH_ALGORITHM = hashlib.sha512 37 | 38 | SESSION_STORAGE = None # pony.sessionstorage.memcachedstorage by default 39 | # SESSION_STORAGE = mystoragemodule 40 | # SESSION_STORAGE = False # means use cookies for save session data, 41 | # can lead to race conditions 42 | 43 | # memcached options (ignored under GAE): 44 | MEMCACHE = None # Use in-process python version by default 45 | # MEMCACHE = [ "127.0.0.1:11211" ] 46 | # MEMCACHE = MyMemcacheConnectionImplementation(...) 47 | ALTERNATIVE_SESSION_MEMCACHE = None # Use general memcache connection by default 48 | ALTERNATIVE_ORM_MEMCACHE = None # Use general memcache connection by default 49 | ALTERNATIVE_TEMPLATING_MEMCACHE = None # Use general memcache connection by default 50 | ALTERNATIVE_RESPONSE_MEMCACHE = None # Use general memcache connection by default 51 | 52 | # pickle options: 53 | PICKLE_START_OFFSET = 230 54 | PICKLE_HTML_AS_PLAIN_STR = True 55 | 56 | # encoding options for pony.pathces.repr 57 | RESTORE_ESCAPES = True 58 | SOURCE_ENCODING = None 59 | CONSOLE_ENCODING = None 60 | 61 | # db options 62 | MAX_FETCH_COUNT = None 63 | 64 | # used for select(...).show() 65 | CONSOLE_WIDTH = 80 66 | 67 | # sql translator options 68 | SIMPLE_ALIASES = True # if True just use entity name like "Course-1" 69 | # if False use attribute names chain as an alias like "student-grades-course" 70 | 71 | INNER_JOIN_SYNTAX = False # put conditions to INNER JOIN ... ON ... or to WHERE ... 72 | 73 | # debugging options 74 | DEBUGGING_REMOVE_ADDR = True 75 | DEBUGGING_RESTORE_ESCAPES = True 76 | -------------------------------------------------------------------------------- /pony/orm/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from pony.orm.core import * 4 | -------------------------------------------------------------------------------- /pony/orm/dbproviders/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ponyorm/pony/b9375605edacde9e68e3fc5c578a4b090a36cb8d/pony/orm/dbproviders/__init__.py -------------------------------------------------------------------------------- /pony/orm/dbproviders/cockroach.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from pony.py23compat import buffer, int_types 3 | 4 | from decimal import Decimal 5 | from datetime import datetime, date, time, timedelta 6 | from uuid import UUID 7 | 8 | try: 9 | import psycopg2 10 | except ImportError: 11 | try: 12 | from psycopg2cffi import compat 13 | except ImportError: 14 | raise ImportError('In order to use PonyORM with CockroachDB please install psycopg2 or psycopg2cffi') 15 | else: 16 | compat.register() 17 | 18 | from pony.orm.dbproviders.postgres import ( 19 | PGSQLBuilder, PGColumn, PGSchema, PGTranslator, PGProvider, 20 | PGIntConverter, PGRealConverter, 21 | PGDatetimeConverter, PGTimedeltaConverter, 22 | PGBlobConverter, PGJsonConverter, PGArrayConverter, 23 | ) 24 | 25 | from pony.orm import core, dbapiprovider, ormtypes 26 | from pony.orm.core import log_orm 27 | from pony.orm.dbapiprovider import wrap_dbapi_exceptions 28 | 29 | NoneType = type(None) 30 | 31 | class CRColumn(PGColumn): 32 | auto_template = 'SERIAL PRIMARY KEY' 33 | 34 | class CRSchema(PGSchema): 35 | column_class = CRColumn 36 | 37 | class CRTranslator(PGTranslator): 38 | pass 39 | 40 | class CRSQLBuilder(PGSQLBuilder): 41 | pass 42 | 43 | class CRIntConverter(PGIntConverter): 44 | signed_types = {None: 'INT', 8: 'INT2', 16: 'INT2', 24: 'INT8', 32: 'INT8', 64: 'INT8'} 45 | unsigned_types = {None: 'INT', 8: 'INT2', 16: 'INT4', 24: 'INT8', 32: 'INT8'} 46 | # signed_types = {None: 'INT', 8: 'INT2', 16: 'INT2', 24: 'INT4', 32: 'INT4', 64: 'INT8'} 47 | # unsigned_types = {None: 'INT', 8: 'INT2', 16: 'INT4', 24: 'INT4', 32: 'INT8'} 48 | 49 | class CRBlobConverter(PGBlobConverter): 50 | def sql_type(converter): 51 | return 'BYTES' 52 | 53 | class CRTimedeltaConverter(PGTimedeltaConverter): 54 | sql_type_name = 'INTERVAL' 55 | 56 | class PGUuidConverter(dbapiprovider.UuidConverter): 57 | def py2sql(converter, val): 58 | return val 59 | 60 | class CRArrayConverter(PGArrayConverter): 61 | array_types = { 62 | int: ('INT', PGIntConverter), 63 | str: ('STRING', dbapiprovider.StrConverter), 64 | float: ('DOUBLE PRECISION', PGRealConverter) 65 | } 66 | 67 | class CRProvider(PGProvider): 68 | dbapi_module = psycopg2 69 | dbschema_cls = CRSchema 70 | translator_cls = CRTranslator 71 | sqlbuilder_cls = CRSQLBuilder 72 | array_converter_cls = CRArrayConverter 73 | 74 | default_schema_name = 'public' 75 | 76 | fk_types = { 'SERIAL' : 'INT8' } 77 | 78 | def normalize_name(provider, name): 79 | return name[:provider.max_name_len].lower() 80 | 81 | @wrap_dbapi_exceptions 82 | def set_transaction_mode(provider, connection, cache): 83 | assert not cache.in_transaction 84 | db_session = cache.db_session 85 | if db_session is not None and db_session.ddl: 86 | cache.immediate = False 87 | if cache.immediate and connection.autocommit: 88 | connection.autocommit = False 89 | if core.local.debug: log_orm('SWITCH FROM AUTOCOMMIT TO TRANSACTION MODE') 90 | elif not cache.immediate and not connection.autocommit: 91 | connection.autocommit = True 92 | if core.local.debug: log_orm('SWITCH TO AUTOCOMMIT MODE') 93 | if db_session is not None and (db_session.serializable or db_session.ddl): 94 | cache.in_transaction = True 95 | 96 | converter_classes = [ 97 | (NoneType, dbapiprovider.NoneConverter), 98 | (bool, dbapiprovider.BoolConverter), 99 | (str, dbapiprovider.StrConverter), 100 | (int_types, CRIntConverter), 101 | (float, PGRealConverter), 102 | (Decimal, dbapiprovider.DecimalConverter), 103 | (datetime, PGDatetimeConverter), 104 | (date, dbapiprovider.DateConverter), 105 | (time, dbapiprovider.TimeConverter), 106 | (timedelta, CRTimedeltaConverter), 107 | (UUID, PGUuidConverter), 108 | (buffer, CRBlobConverter), 109 | (ormtypes.Json, PGJsonConverter), 110 | ] 111 | 112 | provider_cls = CRProvider 113 | -------------------------------------------------------------------------------- /pony/orm/examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ponyorm/pony/b9375605edacde9e68e3fc5c578a4b090a36cb8d/pony/orm/examples/__init__.py -------------------------------------------------------------------------------- /pony/orm/examples/bottle_example.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function 2 | 3 | from bottle import default_app, install, route, request, redirect, run, template 4 | 5 | # Import eStore model http://editor.ponyorm.com/user/pony/eStore 6 | from pony.orm.examples.estore import * 7 | from pony.orm.integration.bottle_plugin import PonyPlugin 8 | 9 | # After the plugin is installed each request will be processed 10 | # in a separate database session. Once the HTTP request processing 11 | # is finished the plugin does the following: 12 | # * commit the changes to the database (or rollback if an exception happened) 13 | # * clear the transaction cache 14 | # * return the database connection to the connection pool 15 | install(PonyPlugin()) 16 | 17 | @route('/') 18 | @route('/products/') 19 | def all_products(): 20 | # Get the list of all products from the database 21 | products = select(p for p in Product) 22 | return template(''' 23 |

List of products

24 | 29 | ''', products=products) 30 | 31 | @route('/products/:id/') 32 | def show_product(id): 33 | # Get the instance of the Product entity by the primary key 34 | p = Product[id] 35 | # You can traverse entity relationship attributes inside the template 36 | # In this examples it is many-to-many relationship p.categories 37 | # Since the data were not loaded into the cache yet, 38 | # it will result in a separate SQL query. 39 | return template(''' 40 |

{{ p.name }}

41 |

Price: {{ p.price }}

42 |

Product categories:

43 | 48 | Edit product info 49 | Return to all products 50 | ''', p=p) 51 | 52 | @route('/products/:id/edit/') 53 | def edit_product(id): 54 | # Get the instance of the Product entity and display its attributes 55 | p = Product[id] 56 | return template(''' 57 |
58 | 59 | 60 | 61 | 63 | 64 | 65 | 67 |
Product name: 62 |
Product price: 66 |
68 | 69 |
70 |

Discard changes 71 |

Return to all products 72 | ''', p=p) 73 | 74 | @route('/products/:id/edit/', method='POST') 75 | def save_product(id): 76 | # Get the instance of the Product entity 77 | p = Product[id] 78 | # Update the attributes with the new values 79 | p.name = request.forms.get('name') 80 | p.price = request.forms.get('price') 81 | # We might put the commit() command here, but it is not necessary 82 | # because PonyPlugin will take care of this. 83 | redirect("/products/%d/" % p.id) 84 | # The Bottle's redirect function raises the HTTPResponse exception. 85 | # Normally PonyPlugin closes the session with rollback 86 | # if a callback function raises an exception. But in this case 87 | # PonyPlugin understands that this exception is not the error 88 | # and closes the session with commit. 89 | 90 | 91 | run(debug=True, host='localhost', port=8080, reloader=True) 92 | -------------------------------------------------------------------------------- /pony/orm/examples/compositekeys.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from datetime import date 4 | from pony.orm.core import * 5 | 6 | db = Database('sqlite', 'complex.sqlite', create_db=True) 7 | 8 | class Group(db.Entity): 9 | dept = Required('Department') 10 | year = Required(int) 11 | spec = Required(int) 12 | students = Set('Student') 13 | courses = Set('Course') 14 | lessons = Set('Lesson', columns=['building', 'number', 'dt']) 15 | PrimaryKey(dept, year, spec) 16 | 17 | class Department(db.Entity): 18 | number = PrimaryKey(int) 19 | faculty = Required('Faculty') 20 | name = Required(str) 21 | groups = Set(Group) 22 | teachers = Set('Teacher') 23 | 24 | class Faculty(db.Entity): 25 | number = PrimaryKey(int) 26 | name = Required(str) 27 | depts = Set(Department) 28 | 29 | class Student(db.Entity): 30 | name = Required(str) 31 | group = Required(Group) 32 | dob = Optional(date) 33 | grades = Set('Grade') 34 | PrimaryKey(name, group) 35 | 36 | class Grade(db.Entity): 37 | student = Required(Student, columns=['student_name', 'dept', 'year', 'spec']) 38 | task = Required('Task') 39 | date = Required(date) 40 | value = Required(int) 41 | PrimaryKey(student, task) 42 | 43 | class Task(db.Entity): 44 | course = Required('Course') 45 | type = Required(str) 46 | number = Required(int) 47 | descr = Optional(str) 48 | grades = Set(Grade) 49 | PrimaryKey(course, type, number) 50 | 51 | class Course(db.Entity): 52 | subject = Required('Subject') 53 | semester = Required(int) 54 | groups = Set(Group) 55 | tasks = Set(Task) 56 | lessons = Set('Lesson') 57 | teachers = Set('Teacher') 58 | PrimaryKey(subject, semester) 59 | 60 | class Subject(db.Entity): 61 | name = PrimaryKey(str) 62 | descr = Optional(str) 63 | courses = Set(Course) 64 | 65 | class Room(db.Entity): 66 | building = Required(str) 67 | number = Required(str) 68 | floor = Optional(int) 69 | schedules = Set('Lesson') 70 | PrimaryKey(building, number) 71 | 72 | class Teacher(db.Entity): 73 | dept = Required(Department) 74 | name = Required(str) 75 | courses = Set(Course) 76 | lessons = Set('Lesson') 77 | 78 | class Lesson(db.Entity): 79 | _table_ = 'Schedule' 80 | groups = Set(Group) 81 | course = Required(Course) 82 | room = Required(Room) 83 | teacher = Required(Teacher) 84 | date = Required(date) 85 | PrimaryKey(room, date) 86 | composite_key(teacher, date) 87 | 88 | db.generate_mapping(create_tables=True) 89 | 90 | def test_queries(): 91 | select(grade for grade in Grade if grade.task.type == 'Lab')[:] 92 | select(grade for grade in Grade if grade.task.descr.startswith('Intermediate'))[:] 93 | select(grade for grade in Grade if grade.task.course.semester == 2)[:] 94 | select(grade for grade in Grade if grade.task.course.subject.name == 'Math')[:] 95 | select(grade for grade in Grade if 'elementary' in grade.task.course.subject.descr.lower())[:] 96 | select(grade for grade in Grade if 'elementary' in grade.task.course.subject.descr.lower() and grade.task.descr.startswith('Intermediate'))[:] 97 | select(grade for grade in Grade if grade.task.descr.startswith('Intermediate') and 'elementary' in grade.task.course.subject.descr.lower())[:] 98 | select(s for s in Student if s.group.dept.faculty.name == 'Abc')[:] 99 | select(g for g in Group if avg(g.students.grades.value) > 4)[:] 100 | select(g for g in Group if avg(g.students.grades.value) > 4 and max(g.students.grades.date) < date(2011, 3, 2))[:] 101 | select(g for g in Group if '4-A' in g.lessons.room.number)[:] 102 | select(g for g in Group if 1 in g.lessons.room.floor)[:] 103 | select(t for t in Teacher if t not in t.courses.groups.lessons.teacher)[:] 104 | 105 | sql_debug(True) 106 | -------------------------------------------------------------------------------- /pony/orm/examples/demo.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function 2 | 3 | from decimal import Decimal 4 | from pony.orm import * 5 | 6 | db = Database("sqlite", "demo.sqlite", create_db=True) 7 | 8 | class Customer(db.Entity): 9 | id = PrimaryKey(int, auto=True) 10 | name = Required(str) 11 | email = Required(str, unique=True) 12 | orders = Set("Order") 13 | 14 | class Order(db.Entity): 15 | id = PrimaryKey(int, auto=True) 16 | total_price = Required(Decimal) 17 | customer = Required(Customer) 18 | items = Set("OrderItem") 19 | 20 | class Product(db.Entity): 21 | id = PrimaryKey(int, auto=True) 22 | name = Required(str) 23 | price = Required(Decimal) 24 | items = Set("OrderItem") 25 | 26 | class OrderItem(db.Entity): 27 | quantity = Required(int, default=1) 28 | order = Required(Order) 29 | product = Required(Product) 30 | PrimaryKey(order, product) 31 | 32 | sql_debug(True) 33 | db.generate_mapping(create_tables=True) 34 | 35 | def populate_database(): 36 | c1 = Customer(name='John Smith', email='john@example.com') 37 | c2 = Customer(name='Matthew Reed', email='matthew@example.com') 38 | c3 = Customer(name='Chuan Qin', email='chuanqin@example.com') 39 | c4 = Customer(name='Rebecca Lawson', email='rebecca@example.com') 40 | c5 = Customer(name='Oliver Blakey', email='oliver@example.com') 41 | 42 | p1 = Product(name='Kindle Fire HD', price=Decimal('284.00')) 43 | p2 = Product(name='Apple iPad with Retina Display', price=Decimal('478.50')) 44 | p3 = Product(name='SanDisk Cruzer 16 GB USB Flash Drive', price=Decimal('9.99')) 45 | p4 = Product(name='Kingston DataTraveler 16GB USB 2.0', price=Decimal('9.98')) 46 | p5 = Product(name='Samsung 840 Series 120GB SATA III SSD', price=Decimal('98.95')) 47 | p6 = Product(name='Crucial m4 256GB SSD SATA 6Gb/s', price=Decimal('188.67')) 48 | 49 | o1 = Order(customer=c1, total_price=Decimal('292.00')) 50 | OrderItem(order=o1, product=p1) 51 | OrderItem(order=o1, product=p4, quantity=2) 52 | 53 | o2 = Order(customer=c1, total_price=Decimal('478.50')) 54 | OrderItem(order=o2, product=p2) 55 | 56 | o3 = Order(customer=c2, total_price=Decimal('680.50')) 57 | OrderItem(order=o3, product=p2) 58 | OrderItem(order=o3, product=p4, quantity=2) 59 | OrderItem(order=o3, product=p6) 60 | 61 | o4 = Order(customer=c3, total_price=Decimal('99.80')) 62 | OrderItem(order=o4, product=p4, quantity=10) 63 | 64 | o5 = Order(customer=c4, total_price=Decimal('722.00')) 65 | OrderItem(order=o5, product=p1) 66 | OrderItem(order=o5, product=p2) 67 | 68 | commit() 69 | 70 | -------------------------------------------------------------------------------- /pony/orm/examples/inheritance1.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function 2 | 3 | from decimal import Decimal 4 | from datetime import date 5 | 6 | from pony import options 7 | options.CUT_TRACEBACK = False 8 | 9 | from pony.orm.core import * 10 | 11 | sql_debug(False) 12 | 13 | db = Database('sqlite', 'inheritance1.sqlite', create_db=True) 14 | 15 | class Person(db.Entity): 16 | id = PrimaryKey(int, auto=True) 17 | name = Required(str) 18 | dob = Optional(date) 19 | ssn = Required(str, unique=True) 20 | 21 | class Student(Person): 22 | group = Required("Group") 23 | mentor = Optional("Teacher") 24 | attend_courses = Set("Course") 25 | 26 | class Teacher(Person): 27 | teach_courses = Set("Course") 28 | apprentices = Set("Student") 29 | salary = Required(Decimal) 30 | 31 | class Assistant(Student, Teacher): 32 | pass 33 | 34 | class Professor(Teacher): 35 | position = Required(str) 36 | 37 | class Group(db.Entity): 38 | number = PrimaryKey(int) 39 | students = Set("Student") 40 | 41 | class Course(db.Entity): 42 | name = Required(str) 43 | semester = Required(int) 44 | students = Set(Student) 45 | teachers = Set(Teacher) 46 | PrimaryKey(name, semester) 47 | 48 | db.generate_mapping(create_tables=True) 49 | 50 | @db_session 51 | def populate_database(): 52 | if Person.select().first(): 53 | return # already populated 54 | 55 | p = Person(name='Person1', ssn='SSN1') 56 | g = Group(number=123) 57 | prof = Professor(name='Professor1', salary=1000, position='position1', ssn='SSN5') 58 | a1 = Assistant(name='Assistant1', group=g, salary=100, ssn='SSN4', mentor=prof) 59 | a2 = Assistant(name='Assistant2', group=g, salary=200, ssn='SSN6', mentor=prof) 60 | s1 = Student(name='Student1', group=g, ssn='SSN2', mentor=a1) 61 | s2 = Student(name='Student2', group=g, ssn='SSN3') 62 | commit() 63 | 64 | def show_all_persons(): 65 | for obj in Person.select(): 66 | print(obj) 67 | for attr in obj._attrs_: 68 | print(attr.name, "=", attr.__get__(obj)) 69 | print() 70 | 71 | if __name__ == '__main__': 72 | populate_database() 73 | # show_all_persons() 74 | 75 | sql_debug(True) 76 | 77 | with db_session: 78 | s1 = Student.get(name='Student1') 79 | if s1 is None: 80 | print('Student1 not found') 81 | else: 82 | mentor = s1.mentor 83 | print(mentor.name, 'is mentor of Student1') 84 | print('Is he assistant?', isinstance(mentor, Assistant)) 85 | print() 86 | 87 | for s in Student.select(lambda s: s.mentor.salary == 1000): 88 | print(s.name) 89 | -------------------------------------------------------------------------------- /pony/orm/examples/numbers.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function 2 | 3 | from pony.orm.core import * 4 | 5 | db = Database() 6 | 7 | class Numbers(db.Entity): 8 | _table_ = "Numbers" 9 | id = PrimaryKey(int, auto=True) 10 | int8 = Required(int, size=8) # TINYINT 11 | int16 = Required(int, size=16) # SMALLINT 12 | int24 = Required(int, size=24) # MEDIUMINT 13 | int32 = Required(int, size=32) # INTEGER 14 | int64 = Required(int, size=64) # BIGINT 15 | uint8 = Required(int, size=8, unsigned=True) # TINYINT UNSIGNED 16 | uint16 = Required(int, size=16, unsigned=True) # SMALLINT UNSIGNED 17 | uint24 = Required(int, size=24, unsigned=True) # MEDIUMINT UNSIGNED 18 | uint32 = Required(int, size=32, unsigned=True) # INTEGER UNSIGNED 19 | # uint64 = Required(int, size=64, unsigned=True) # BIGINT UNSIGNED, supported by MySQL and Oracle 20 | 21 | sql_debug(True) # Output all SQL queries to stdout 22 | 23 | db.bind('sqlite', 'test_numbers.sqlite', create_db=True) 24 | #db.bind('mysql', host="localhost", user="pony", passwd="pony", db="test_numbers") 25 | #db.bind('postgres', user='pony', password='pony', host='localhost', database='test_numbers') 26 | #db.bind('oracle', 'test_numbers/pony@localhost') 27 | 28 | db.drop_table("Numbers", if_exists=True, with_all_data=True) 29 | db.generate_mapping(create_tables=True) 30 | 31 | @db_session 32 | def populate_database(): 33 | lo = Numbers(int8=-128, 34 | int16=-32768, 35 | int24=-8388608, 36 | int32=-2147483648, 37 | int64=-9223372036854775808, 38 | uint8=0, uint16=0, uint24=0, uint32=0) #, uint64=0) 39 | hi = Numbers(int8=127, 40 | int16=32767, 41 | int24=8388607, 42 | int32=2147483647, 43 | int64=9223372036854775807, 44 | uint8=255, 45 | uint16=65535, 46 | uint24=16777215, 47 | uint32=4294967295) 48 | # uint64=18446744073709551615) 49 | commit() 50 | 51 | @db_session 52 | def test_data(): 53 | for n in Numbers.select(): 54 | print(n.id, n.int8, n.int16, n.int24, n.int32, n.int64, 55 | n.uint8, n.uint16, n.uint24, n.uint32) #, n.uint64) 56 | 57 | if __name__ == '__main__': 58 | populate_database() 59 | test_data() 60 | -------------------------------------------------------------------------------- /pony/orm/examples/university2.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function 2 | 3 | from pony.orm.core import * 4 | from decimal import Decimal 5 | from datetime import date 6 | 7 | db = Database() 8 | 9 | class Faculty(db.Entity): 10 | _table_ = 'Faculties' 11 | number = PrimaryKey(int) 12 | name = Required(str, unique=True) 13 | departments = Set('Department') 14 | 15 | class Department(db.Entity): 16 | _table_ = 'Departments' 17 | number = PrimaryKey(int) 18 | name = Required(str, unique=True) 19 | faculty = Required(Faculty) 20 | teachers = Set('Teacher') 21 | majors = Set('Major') 22 | groups = Set('Group') 23 | 24 | class Group(db.Entity): 25 | _table_ = 'Groups' 26 | number = PrimaryKey(int) 27 | grad_year = Required(int) 28 | department = Required(Department, column='dep') 29 | lessons = Set('Lesson', columns=['day_of_week', 'meeting_time', 'classroom_number', 'building']) 30 | students = Set('Student') 31 | 32 | class Student(db.Entity): 33 | _table_ = 'Students' 34 | name = Required(str) 35 | scholarship = Required(Decimal, 10, 2, default=Decimal('0.0')) 36 | group = Required(Group) 37 | grades = Set('Grade') 38 | 39 | class Major(db.Entity): 40 | _table_ = 'Majors' 41 | name = PrimaryKey(str) 42 | department = Required(Department) 43 | courses = Set('Course') 44 | 45 | class Subject(db.Entity): 46 | _table_ = 'Subjects' 47 | name = PrimaryKey(str) 48 | courses = Set('Course') 49 | teachers = Set('Teacher') 50 | 51 | class Course(db.Entity): 52 | _table_ = 'Courses' 53 | major = Required(Major) 54 | subject = Required(Subject) 55 | semester = Required(int) 56 | composite_key(major, subject, semester) 57 | lect_hours = Required(int) 58 | pract_hours = Required(int) 59 | credit = Required(int) 60 | lessons = Set('Lesson') 61 | grades = Set('Grade') 62 | 63 | class Lesson(db.Entity): 64 | _table_ = 'Lessons' 65 | day_of_week = Required(int) 66 | meeting_time = Required(int) 67 | classroom = Required('Classroom') 68 | PrimaryKey(day_of_week, meeting_time, classroom) 69 | course = Required(Course) 70 | teacher = Required('Teacher') 71 | groups = Set(Group) 72 | 73 | class Grade(db.Entity): 74 | _table_ = 'Grades' 75 | student = Required(Student) 76 | course = Required(Course) 77 | PrimaryKey(student, course) 78 | teacher = Required('Teacher') 79 | date = Required(date) 80 | value = Required(str) 81 | 82 | class Teacher(db.Entity): 83 | _table_ = 'Teachers' 84 | name = Required(str) 85 | degree = Optional(str) 86 | department = Required(Department) 87 | subjects = Set(Subject) 88 | lessons = Set(Lesson) 89 | grades = Set(Grade) 90 | 91 | class Building(db.Entity): 92 | _table_ = 'Buildings' 93 | number = PrimaryKey(str) 94 | description = Optional(str) 95 | classrooms = Set('Classroom') 96 | 97 | class Classroom(db.Entity): 98 | _table_ = 'Classrooms' 99 | building = Required(Building) 100 | number = Required(str) 101 | PrimaryKey(building, number) 102 | description = Optional(str) 103 | lessons = Set(Lesson) 104 | 105 | db.bind('sqlite', 'university2.sqlite', create_db=True) 106 | #db.bind('mysql', host='localhost', user='pony', passwd='pony', db='university2') 107 | #db.bind('postgres', user='pony', password='pony', host='localhost', database='university2') 108 | #db.bind('oracle', 'university2/pony@localhost') 109 | 110 | db.generate_mapping(create_tables=True) 111 | 112 | sql_debug(True) 113 | 114 | def test_queries(): 115 | # very simple query 116 | select(s for s in Student)[:] 117 | 118 | # one condition 119 | select(s for s in Student if s.scholarship > 0)[:] 120 | 121 | # multiple conditions 122 | select(s for s in Student if s.scholarship > 0 and s.group.number == 4142)[:] 123 | 124 | # no join here - attribute can be found in table Students 125 | select(s for s in Student if s.group.number == 4142)[:] 126 | 127 | # automatic join of two tables because grad_year is stored in table Groups 128 | select(s for s in Student if s.group.grad_year == 2011)[:] 129 | 130 | # still two tables are joined 131 | select(s for s in Student if s.group.department.number == 44)[:] 132 | 133 | # automatic join of tree tables 134 | select(s for s in Student if s.group.department.name == 'Ancient Philosophy')[:] 135 | 136 | # manual join of tables will produce equivalent query 137 | select(s for s in Student for g in Group if s.group == g and g.department.name == 'Ancient Philosophy')[:] 138 | 139 | # join two tables by composite foreign key 140 | select(c for c in Classroom for l in Lesson if l.classroom == c and l.course.subject.name == 'Physics')[:] 141 | 142 | # Lessons will be joined with Buildings directly without Classrooms 143 | select(s for s in Subject for l in Lesson if s == l.course.subject and l.classroom.building.description == 'some description')[:] 144 | 145 | # just another example of join of many tables 146 | select(c for c in Course if c.major.department.faculty.number == 4)[:] 147 | -------------------------------------------------------------------------------- /pony/orm/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ponyorm/pony/b9375605edacde9e68e3fc5c578a4b090a36cb8d/pony/orm/integration/__init__.py -------------------------------------------------------------------------------- /pony/orm/integration/bottle_plugin.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | from bottle import HTTPResponse, HTTPError 4 | from pony.orm.core import db_session 5 | 6 | def is_allowed_exception(e): 7 | return isinstance(e, HTTPResponse) and not isinstance(e, HTTPError) 8 | 9 | class PonyPlugin(object): 10 | name = 'pony' 11 | api = 2 12 | def apply(self, callback, route): 13 | return db_session(allowed_exceptions=is_allowed_exception)(callback) 14 | -------------------------------------------------------------------------------- /pony/orm/serialization.py: -------------------------------------------------------------------------------- 1 | import json 2 | from datetime import date, datetime 3 | from decimal import Decimal 4 | from collections import defaultdict 5 | 6 | from pony.orm.core import Entity, TransactionError 7 | from pony.utils import cut_traceback, throw 8 | 9 | class Bag(object): 10 | def __init__(bag, database): 11 | bag.database = database 12 | bag.session_cache = None 13 | bag.entity_configs = {} 14 | bag.objects = defaultdict(set) 15 | bag.vars = {} 16 | bag.dicts = defaultdict(dict) 17 | @cut_traceback 18 | def config(bag, entity, only=None, exclude=None, with_collections=True, with_lazy=False, related_objects=True): 19 | if bag.database.entities.get(entity.__name__) is not entity: throw(TypeError, 20 | 'Entity %s does not belong to database %r' % (entity.__name__, bag.database)) 21 | attrs = entity._get_attrs_(only, exclude, with_collections, with_lazy) 22 | bag.entity_configs[entity] = attrs, related_objects 23 | return attrs, related_objects 24 | @cut_traceback 25 | def put(bag, x): 26 | if isinstance(x, Entity): 27 | bag._put_object(x) 28 | else: 29 | try: x = list(x) 30 | except: throw(TypeError, 'Entity instance or a sequence of instances expected. Got: %r' % x) 31 | for item in x: 32 | if not isinstance(item, Entity): throw(TypeError, 33 | 'Entity instance or a sequence of instances expected. Got: %r' % item) 34 | bag._put_object(item) 35 | def _put_object(bag, obj): 36 | entity = obj.__class__ 37 | if bag.database.entities.get(entity.__name__) is not entity: throw(TypeError, 38 | 'Entity %s does not belong to database %r' % (entity.__name__, bag.database)) 39 | cache = bag.session_cache 40 | if cache is None: cache = bag.session_cache = obj._session_cache_ 41 | elif obj._session_cache_ is not cache: throw(TransactionError, 42 | 'An attempt to mix objects belonging to different transactions') 43 | bag.objects[entity].add(obj) 44 | def _reduce_composite_pk(bag, pk): 45 | return ','.join(str(item).replace('*', '**').replace(',', '*,') for item in pk) 46 | @cut_traceback 47 | def to_dict(bag): 48 | bag.dicts.clear() 49 | for entity, objects in bag.objects.items(): 50 | for obj in objects: 51 | dicts = bag.dicts[entity] 52 | if obj not in dicts: bag._process_object(obj) 53 | result = defaultdict(dict) 54 | for entity, dicts in bag.dicts.items(): 55 | composite_pk = len(entity._pk_columns_) > 1 56 | for obj, d in dicts.items(): 57 | pk = obj._get_raw_pkval_() 58 | if composite_pk: pk = bag._reduce_composite_pk(pk) 59 | else: pk = pk[0] 60 | result[entity.__name__][pk] = d 61 | bag.dicts.clear() 62 | return result 63 | def _process_object(bag, obj, process_related=True): 64 | entity = obj.__class__ 65 | try: attrs, related_objects = bag.entity_configs[entity] 66 | except KeyError: attrs, related_objects = bag.config(entity) 67 | process_related_objects = process_related and related_objects 68 | d = {} 69 | for attr in attrs: 70 | value = attr.__get__(obj) 71 | if attr.is_collection: 72 | if not process_related: 73 | continue 74 | if process_related_objects: 75 | for related_obj in value: 76 | if related_obj not in bag.dicts: 77 | bag._process_object(related_obj, process_related=False) 78 | if attr.reverse.entity._pk_is_composite_: 79 | value = sorted(bag._reduce_composite_pk(item._get_raw_pkval_()) for item in value) 80 | else: value = sorted(item._get_raw_pkval_()[0] for item in value) 81 | elif attr.is_relation: 82 | if value is not None: 83 | if process_related_objects: 84 | bag._process_object(value, process_related=False) 85 | value = value._get_raw_pkval_() 86 | if len(value) == 1: value = value[0] 87 | d[attr.name] = value 88 | bag.dicts[entity][obj] = d 89 | @cut_traceback 90 | def to_json(bag): 91 | return json.dumps(bag.to_dict(), default=json_converter, indent=2, sort_keys=True) 92 | 93 | def to_dict(objects): 94 | if isinstance(objects, Entity): objects = [ objects ] 95 | objects = iter(objects) 96 | try: first_object = next(objects) 97 | except StopIteration: return {} 98 | if not isinstance(first_object, Entity): throw(TypeError, 99 | 'Entity instance or a sequence of instances expected. Got: %r' % first_object) 100 | database = first_object._database_ 101 | bag = Bag(database) 102 | bag.put(first_object) 103 | bag.put(objects) 104 | return dict(bag.to_dict()) 105 | 106 | def to_json(objects): 107 | return json.dumps(to_dict(objects), default=json_converter, indent=2, sort_keys=True) 108 | 109 | def json_converter(x): 110 | if isinstance(x, (datetime, date, Decimal)): 111 | return str(x) 112 | raise TypeError(x) 113 | -------------------------------------------------------------------------------- /pony/orm/sqlsymbols.py: -------------------------------------------------------------------------------- 1 | symbols = [ 'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'SELECT_FOR_UPDATE', 2 | 'FROM', 'INNER_JOIN', 'LEFT_JOIN', 'WHERE', 'GROUP_BY', 'HAVING', 3 | 'UNION', 'INTERSECT', 'EXCEPT', 4 | 'ORDER_BY', 'LIMIT', 'ASC', 'DESC', 5 | 'DISTINCT', 'ALL', 'AGGREGATES', 'AS', 6 | 'COUNT', 'SUM', 'MIN', 'MAX', 'AVG', 7 | 'TABLE', 'COLUMN', 'PARAM', 'VALUE', 'AND', 'OR', 'NOT', 8 | 'EQ', 'NE', 'LT', 'LE', 'GT', 'GE', 'IS_NULL', 'IS_NOT_NULL', 9 | 'LIKE', 'NOT_LIKE', 'BETWEEN', 'NOT_BETWEEN', 10 | 'IN', 'NOT_IN', 'EXISTS', 'NOT_EXISTS', 'ROW', 11 | 'ADD', 'SUB', 'MUL', 'DIV', 'POW', 'NEG', 'ABS', 12 | 'UPPER', 'LOWER', 'CONCAT', 'STRIN', 'LIKE', 'SUBSTR', 'LENGTH', 13 | 'TRIM', 'LTRIM', 'RTRIM', 'REPLACE', 14 | 'CASE', 'COALESCE', 15 | 'TO_INT', 'RANDOM', 16 | 'DATE', 'YEAR', 'MONTH', 'DAY', 'HOUR', 'MINUTE', 'SECOND', 'TODAY', 'NOW', 17 | 'DATE_ADD', 'DATE_SUB', 'DATETIME_ADD', 'DATETIME_SUB' ] 18 | 19 | globals().update((s, s) for s in symbols) 20 | -------------------------------------------------------------------------------- /pony/orm/tests/__init__.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | import types 4 | import pony.orm.core, pony.options 5 | 6 | pony.options.CUT_TRACEBACK = False 7 | pony.orm.core.sql_debug(False) 8 | 9 | 10 | def _load_env(): 11 | settings_filename = os.environ.get('pony_test_db') 12 | if settings_filename is None: 13 | print('use default sqlite provider') 14 | return dict(provider='sqlite', filename=':memory:') 15 | with open(settings_filename, 'r') as f: 16 | content = f.read() 17 | 18 | config = {} 19 | exec(content, config) 20 | settings = config.get('settings') 21 | if settings is None or not isinstance(settings, dict): 22 | raise ValueError('Incorrect settings pony test db file contents') 23 | provider = settings.get('provider') 24 | if provider is None: 25 | raise ValueError('Incorrect settings pony test db file contents: provider was not specified') 26 | print('use provider %s' % provider) 27 | return settings 28 | 29 | 30 | db_params = _load_env() 31 | 32 | 33 | def setup_database(db): 34 | if db.provider is None: 35 | db.bind(**db_params) 36 | if db.schema is None: 37 | db.generate_mapping(check_tables=False) 38 | db.drop_all_tables(with_all_data=True) 39 | db.create_tables() 40 | 41 | 42 | def teardown_database(db): 43 | if db.schema: 44 | db.drop_all_tables(with_all_data=True) 45 | db.disconnect() 46 | 47 | 48 | def only_for(providers): 49 | if not isinstance(providers, (list, tuple)): 50 | providers = [providers] 51 | def decorator(x): 52 | if isinstance(x, type) and issubclass(x, unittest.TestCase): 53 | @classmethod 54 | def setUpClass(cls): 55 | raise unittest.SkipTest('%s tests implemented only for %s provider%s' % ( 56 | cls.__name__, ', '.join(providers), '' if len(providers) < 2 else 's' 57 | )) 58 | if db_params['provider'] not in providers: 59 | x.setUpClass = setUpClass 60 | result = x 61 | elif isinstance(x, types.FunctionType): 62 | def new_test_func(self): 63 | if db_params['provider'] not in providers: 64 | raise unittest.SkipTest('%s test implemented only for %s provider%s' % ( 65 | x.__name__, ', '.join(providers), '' if len(providers) < 2 else 's' 66 | )) 67 | return x(self) 68 | result = new_test_func 69 | else: 70 | raise TypeError 71 | return result 72 | return decorator 73 | -------------------------------------------------------------------------------- /pony/orm/tests/aggregate_count_queries.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ponyorm/pony/b9375605edacde9e68e3fc5c578a4b090a36cb8d/pony/orm/tests/aggregate_count_queries.txt -------------------------------------------------------------------------------- /pony/orm/tests/coverage.bat: -------------------------------------------------------------------------------- 1 | C:\Python33\Scripts\coverage.exe erase 2 | 3 | 4 | C:\Python26\Scripts\coverage.exe run --source pony.orm.dbapiprovider,pony.orm.dbschema,pony.orm.decompiling,pony.orm.core,pony.orm.sqlbuilding,pony.orm.sqltranslation --branch -m unittest discover 5 | 6 | C:\Python27\Scripts\coverage.exe run --source pony.orm.dbapiprovider,pony.orm.dbschema,pony.orm.decompiling,pony.orm.core,pony.orm.sqlbuilding,pony.orm.sqltranslation --branch -m unittest discover 7 | 8 | C:\Python33\Scripts\coverage.exe run --source pony.orm.dbapiprovider,pony.orm.dbschema,pony.orm.decompiling,pony.orm.core,pony.orm.sqlbuilding,pony.orm.sqltranslation --branch -m unittest discover 9 | 10 | 11 | C:\Python26\Scripts\coverage.exe run -a --source pony.orm.dbapiprovider,pony.orm.dbschema,pony.orm.decompiling,pony.orm.core,pony.orm.sqlbuilding,pony.orm.sqltranslation --branch sql_tests.py 12 | 13 | C:\Python27\Scripts\coverage.exe run -a --source pony.orm.dbapiprovider,pony.orm.dbschema,pony.orm.decompiling,pony.orm.core,pony.orm.sqlbuilding,pony.orm.sqltranslation --branch sql_tests.py 14 | 15 | C:\Python33\Scripts\coverage.exe run -a --source pony.orm.dbapiprovider,pony.orm.dbschema,pony.orm.decompiling,pony.orm.core,pony.orm.sqlbuilding,pony.orm.sqltranslation --branch sql_tests.py 16 | 17 | 18 | C:\Python33\Scripts\coverage.exe html 19 | -------------------------------------------------------------------------------- /pony/orm/tests/coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | coverage erase 4 | 5 | coverage-2.7 run --source pony.orm.dbapiprovider,pony.orm.dbschema,pony.orm.decompiling,pony.orm.core,pony.orm.sqlbuilding,pony.orm.sqltranslation --branch -m unittest discover 6 | 7 | coverage-3.4 run --source pony.orm.dbapiprovider,pony.orm.dbschema,pony.orm.decompiling,pony.orm.core,pony.orm.sqlbuilding,pony.orm.sqltranslation --branch -m unittest discover 8 | 9 | 10 | coverage-2.7 run -a --source pony.orm.dbapiprovider,pony.orm.dbschema,pony.orm.decompiling,pony.orm.core,pony.orm.sqlbuilding,pony.orm.sqltranslation --branch sql_tests.py 11 | 12 | coverage-3.4 run -a --source pony.orm.dbapiprovider,pony.orm.dbschema,pony.orm.decompiling,pony.orm.core,pony.orm.sqlbuilding,pony.orm.sqltranslation --branch sql_tests.py 13 | 14 | coverage html 15 | -------------------------------------------------------------------------------- /pony/orm/tests/model1-database.sql: -------------------------------------------------------------------------------- 1 | drop table if exists Groups; 2 | create table Groups( 3 | number varchar(6) primary key, 4 | department integer not null 5 | ); 6 | 7 | drop table if exists Students; 8 | create table Students( 9 | record integer primary key, 10 | fio varchar(50) not null, 11 | [group] varchar(6) not null references Groups(number), 12 | scholarship integer not null default 0 13 | ); 14 | 15 | drop table if exists Subjects; 16 | create table Subjects( 17 | name varchar(50) primary key 18 | ); 19 | 20 | drop table if exists Group_Subject; 21 | create table Group_Subject( 22 | [group] varchar(6) not null references Groups(number), 23 | subject varchar(50) not null references Subjects(name), 24 | primary key ([group], subject) 25 | ); 26 | 27 | drop table if exists Exams; 28 | create table Exams( 29 | student integer not null references Students(number), 30 | subject varchar(50) not null references Subjects(name), 31 | value integer not null, 32 | primary key (student, subject) 33 | ); 34 | 35 | insert into Groups values ('4145', 44); 36 | insert into Groups values ('4146', 44); 37 | insert into Groups values ('3132', 33); 38 | 39 | insert into Students values(101, 'Bob', '4145', 0); 40 | insert into Students values(102, 'Joe', '4145', 800); 41 | insert into Students values(103, 'Alex', '4145', 0); 42 | insert into Students values(104, 'Brad', '3132', 500); 43 | insert into Students values(105, 'John', '3132', 1000); 44 | 45 | insert into Subjects values('Physics'); 46 | insert into Subjects values('Chemistry'); 47 | insert into Subjects values('Math'); 48 | 49 | insert into Group_Subject values('4145', 'Physics'); 50 | insert into Group_Subject values('4145', 'Chemistry'); 51 | insert into Group_Subject values('4145', 'Math'); 52 | insert into Group_Subject values('3132', 'Physics'); 53 | insert into Group_Subject values('3132', 'Math'); 54 | 55 | insert into Exams values (101, 'Physics', 4); 56 | insert into Exams values (101, 'Math', 3); 57 | insert into Exams values (102, 'Chemistry', 5); 58 | insert into Exams values (103, 'Physics', 2); 59 | insert into Exams values (103, 'Chemistry', 4); 60 | -------------------------------------------------------------------------------- /pony/orm/tests/model1.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | from pony.orm.core import * 4 | from pony.orm.tests import db_params 5 | 6 | db = Database(**db_params) 7 | 8 | class Student(db.Entity): 9 | _table_ = "Students" 10 | record = PrimaryKey(int) 11 | name = Required(str, column="fio") 12 | group = Required("Group") 13 | scholarship = Required(int, default=0) 14 | marks = Set("Mark") 15 | 16 | class Group(db.Entity): 17 | _table_ = "Groups" 18 | number = PrimaryKey(str) 19 | department = Required(int) 20 | students = Set("Student") 21 | subjects = Set("Subject") 22 | 23 | class Subject(db.Entity): 24 | _table_ = "Subjects" 25 | name = PrimaryKey(str) 26 | groups = Set("Group") 27 | marks = Set("Mark") 28 | 29 | class Mark(db.Entity): 30 | _table_ = "Exams" 31 | student = Required(Student, column="student") 32 | subject = Required(Subject, column="subject") 33 | value = Required(int) 34 | PrimaryKey(student, subject) 35 | 36 | 37 | db.generate_mapping(check_tables=False) 38 | 39 | 40 | @db_session 41 | def populate_db(): 42 | Physics = Subject(name='Physics') 43 | Chemistry = Subject(name='Chemistry') 44 | Math = Subject(name='Math') 45 | 46 | g3132 = Group(number='3132', department=33, subjects=[ Physics, Math ]) 47 | g4145 = Group(number='4145', department=44, subjects=[ Physics, Chemistry, Math ]) 48 | g4146 = Group(number='4146', department=44) 49 | 50 | s101 = Student(record=101, name='Bob', group=g4145, scholarship=0) 51 | s102 = Student(record=102, name='Joe', group=g4145, scholarship=800) 52 | s103 = Student(record=103, name='Alex', group=g4145, scholarship=0) 53 | s104 = Student(record=104, name='Brad', group=g3132, scholarship=500) 54 | s105 = Student(record=105, name='John', group=g3132, scholarship=1000) 55 | 56 | Mark(student=s101, subject=Physics, value=4) 57 | Mark(student=s101, subject=Math, value=3) 58 | Mark(student=s102, subject=Chemistry, value=5) 59 | Mark(student=s103, subject=Physics, value=2) 60 | Mark(student=s103, subject=Chemistry, value=4) 61 | -------------------------------------------------------------------------------- /pony/orm/tests/poster_queries.txt: -------------------------------------------------------------------------------- 1 | Schema: 2 | pony.orm.examples.estore 3 | 4 | >>> x = "joe@example.com" 5 | >>> select((o for o in Order if o.customer.email == x))[:] 6 | 7 | SELECT "o"."id", "o"."state", "o"."date_created", "o"."date_shipped", "o"."date_delivered", "o"."total_price", "o"."customer" 8 | FROM "Order" "o", "Customer" "customer-1" 9 | WHERE "customer-1"."email" = ? 10 | AND "o"."customer" = "customer-1"."id" 11 | 12 | MySQL: 13 | 14 | SELECT `o`.`id`, `o`.`state`, `o`.`date_created`, `o`.`date_shipped`, `o`.`date_delivered`, `o`.`total_price`, `o`.`customer` 15 | FROM `Order` `o`, `Customer` `customer-1` 16 | WHERE `customer-1`.`email` = %s 17 | AND `o`.`customer` = `customer-1`.`id` 18 | 19 | PostgreSQL: 20 | 21 | SELECT "o"."id", "o"."state", "o"."date_created", "o"."date_shipped", "o"."date_delivered", "o"."total_price", "o"."customer" 22 | FROM "order" "o", "customer" "customer-1" 23 | WHERE "customer-1"."email" = %(p1)s 24 | AND "o"."customer" = "customer-1"."id" 25 | 26 | Oracle: 27 | 28 | SELECT "o"."ID", "o"."STATE", "o"."DATE_CREATED", "o"."DATE_SHIPPED", "o"."DATE_DELIVERED", "o"."TOTAL_PRICE", "o"."CUSTOMER" 29 | FROM "ORDER" "o", "CUSTOMER" "customer-1" 30 | WHERE "customer-1"."EMAIL" = :p1 31 | AND "o"."CUSTOMER" = "customer-1"."ID" 32 | 33 | >>> avg(o.total_price for o in Order if o.date_created.year == 2012) 34 | 35 | SELECT AVG("o"."total_price") 36 | FROM "Order" "o" 37 | WHERE cast(substr("o"."date_created", 1, 4) as integer) = 2012 38 | 39 | MySQL: 40 | 41 | SELECT AVG(`o`.`total_price`) 42 | FROM `Order` `o` 43 | WHERE year(`o`.`date_created`) = 2012 44 | 45 | PostgreSQL: 46 | 47 | SELECT AVG("o"."total_price") 48 | FROM "order" "o" 49 | WHERE EXTRACT(YEAR FROM "o"."date_created") = 2012 50 | 51 | Oracle: 52 | 53 | SELECT AVG("o"."TOTAL_PRICE") 54 | FROM "ORDER" "o" 55 | WHERE EXTRACT(YEAR FROM "o"."DATE_CREATED") = 2012 56 | 57 | >>> select((c, sum(c.orders.total_price)) for c in Customer).order_by(lambda c: desc(sum(c.orders.total_price)))[:10] 58 | 59 | SELECT "c"."id", coalesce(SUM("order-1"."total_price"), 0) 60 | FROM "Customer" "c" 61 | LEFT JOIN "Order" "order-1" 62 | ON "c"."id" = "order-1"."customer" 63 | GROUP BY "c"."id" 64 | ORDER BY coalesce(SUM("order-1"."total_price"), 0) DESC 65 | LIMIT 10 66 | 67 | MySQL: 68 | 69 | SELECT `c`.`id`, coalesce(SUM(`order-1`.`total_price`), 0) 70 | FROM `Customer` `c` 71 | LEFT JOIN `Order` `order-1` 72 | ON `c`.`id` = `order-1`.`customer` 73 | GROUP BY `c`.`id` 74 | ORDER BY coalesce(SUM(`order-1`.`total_price`), 0) DESC 75 | LIMIT 10 76 | 77 | PostgreSQL: 78 | 79 | SELECT "c"."id", coalesce(SUM("order-1"."total_price"), 0) 80 | FROM "customer" "c" 81 | LEFT JOIN "order" "order-1" 82 | ON "c"."id" = "order-1"."customer" 83 | GROUP BY "c"."id" 84 | ORDER BY coalesce(SUM("order-1"."total_price"), 0) DESC 85 | LIMIT 10 86 | 87 | Oracle: 88 | 89 | SELECT * FROM ( 90 | SELECT "c"."ID", coalesce(SUM("order-1"."TOTAL_PRICE"), 0) 91 | FROM "CUSTOMER" "c" 92 | LEFT JOIN "ORDER" "order-1" 93 | ON "c"."ID" = "order-1"."CUSTOMER" 94 | GROUP BY "c"."ID" 95 | ORDER BY coalesce(SUM("order-1"."TOTAL_PRICE"), 0) DESC 96 | ) WHERE ROWNUM <= 10 97 | -------------------------------------------------------------------------------- /pony/orm/tests/sql_tests.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import re, os, os.path, sys 4 | from datetime import datetime, timedelta 5 | 6 | from pony import orm 7 | from pony.orm import core 8 | from pony.orm.tests import testutils 9 | 10 | core.suppress_debug_change = True 11 | 12 | directive_re = re.compile(r'(\w+)(\s+[0-9\.]+)?:') 13 | directive = module_name = None 14 | statements = [] 15 | lines = [] 16 | 17 | def Schema(param): 18 | if not statement_used: 19 | print() 20 | print('Statement not used:') 21 | print() 22 | print('\n'.join(statements)) 23 | print() 24 | sys.exit() 25 | assert len(lines) == 1 26 | global module_name 27 | module_name = lines[0].strip() 28 | 29 | def SQLite(server_version): 30 | do_test('sqlite', server_version) 31 | 32 | def MySQL(server_version): 33 | do_test('mysql', server_version) 34 | 35 | def PostgreSQL(server_version): 36 | do_test('postgres', server_version) 37 | 38 | def Oracle(server_version): 39 | do_test('oracle', server_version) 40 | 41 | unavailable_providers = set() 42 | 43 | def do_test(provider_name, raw_server_version): 44 | if provider_name in unavailable_providers: return 45 | testutils.TestDatabase.real_provider_name = provider_name 46 | testutils.TestDatabase.raw_server_version = raw_server_version 47 | core.Database = orm.Database = testutils.TestDatabase 48 | sys.modules.pop(module_name, None) 49 | try: __import__(module_name) 50 | except ImportError as e: 51 | print() 52 | print('ImportError for database provider %s:\n%s' % (provider_name, e)) 53 | print() 54 | unavailable_providers.add(provider_name) 55 | return 56 | module = sys.modules[module_name] 57 | globals = vars(module).copy() 58 | globals.update(datetime=datetime, timedelta=timedelta) 59 | with orm.db_session: 60 | for statement in statements[:-1]: 61 | code = compile(statement, '', 'exec') 62 | exec(code, globals) 63 | statement = statements[-1] 64 | try: last_code = compile(statement, '', 'eval') 65 | except SyntaxError: 66 | last_code = compile(statement, '', 'exec') 67 | exec(last_code, globals) 68 | else: 69 | result = eval(last_code, globals) 70 | if isinstance(result, core.Query): result = list(result) 71 | sql = module.db.sql 72 | expected_sql = '\n'.join(lines) 73 | if sql == expected_sql: print('.', end='') 74 | else: 75 | print() 76 | print(provider_name, statements[-1]) 77 | print() 78 | print('Expected:') 79 | print(expected_sql) 80 | print() 81 | print('Got:') 82 | print(sql) 83 | print() 84 | global statement_used 85 | statement_used = True 86 | 87 | dirname, fname = os.path.split(__file__) 88 | queries_fname = os.path.join(dirname, 'queries.txt') 89 | 90 | def orphan_lines(lines): 91 | SQLite(None) 92 | lines[:] = [] 93 | 94 | statement_used = True 95 | for raw_line in open(queries_fname): 96 | line = raw_line.strip() 97 | if not line: continue 98 | if line.startswith('#'): continue 99 | match = directive_re.match(line) 100 | if match: 101 | if directive: 102 | directive(directive_param) 103 | lines[:] = [] 104 | elif lines: orphan_lines(lines) 105 | directive = eval(match.group(1)) 106 | if match.group(2): 107 | directive_param = match.group(2) 108 | else: directive_param = None 109 | elif line.startswith('>>> '): 110 | if directive: 111 | directive(directive_param) 112 | lines[:] = [] 113 | statements[:] = [] 114 | elif lines: orphan_lines(lines) 115 | directive = None 116 | directive_param = None 117 | statements.append(line[4:]) 118 | statement_used = False 119 | else: 120 | lines.append(raw_line.rstrip()) 121 | 122 | if directive: 123 | directive(directive_param) 124 | elif lines: 125 | orphan_lines(lines) 126 | -------------------------------------------------------------------------------- /pony/orm/tests/test_attribute_options.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from decimal import Decimal 3 | from datetime import datetime, time 4 | from random import randint 5 | 6 | from pony import orm 7 | from pony.orm.core import * 8 | from pony.orm.tests import setup_database, teardown_database 9 | from pony.orm.tests.testutils import raises_exception 10 | 11 | db = Database() 12 | 13 | class Person(db.Entity): 14 | id = PrimaryKey(int) 15 | name = orm.Required(str, 40) 16 | lastName = orm.Required(str, max_len=40, unique=True) 17 | age = orm.Optional(int, max=60, min=10) 18 | nickName = orm.Optional(str, autostrip=False) 19 | middleName = orm.Optional(str, nullable=True) 20 | rate = orm.Optional(Decimal, precision=11) 21 | salaryRate = orm.Optional(Decimal, precision=13, scale=8) 22 | timeStmp = orm.Optional(datetime, precision=6) 23 | gpa = orm.Optional(float, py_check=lambda val: val >= 0 and val <= 5) 24 | vehicle = orm.Optional(str, column='car') 25 | 26 | class TestAttributeOptions(unittest.TestCase): 27 | @classmethod 28 | def setUpClass(cls): 29 | setup_database(db) 30 | with orm.db_session: 31 | p1 = Person(id=1, name='Andrew', lastName='Bodroue', age=40, rate=0.980000000001, salaryRate=0.98000001) 32 | p2 = Person(id=2, name='Vladimir', lastName='Andrew ', nickName='vlad ') 33 | p3 = Person(id=3, name='Nick', lastName='Craig', middleName=None, timeStmp='2010-12-10 14:12:09.019473', 34 | vehicle='dodge') 35 | 36 | @classmethod 37 | def tearDownClass(cls): 38 | teardown_database(db) 39 | 40 | def setUp(self): 41 | rollback() 42 | db_session.__enter__() 43 | 44 | def tearDown(self): 45 | rollback() 46 | db_session.__exit__() 47 | 48 | def test_optionalStringEmpty(self): 49 | queryResult = select(p.id for p in Person if p.nickName==None).first() 50 | self.assertIsNone(queryResult) 51 | 52 | def test_optionalStringNone(self): 53 | queryResult = select(p.id for p in Person if p.middleName==None).first() 54 | self.assertIsNotNone(queryResult) 55 | 56 | def test_stringAutoStrip(self): 57 | self.assertEqual(Person[2].lastName, 'Andrew') 58 | 59 | def test_stringAutoStripFalse(self): 60 | self.assertEqual(Person[2].nickName, 'vlad ') 61 | 62 | def test_intNone(self): 63 | queryResult = select(p.id for p in Person if p.age==None).first() 64 | self.assertIsNotNone(queryResult) 65 | 66 | def test_columnName(self): 67 | self.assertEqual(getattr(Person.vehicle, 'column'), 'car') 68 | 69 | def test_decimalPrecisionTwo(self): 70 | queryResult = select(p.rate for p in Person if p.age==40).first() 71 | self.assertAlmostEqual(float(queryResult), 0.98, 12) 72 | 73 | def test_decimalPrecisionEight(self): 74 | queryResult = select(p.salaryRate for p in Person if p.age==40).first() 75 | self.assertAlmostEqual(float(queryResult), 0.98000001, 8) 76 | 77 | def test_fractionalSeconds(self): 78 | queryResult = select(p.timeStmp for p in Person if p.name=='Nick').first() 79 | self.assertEqual(queryResult.microsecond, 19473) 80 | 81 | def test_intMax(self): 82 | p4 = Person(id=4, name='Denis', lastName='Blanc', age=60) 83 | 84 | def test_intMin(self): 85 | p4 = Person(id=4, name='Denis', lastName='Blanc', age=10) 86 | 87 | @raises_exception(ValueError, "Value 61 of attr Person.age is greater than the maximum allowed value 60") 88 | def test_intMaxException(self): 89 | p4 = Person(id=4, name='Denis', lastName='Blanc', age=61) 90 | 91 | @raises_exception(ValueError, "Value 9 of attr Person.age is less than the minimum allowed value 10") 92 | def test_intMinException(self): 93 | p4 = Person(id=4, name='Denis', lastName='Blanc', age=9) 94 | 95 | def test_py_check(self): 96 | p4 = Person(id=4, name='Denis', lastName='Blanc', gpa=5) 97 | p5 = Person(id=5, name='Mario', lastName='Gon', gpa=1) 98 | flush() 99 | 100 | @raises_exception(ValueError, "Check for attribute Person.gpa failed. Value: 6.0") 101 | def test_py_checkMoreException(self): 102 | p6 = Person(id=6, name='Daniel', lastName='Craig', gpa=6) 103 | 104 | @raises_exception(ValueError, "Check for attribute Person.gpa failed. Value: -1.0") 105 | def test_py_checkLessException(self): 106 | p6 = Person(id=6, name='Daniel', lastName='Craig', gpa=-1) 107 | 108 | @raises_exception(TransactionIntegrityError, 109 | 'Object Person[...] cannot be stored in the database. IntegrityError: ...') 110 | def test_unique(self): 111 | p6 = Person(id=6, name='Boris', lastName='Bodroue') 112 | flush() 113 | -------------------------------------------------------------------------------- /pony/orm/tests/test_autostrip.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pony.orm import * 4 | from pony.orm.tests.testutils import raises_exception 5 | from pony.orm.tests import setup_database, teardown_database 6 | 7 | db = Database() 8 | 9 | class Person(db.Entity): 10 | name = Required(str) 11 | tel = Optional(str) 12 | 13 | 14 | class TestAutostrip(unittest.TestCase): 15 | @classmethod 16 | def setUpClass(cls): 17 | setup_database(db) 18 | 19 | @classmethod 20 | def tearDownClass(cls): 21 | teardown_database(db) 22 | 23 | @db_session 24 | def test_1(self): 25 | p = Person(name=' John ', tel=' ') 26 | p.flush() 27 | self.assertEqual(p.name, 'John') 28 | self.assertEqual(p.tel, '') 29 | 30 | @raises_exception(ValueError, 'Attribute Person.name is required') 31 | @db_session 32 | def test_2(self): 33 | p = Person(name=' ') 34 | 35 | if __name__ == '__main__': 36 | unittest.main() 37 | -------------------------------------------------------------------------------- /pony/orm/tests/test_buffer.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pony import orm 4 | from pony.orm.tests import setup_database, teardown_database 5 | 6 | db = orm.Database() 7 | 8 | 9 | class Foo(db.Entity): 10 | id = orm.PrimaryKey(int) 11 | b = orm.Optional(orm.buffer) 12 | 13 | 14 | class Bar(db.Entity): 15 | b = orm.PrimaryKey(orm.buffer) 16 | 17 | 18 | class Baz(db.Entity): 19 | id = orm.PrimaryKey(int) 20 | b = orm.Optional(orm.buffer, unique=True) 21 | 22 | 23 | buf = orm.buffer(b'123') 24 | 25 | class Test(unittest.TestCase): 26 | @classmethod 27 | def setUpClass(cls): 28 | setup_database(db) 29 | with orm.db_session: 30 | Foo(id=1, b=buf) 31 | Bar(b=buf) 32 | Baz(id=1, b=buf) 33 | 34 | @classmethod 35 | def tearDownClass(cls): 36 | teardown_database(db) 37 | 38 | def test_1(self): # Bug #355 39 | with orm.db_session: 40 | Bar[buf] 41 | 42 | def test_2(self): # Regression after #355 fix 43 | with orm.db_session: 44 | result = orm.select(bar.b for bar in Foo)[:] 45 | self.assertEqual(result, [buf]) 46 | 47 | def test_3(self): # Bug #390 48 | with orm.db_session: 49 | Baz.get(b=buf) 50 | -------------------------------------------------------------------------------- /pony/orm/tests/test_bug_170.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pony import orm 4 | from pony.orm.tests import setup_database, teardown_database 5 | 6 | db = orm.Database() 7 | 8 | 9 | class Person(db.Entity): 10 | id = orm.PrimaryKey(int, auto=True) 11 | name = orm.Required(str) 12 | orm.composite_key(id, name) 13 | 14 | 15 | class Test(unittest.TestCase): 16 | @classmethod 17 | def setUpClass(cls): 18 | setup_database(db) 19 | 20 | @classmethod 21 | def tearDownClass(cls): 22 | teardown_database(db) 23 | 24 | def test_1(self): 25 | table = db.schema.tables[Person._table_] 26 | pk_column = table.column_dict[Person.id.column] 27 | self.assertTrue(pk_column.is_pk) 28 | 29 | with orm.db_session: 30 | p1 = Person(name='John') 31 | p2 = Person(name='Mike') 32 | -------------------------------------------------------------------------------- /pony/orm/tests/test_bug_182.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pony.orm import * 4 | from pony import orm 5 | from pony.orm.tests import setup_database, teardown_database 6 | 7 | db = Database() 8 | 9 | 10 | class User(db.Entity): 11 | name = Required(str) 12 | servers = Set("Server") 13 | 14 | 15 | class Worker(User): 16 | pass 17 | 18 | 19 | class Admin(Worker): 20 | pass 21 | 22 | # And M:1 relationship with another entity 23 | class Server(db.Entity): 24 | name = Required(str) 25 | user = Optional(User) 26 | 27 | 28 | class Test(unittest.TestCase): 29 | @classmethod 30 | def setUpClass(cls): 31 | setup_database(db) 32 | with orm.db_session: 33 | Server(name='s1.example.com', user=User(name="Alex")) 34 | Server(name='s2.example.com', user=Worker(name="John")) 35 | Server(name='free.example.com', user=None) 36 | 37 | @classmethod 38 | def tearDownClass(cls): 39 | teardown_database(db) 40 | 41 | @db_session 42 | def test(self): 43 | qu = left_join((s.name, s.user.name) for s in db.Server)[:] 44 | for server, user in qu: 45 | if user is None: 46 | break 47 | else: 48 | self.fail() 49 | 50 | -------------------------------------------------------------------------------- /pony/orm/tests/test_bug_331.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pony.orm.tests import setup_database, teardown_database 4 | from pony.orm import * 5 | 6 | db = Database() 7 | 8 | 9 | class Person(db.Entity): 10 | name = Required(str) 11 | group = Optional(lambda: Group) 12 | 13 | 14 | class Group(db.Entity): 15 | title = PrimaryKey(str) 16 | persons = Set(Person) 17 | 18 | def __len__(self): 19 | return len(self.persons) 20 | 21 | 22 | class Test(unittest.TestCase): 23 | @classmethod 24 | def setUpClass(cls): 25 | setup_database(db) 26 | 27 | @classmethod 28 | def tearDownClass(cls): 29 | teardown_database(db) 30 | 31 | def test_1(self): 32 | with db_session: 33 | p1 = Person(name="Alex") 34 | p2 = Person(name="Brad") 35 | p3 = Person(name="Chad") 36 | p4 = Person(name="Dylan") 37 | p5 = Person(name="Ethan") 38 | 39 | g1 = Group(title="Foxes") 40 | g2 = Group(title="Gorillas") 41 | 42 | g1.persons.add(p1) 43 | g1.persons.add(p2) 44 | g1.persons.add(p3) 45 | g2.persons.add(p4) 46 | g2.persons.add(p5) 47 | commit() 48 | 49 | foxes = Group['Foxes'] 50 | gorillas = Group['Gorillas'] 51 | 52 | self.assertEqual(len(foxes), 3) 53 | self.assertEqual(len(gorillas), 2) 54 | -------------------------------------------------------------------------------- /pony/orm/tests/test_bug_386.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pony import orm 4 | from pony.orm.tests import setup_database, teardown_database 5 | 6 | db = orm.Database() 7 | 8 | 9 | class Person(db.Entity): 10 | name = orm.Required(str) 11 | 12 | 13 | class Test(unittest.TestCase): 14 | @classmethod 15 | def setUpClass(cls): 16 | setup_database(db) 17 | 18 | @classmethod 19 | def tearDownClass(cls): 20 | teardown_database(db) 21 | 22 | def test_1(self): 23 | with orm.db_session: 24 | a = Person(name='John') 25 | a.delete() 26 | Person.exists(name='Mike') 27 | -------------------------------------------------------------------------------- /pony/orm/tests/test_cascade.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pony.orm import * 4 | from pony.orm.tests.testutils import * 5 | from pony.orm.tests import setup_database, teardown_database 6 | 7 | 8 | class TestCascade(unittest.TestCase): 9 | providers = ['sqlite'] # Implement for other providers 10 | 11 | def tearDown(self): 12 | if self.db.schema is not None: 13 | teardown_database(self.db) 14 | 15 | def assert_on_delete(self, table_name, value): 16 | db = self.db 17 | if not (db.provider.dialect == 'SQLite' and pony.__version__ < '0.9'): 18 | table_name = table_name.lower() 19 | table = db.schema.tables[table_name] 20 | fkeys = table.foreign_keys 21 | self.assertEqual(1, len(fkeys)) 22 | if pony.__version__ >= '0.9': 23 | self.assertEqual(fkeys[0].on_delete, value) 24 | elif db.provider.dialect == 'SQLite': 25 | self.assertIn('ON DELETE %s' % value, table.get_create_command()) 26 | else: 27 | self.assertIn('ON DELETE %s' % value, list(fkeys.values())[0].get_create_command()) 28 | 29 | 30 | def test_1(self): 31 | db = self.db = Database() 32 | 33 | class Person(self.db.Entity): 34 | name = Required(str) 35 | group = Required('Group') 36 | 37 | class Group(self.db.Entity): 38 | persons = Set(Person) 39 | 40 | setup_database(db) 41 | self.assert_on_delete('Person', 'CASCADE') 42 | 43 | def test_2(self): 44 | db = self.db = Database() 45 | 46 | class Person(self.db.Entity): 47 | name = Required(str) 48 | group = Required('Group') 49 | 50 | class Group(self.db.Entity): 51 | persons = Set(Person, cascade_delete=True) 52 | 53 | setup_database(db) 54 | self.assert_on_delete('Person', 'CASCADE') 55 | 56 | def test_3(self): 57 | db = self.db = Database() 58 | 59 | class Person(self.db.Entity): 60 | name = Required(str) 61 | group = Optional('Group') 62 | 63 | class Group(self.db.Entity): 64 | persons = Set(Person, cascade_delete=True) 65 | 66 | setup_database(db) 67 | self.assert_on_delete('Person', 'CASCADE') 68 | 69 | @raises_exception(TypeError, "'cascade_delete' option cannot be set for attribute Group.persons, because reverse attribute Person.group is collection") 70 | def test_4(self): 71 | db = self.db = Database() 72 | 73 | class Person(self.db.Entity): 74 | name = Required(str) 75 | group = Set('Group') 76 | 77 | class Group(self.db.Entity): 78 | persons = Set(Person, cascade_delete=True) 79 | 80 | setup_database(db) 81 | 82 | @raises_exception(TypeError, "'cascade_delete' option cannot be set for both sides of relationship (Person.group and Group.persons) simultaneously") 83 | def test_5(self): 84 | db = self.db = Database() 85 | 86 | class Person(self.db.Entity): 87 | name = Required(str) 88 | group = Set('Group', cascade_delete=True) 89 | 90 | class Group(self.db.Entity): 91 | persons = Required(Person, cascade_delete=True) 92 | 93 | setup_database(db) 94 | 95 | def test_6(self): 96 | db = self.db = Database() 97 | 98 | class Person(self.db.Entity): 99 | name = Required(str) 100 | group = Set('Group') 101 | 102 | class Group(self.db.Entity): 103 | persons = Optional(Person) 104 | 105 | setup_database(db) 106 | self.assert_on_delete('Group', 'SET NULL') 107 | 108 | 109 | if __name__ == '__main__': 110 | unittest.main() 111 | -------------------------------------------------------------------------------- /pony/orm/tests/test_cascade_delete.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pony.orm import * 4 | from pony.orm.tests import setup_database, teardown_database, only_for 5 | 6 | db = Database() 7 | 8 | class X(db.Entity): 9 | id = PrimaryKey(int) 10 | parent = Optional('X', reverse='children') 11 | children = Set('X', reverse='parent', cascade_delete=True) 12 | 13 | 14 | class Y(db.Entity): 15 | parent = Optional('Y', reverse='children') 16 | children = Set('Y', reverse='parent', cascade_delete=True, lazy=True) 17 | 18 | 19 | class TestCascade(unittest.TestCase): 20 | @classmethod 21 | def setUpClass(cls): 22 | setup_database(db) 23 | with db_session: 24 | x1 = X(id=1) 25 | x2 = X(id=2, parent=x1) 26 | x3 = X(id=3, parent=x1) 27 | x4 = X(id=4, parent=x3) 28 | x5 = X(id=5, parent=x3) 29 | x6 = X(id=6, parent=x5) 30 | x7 = X(id=7, parent=x3) 31 | x8 = X(id=8, parent=x7) 32 | x9 = X(id=9, parent=x7) 33 | x10 = X(id=10) 34 | x11 = X(id=11, parent=x10) 35 | x12 = X(id=12, parent=x10) 36 | 37 | y1 = Y(id=1) 38 | y2 = Y(id=2, parent=y1) 39 | y3 = Y(id=3, parent=y1) 40 | y4 = Y(id=4, parent=y3) 41 | y5 = Y(id=5, parent=y3) 42 | y6 = Y(id=6, parent=y5) 43 | y7 = Y(id=7, parent=y3) 44 | y8 = Y(id=8, parent=y7) 45 | y9 = Y(id=9, parent=y7) 46 | y10 = Y(id=10) 47 | y11 = Y(id=11, parent=y10) 48 | y12 = Y(id=12, parent=y10) 49 | 50 | @classmethod 51 | def tearDownClass(cls): 52 | teardown_database(db) 53 | 54 | def setUp(self): 55 | rollback() 56 | db_session.__enter__() 57 | 58 | def tearDown(self): 59 | rollback() 60 | db_session.__exit__() 61 | 62 | def test_1(self): 63 | db.merge_local_stats() 64 | X[1].delete() 65 | stats = db.local_stats[None] 66 | self.assertEqual(5, stats.db_count) 67 | 68 | def test_2(self): 69 | db.merge_local_stats() 70 | Y[1].delete() 71 | stats = db.local_stats[None] 72 | self.assertEqual(10, stats.db_count) 73 | -------------------------------------------------------------------------------- /pony/orm/tests/test_collections.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | 5 | from pony.orm.tests.testutils import raises_exception 6 | from pony.orm.tests.model1 import * 7 | from pony.orm.tests import setup_database, teardown_database 8 | 9 | 10 | class TestCollections(unittest.TestCase): 11 | @classmethod 12 | def setUpClass(cls): 13 | setup_database(db) 14 | populate_db() 15 | 16 | @classmethod 17 | def tearDownClass(cls): 18 | db.drop_all_tables(with_all_data=True) 19 | 20 | @db_session 21 | def test_setwrapper_len(self): 22 | g = Group.get(number='4145') 23 | self.assertTrue(len(g.students) == 3) 24 | 25 | @db_session 26 | def test_setwrapper_nonzero(self): 27 | g = Group.get(number='4145') 28 | self.assertTrue(bool(g.students) == True) 29 | self.assertTrue(len(g.students) == 3) 30 | 31 | @db_session 32 | @raises_exception(TypeError, 'Collection attribute Group.students cannot be specified as search criteria') 33 | def test_get_by_collection_error(self): 34 | Group.get(students=[]) 35 | 36 | @db_session 37 | def test_collection_create_one2many_1(self): 38 | g = Group['3132'] 39 | g.students.create(record=106, name='Mike', scholarship=200) 40 | flush() 41 | self.assertEqual(len(g.students), 3) 42 | rollback() 43 | 44 | @raises_exception(TypeError, "When using Group.students.create(), " 45 | "'group' attribute should not be passed explicitly") 46 | @db_session 47 | def test_collection_create_one2many_2(self): 48 | g = Group['3132'] 49 | g.students.create(record=106, name='Mike', scholarship=200, group=g) 50 | 51 | @raises_exception(TransactionIntegrityError, "Object Student[105] cannot be stored in the database...") 52 | @db_session 53 | def test_collection_create_one2many_3(self): 54 | g = Group['3132'] 55 | g.students.create(record=105, name='Mike', scholarship=200) 56 | 57 | @db_session 58 | def test_collection_create_many2many_1(self): 59 | g = Group['3132'] 60 | g.subjects.create(name='Biology') 61 | flush() 62 | self.assertEqual(len(g.subjects), 3) 63 | rollback() 64 | 65 | @raises_exception(TypeError, "When using Group.subjects.create(), " 66 | "'groups' attribute should not be passed explicitly") 67 | @db_session 68 | def test_collection_create_many2many_2(self): 69 | g = Group['3132'] 70 | g.subjects.create(name='Biology', groups=[g]) 71 | 72 | @raises_exception(TransactionIntegrityError, "Object Subject['Math'] cannot be stored in the database...") 73 | @db_session 74 | def test_collection_create_many2many_3(self): 75 | g = Group['3132'] 76 | g.subjects.create(name='Math') 77 | 78 | # replace collection items when the old ones are not fully loaded 79 | ##>>> from pony.examples.orm.students01.model import * 80 | ##>>> s1 = Student[101] 81 | ##>>> g = s1.group 82 | ##>>> g.__dict__[Group.students].is_fully_loaded 83 | ##False 84 | ##>>> s2 = Student[104] 85 | ##>>> g.students = [s2] 86 | ##>>> 87 | 88 | # replace collection items when the old ones are not loaded 89 | ##>>> from pony.examples.orm.students01.model import * 90 | ##>>> g = Group[4145] 91 | ##>>> Group.students not in g.__dict__ 92 | ##True 93 | ##>>> s2 = Student[104] 94 | ##>>> g.students = [s2] 95 | 96 | 97 | if __name__ == '__main__': 98 | unittest.main() 99 | -------------------------------------------------------------------------------- /pony/orm/tests/test_conversions.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from datetime import timedelta 3 | 4 | from pony import converting 5 | 6 | class Test(unittest.TestCase): 7 | def test_timestamps_1(self): 8 | s = '1:2:3' 9 | td = converting.str2timedelta(s) 10 | self.assertEqual(td, timedelta(hours=1, minutes=2, seconds=3)) 11 | s = '01:02:03' 12 | td = converting.str2timedelta(s) 13 | self.assertEqual(td, timedelta(hours=1, minutes=2, seconds=3)) 14 | s = '1:2:3.456' 15 | td = converting.str2timedelta(s) 16 | self.assertEqual(td, timedelta(hours=1, minutes=2, seconds=3, milliseconds=456)) 17 | s = '1:2:3.45678' 18 | td = converting.str2timedelta(s) 19 | self.assertEqual(td, timedelta(hours=1, minutes=2, seconds=3, microseconds=456780)) 20 | s = '12:34:56' 21 | td = converting.str2timedelta(s) 22 | self.assertEqual(td, timedelta(hours=12, minutes=34, seconds=56)) 23 | s = '12:34:56.789' 24 | td = converting.str2timedelta(s) 25 | self.assertEqual(td, timedelta(hours=12, minutes=34, seconds=56, milliseconds=789)) 26 | s = '12:34:56.789123' 27 | td = converting.str2timedelta(s) 28 | self.assertEqual(td, timedelta(hours=12, minutes=34, seconds=56, microseconds=789123)) 29 | 30 | def test_timestamps_2(self): 31 | s = '-1:2:3' 32 | td = converting.str2timedelta(s) 33 | self.assertEqual(td, -timedelta(hours=1, minutes=2, seconds=3)) 34 | s = '-01:02:03' 35 | td = converting.str2timedelta(s) 36 | self.assertEqual(td, -timedelta(hours=1, minutes=2, seconds=3)) 37 | s = '-1:2:3.456' 38 | td = converting.str2timedelta(s) 39 | self.assertEqual(td, -timedelta(hours=1, minutes=2, seconds=3, milliseconds=456)) 40 | s = '-1:2:3.45678' 41 | td = converting.str2timedelta(s) 42 | self.assertEqual(td, -timedelta(hours=1, minutes=2, seconds=3, microseconds=456780)) 43 | s = '-12:34:56' 44 | td = converting.str2timedelta(s) 45 | self.assertEqual(td, -timedelta(hours=12, minutes=34, seconds=56)) 46 | s = '-12:34:56.789' 47 | td = converting.str2timedelta(s) 48 | self.assertEqual(td, -timedelta(hours=12, minutes=34, seconds=56, milliseconds=789)) 49 | s = '-12:34:56.789123' 50 | td = converting.str2timedelta(s) 51 | self.assertEqual(td, -timedelta(hours=12, minutes=34, seconds=56, microseconds=789123)) 52 | 53 | def test_timestamps_3(self): 54 | s = '0:1:2' 55 | td = converting.str2timedelta(s) 56 | self.assertEqual(td, timedelta(minutes=1, seconds=2)) 57 | s = '0:1:2.3456' 58 | td = converting.str2timedelta(s) 59 | self.assertEqual(td, timedelta(minutes=1, seconds=2, microseconds=345600)) 60 | 61 | def test_timestamps_4(self): 62 | s = '-0:1:2' 63 | td = converting.str2timedelta(s) 64 | self.assertEqual(td, -timedelta(minutes=1, seconds=2)) 65 | s = '-0:1:2.3456' 66 | td = converting.str2timedelta(s) 67 | self.assertEqual(td, -timedelta(minutes=1, seconds=2, microseconds=345600)) 68 | -------------------------------------------------------------------------------- /pony/orm/tests/test_core_multiset.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import pickle, unittest 4 | 5 | 6 | from pony.orm.core import * 7 | from pony.orm.tests import setup_database, teardown_database 8 | 9 | db = Database() 10 | 11 | class Department(db.Entity): 12 | number = PrimaryKey(int) 13 | groups = Set('Group') 14 | courses = Set('Course') 15 | 16 | class Group(db.Entity): 17 | number = PrimaryKey(int) 18 | department = Required(Department) 19 | students = Set('Student') 20 | 21 | class Student(db.Entity): 22 | name = Required(str) 23 | group = Required(Group) 24 | courses = Set('Course') 25 | 26 | class Course(db.Entity): 27 | name = PrimaryKey(str) 28 | department = Required(Department) 29 | students = Set('Student') 30 | 31 | 32 | class TestMultiset(unittest.TestCase): 33 | 34 | @classmethod 35 | def setUpClass(cls): 36 | setup_database(db) 37 | 38 | with db_session: 39 | d1 = Department(number=1) 40 | d2 = Department(number=2) 41 | d3 = Department(number=3) 42 | 43 | g1 = Group(number=101, department=d1) 44 | g2 = Group(number=102, department=d1) 45 | g3 = Group(number=201, department=d2) 46 | 47 | c1 = Course(name='C1', department=d1) 48 | c2 = Course(name='C2', department=d1) 49 | c3 = Course(name='C3', department=d2) 50 | c4 = Course(name='C4', department=d2) 51 | c5 = Course(name='C5', department=d3) 52 | 53 | s1 = Student(name='S1', group=g1, courses=[c1, c2]) 54 | s2 = Student(name='S2', group=g1, courses=[c1, c3]) 55 | s3 = Student(name='S3', group=g1, courses=[c2, c3]) 56 | 57 | s4 = Student(name='S4', group=g2, courses=[c1, c2]) 58 | s5 = Student(name='S5', group=g2, courses=[c1, c2]) 59 | 60 | s6 = Student(name='A', group=g3, courses=[c5]) 61 | 62 | @classmethod 63 | def tearDownClass(cls): 64 | teardown_database(db) 65 | 66 | @db_session 67 | def test_multiset_repr_1(self): 68 | d = Department[1] 69 | multiset = d.groups.students 70 | self.assertEqual(repr(multiset), "") 71 | 72 | @db_session 73 | def test_multiset_repr_2(self): 74 | g = Group[101] 75 | multiset = g.students.courses 76 | self.assertEqual(repr(multiset), "") 77 | 78 | @db_session 79 | def test_multiset_repr_3(self): 80 | g = Group[201] 81 | multiset = g.students.courses 82 | self.assertEqual(repr(multiset), "") 83 | 84 | def test_multiset_repr_4(self): 85 | with db_session: 86 | g = Group[101] 87 | multiset = g.students.courses 88 | self.assertIsNone(multiset._obj_._session_cache_) 89 | self.assertEqual(repr(multiset), "") 90 | 91 | @db_session 92 | def test_multiset_str(self): 93 | g = Group[101] 94 | multiset = g.students.courses 95 | self.assertEqual(str(multiset), "CourseMultiset({Course[%r]: 2, Course[%r]: 2, Course[%r]: 2})" 96 | % (u'C1', u'C2', u'C3')) 97 | 98 | @db_session 99 | def test_multiset_distinct(self): 100 | d = Department[1] 101 | multiset = d.groups.students.courses 102 | self.assertEqual(multiset.distinct(), {Course['C1']: 4, Course['C2']: 4, Course['C3']: 2}) 103 | 104 | @db_session 105 | def test_multiset_nonzero(self): 106 | d = Department[1] 107 | multiset = d.groups.students 108 | self.assertEqual(bool(multiset), True) 109 | 110 | @db_session 111 | def test_multiset_len(self): 112 | d = Department[1] 113 | multiset = d.groups.students.courses 114 | self.assertEqual(len(multiset), 10) 115 | 116 | @db_session 117 | def test_multiset_eq(self): 118 | d = Department[1] 119 | multiset = d.groups.students.courses 120 | c1, c2, c3 = Course['C1'], Course['C2'], Course['C3'] 121 | self.assertEqual(multiset, multiset) 122 | self.assertEqual(multiset, {c1: 4, c2: 4, c3: 2}) 123 | self.assertEqual(multiset, [ c1, c1, c1, c2, c2, c2, c2, c3, c3, c1 ]) 124 | 125 | @db_session 126 | def test_multiset_ne(self): 127 | d = Department[1] 128 | multiset = d.groups.students.courses 129 | self.assertFalse(multiset != multiset) 130 | 131 | @db_session 132 | def test_multiset_contains(self): 133 | d = Department[1] 134 | multiset = d.groups.students.courses 135 | self.assertTrue(Course['C1'] in multiset) 136 | self.assertFalse(Course['C5'] in multiset) 137 | 138 | def test_multiset_reduce(self): 139 | with db_session: 140 | d = Department[1] 141 | multiset = d.groups.students 142 | s = pickle.dumps(multiset) 143 | with db_session: 144 | d = Department[1] 145 | multiset_2 = d.groups.students 146 | multiset_1 = pickle.loads(s) 147 | self.assertEqual(multiset_1, multiset_2) 148 | 149 | 150 | if __name__ == '__main__': 151 | unittest.main() 152 | -------------------------------------------------------------------------------- /pony/orm/tests/test_crud_raw_sql.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | 5 | from pony.orm.core import * 6 | from pony.orm.tests.testutils import raises_exception 7 | from pony.orm.tests import setup_database, teardown_database, only_for 8 | 9 | db = Database() 10 | 11 | class Student(db.Entity): 12 | name = Required(str) 13 | age = Optional(int) 14 | friends = Set("Student", reverse='friends') 15 | group = Required("Group") 16 | bio = Optional("Bio") 17 | 18 | class Group(db.Entity): 19 | dept = Required(int) 20 | grad_year = Required(int) 21 | students = Set(Student) 22 | PrimaryKey(dept, grad_year) 23 | 24 | class Bio(db.Entity): 25 | picture = Optional(buffer) 26 | desc = Required(str) 27 | Student = Required(Student) 28 | 29 | 30 | @only_for('sqlite') 31 | class TestCrudRawSQL(unittest.TestCase): 32 | @classmethod 33 | def setUpClass(cls): 34 | setup_database(db) 35 | 36 | @classmethod 37 | def tearDownClass(cls): 38 | teardown_database(db) 39 | 40 | def setUp(self): 41 | with db_session: 42 | db.execute('delete from Student') 43 | db.execute('delete from "Group"') 44 | db.insert(Group, dept=44, grad_year=1999) 45 | db.insert(Student, id=1, name='A', age=30, group_dept=44, group_grad_year=1999) 46 | db.insert(Student, id=2, name='B', age=25, group_dept=44, group_grad_year=1999) 47 | db.insert(Student, id=3, name='C', age=20, group_dept=44, group_grad_year=1999) 48 | rollback() 49 | db_session.__enter__() 50 | 51 | def tearDown(self): 52 | rollback() 53 | db_session.__exit__() 54 | 55 | def test1(self): 56 | students = set(Student.select_by_sql("select id, name, age, group_dept, group_grad_year from Student order by age")) 57 | self.assertEqual(students, {Student[3], Student[2], Student[1]}) 58 | 59 | def test2(self): 60 | students = set(Student.select_by_sql("select id, age, group_dept from Student order by age")) 61 | self.assertEqual(students, {Student[3], Student[2], Student[1]}) 62 | 63 | @raises_exception(NameError, "Column x does not belong to entity Student") 64 | def test3(self): 65 | students = set(Student.select_by_sql("select id, age, age*2 as x from Student order by age")) 66 | self.assertEqual(students, {Student[3], Student[2], Student[1]}) 67 | 68 | @raises_exception(TypeError, 'The first positional argument must be lambda function or its text source. Got: 123') 69 | def test4(self): 70 | students = Student.select(123) 71 | 72 | def test5(self): 73 | x = 1 74 | y = 30 75 | cursor = db.execute("select name from Student where id = $x and age = $y") 76 | self.assertEqual(cursor.fetchone()[0], 'A') 77 | 78 | def test6(self): 79 | x = 1 80 | y = 30 81 | cursor = db.execute("select name, 'abc$$def%' from Student where id = $x and age = $y") 82 | self.assertEqual(cursor.fetchone(), ('A', 'abc$def%')) 83 | 84 | def test7(self): 85 | cursor = db.execute("select name, 'abc$$def%' from Student where id = 1") 86 | self.assertEqual(cursor.fetchone(), ('A', 'abc$def%')) 87 | 88 | 89 | if __name__ == '__main__': 90 | unittest.main() 91 | -------------------------------------------------------------------------------- /pony/orm/tests/test_datetime.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | from datetime import date, datetime, timedelta 5 | 6 | from pony.orm.core import * 7 | from pony.orm.tests.testutils import * 8 | from pony.orm.tests import setup_database, teardown_database 9 | 10 | db = Database() 11 | 12 | 13 | class Entity1(db.Entity): 14 | id = PrimaryKey(int) 15 | d = Required(date) 16 | dt = Required(datetime) 17 | 18 | 19 | class TestDate(unittest.TestCase): 20 | @classmethod 21 | def setUpClass(cls): 22 | setup_database(db) 23 | with db_session: 24 | Entity1(id=1, d=date(2009, 10, 20), dt=datetime(2009, 10, 20, 10, 20, 30)) 25 | Entity1(id=2, d=date(2010, 10, 21), dt=datetime(2010, 10, 21, 10, 21, 31)) 26 | Entity1(id=3, d=date(2011, 11, 22), dt=datetime(2011, 11, 22, 10, 20, 32)) 27 | 28 | @classmethod 29 | def tearDownClass(cls): 30 | teardown_database(db) 31 | 32 | def setUp(self): 33 | rollback() 34 | db_session.__enter__() 35 | 36 | def tearDown(self): 37 | rollback() 38 | db_session.__exit__() 39 | 40 | def test_create(self): 41 | e1 = Entity1(id=4, d=date(2011, 10, 20), dt=datetime(2009, 10, 20, 10, 20, 30)) 42 | 43 | def test_date_year(self): 44 | result = select(e for e in Entity1 if e.d.year > 2009) 45 | self.assertEqual(len(result), 2) 46 | 47 | def test_date_month(self): 48 | result = select(e for e in Entity1 if e.d.month == 10) 49 | self.assertEqual(len(result), 2) 50 | 51 | def test_date_day(self): 52 | result = select(e for e in Entity1 if e.d.day == 22) 53 | self.assertEqual(len(result), 1) 54 | 55 | def test_datetime_year(self): 56 | result = select(e for e in Entity1 if e.dt.year > 2009) 57 | self.assertEqual(len(result), 2) 58 | 59 | def test_datetime_month(self): 60 | result = select(e for e in Entity1 if e.dt.month == 10) 61 | self.assertEqual(len(result), 2) 62 | 63 | def test_datetime_day(self): 64 | result = select(e for e in Entity1 if e.dt.day == 22) 65 | self.assertEqual(len(result), 1) 66 | 67 | def test_datetime_hour(self): 68 | result = select(e for e in Entity1 if e.dt.hour == 10) 69 | self.assertEqual(len(result), 3) 70 | 71 | def test_datetime_minute(self): 72 | result = select(e for e in Entity1 if e.dt.minute == 20) 73 | self.assertEqual(len(result), 2) 74 | 75 | def test_datetime_second(self): 76 | result = select(e for e in Entity1 if e.dt.second == 30) 77 | self.assertEqual(len(result), 1) 78 | 79 | def test_date_sub_date(self): 80 | dt = date(2012, 1, 1) 81 | result = select(e.id for e in Entity1 if dt - e.d > timedelta(days=500)) 82 | self.assertEqual(set(result), {1}) 83 | 84 | def test_datetime_sub_datetime(self): 85 | dt = datetime(2012, 1, 1, 10, 20, 30) 86 | result = select(e.id for e in Entity1 if dt - e.dt > timedelta(days=500)) 87 | self.assertEqual(set(result), {1}) 88 | 89 | def test_date_sub_timedelta_param(self): 90 | td = timedelta(days=500) 91 | result = select(e.id for e in Entity1 if e.d - td < date(2009, 1, 1)) 92 | self.assertEqual(set(result), {1}) 93 | 94 | def test_date_sub_const_timedelta(self): 95 | result = select(e.id for e in Entity1 if e.d - timedelta(days=500) < date(2009, 1, 1)) 96 | self.assertEqual(set(result), {1}) 97 | 98 | def test_datetime_sub_timedelta_param(self): 99 | td = timedelta(days=500) 100 | result = select(e.id for e in Entity1 if e.dt - td < datetime(2009, 1, 1, 10, 20, 30)) 101 | self.assertEqual(set(result), {1}) 102 | 103 | def test_datetime_sub_const_timedelta(self): 104 | result = select(e.id for e in Entity1 if e.dt - timedelta(days=500) < datetime(2009, 1, 1, 10, 20, 30)) 105 | self.assertEqual(set(result), {1}) 106 | 107 | def test_date_add_timedelta_param(self): 108 | td = timedelta(days=500) 109 | result = select(e.id for e in Entity1 if e.d + td > date(2013, 1, 1)) 110 | self.assertEqual(set(result), {3}) 111 | 112 | def test_date_add_const_timedelta(self): 113 | result = select(e.id for e in Entity1 if e.d + timedelta(days=500) > date(2013, 1, 1)) 114 | self.assertEqual(set(result), {3}) 115 | 116 | def test_datetime_add_timedelta_param(self): 117 | td = timedelta(days=500) 118 | result = select(e.id for e in Entity1 if e.dt + td > date(2013, 1, 1)) 119 | self.assertEqual(set(result), {3}) 120 | 121 | def test_datetime_add_const_timedelta(self): 122 | result = select(e.id for e in Entity1 if e.dt + timedelta(days=500) > date(2013, 1, 1)) 123 | self.assertEqual(set(result), {3}) 124 | 125 | @raises_exception(TypeError, "Unsupported operand types 'date' and 'str' for operation '-' in expression: e.d - s") 126 | def test_date_sub_error(self): 127 | s = 'hello' 128 | result = select(e.id for e in Entity1 if e.d - s > timedelta(days=500)) 129 | self.assertEqual(set(result), {1}) 130 | 131 | @raises_exception(TypeError, 132 | "Unsupported operand types 'datetime' and 'str' for operation '-' in expression: e.dt - s") 133 | def test_datetime_sub_error(self): 134 | s = 'hello' 135 | result = select(e.id for e in Entity1 if e.dt - s > timedelta(days=500)) 136 | self.assertEqual(set(result), {1}) 137 | 138 | 139 | if __name__ == '__main__': 140 | unittest.main() 141 | -------------------------------------------------------------------------------- /pony/orm/tests/test_declarative_join_optimization.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | from datetime import date 5 | 6 | from pony.orm.core import * 7 | from pony.orm.tests.testutils import * 8 | from pony.orm.tests import setup_database, teardown_database 9 | 10 | db = Database() 11 | 12 | class Department(db.Entity): 13 | name = Required(str) 14 | groups = Set('Group') 15 | courses = Set('Course') 16 | 17 | class Group(db.Entity): 18 | number = PrimaryKey(int) 19 | dept = Required(Department) 20 | major = Required(str) 21 | students = Set("Student") 22 | 23 | class Course(db.Entity): 24 | name = Required(str) 25 | dept = Required(Department) 26 | semester = Required(int) 27 | credits = Required(int) 28 | students = Set("Student") 29 | PrimaryKey(name, semester) 30 | 31 | class Student(db.Entity): 32 | id = PrimaryKey(int, auto=True) 33 | name = Required(str) 34 | dob = Required(date) 35 | picture = Optional(buffer) 36 | gpa = Required(float, default=0) 37 | group = Required(Group) 38 | courses = Set(Course) 39 | 40 | 41 | class TestM2MOptimization(unittest.TestCase): 42 | @classmethod 43 | def setUpClass(cls): 44 | setup_database(db) 45 | @classmethod 46 | def tearDownClass(cls): 47 | teardown_database(db) 48 | def setUp(self): 49 | rollback() 50 | db_session.__enter__() 51 | def tearDown(self): 52 | rollback() 53 | db_session.__exit__() 54 | def test1(self): 55 | q = select(s for s in Student if len(s.courses) > 2) 56 | self.assertEqual(Course._table_ not in flatten(q._translator.conditions), True) 57 | def test2(self): 58 | q = select(s for s in Student if max(s.courses.semester) > 2) 59 | self.assertEqual(Course._table_ not in flatten(q._translator.conditions), True) 60 | # def test3(self): 61 | # q = select(s for s in Student if max(s.courses.credits) > 2) 62 | # self.assertEqual(Course._table_ in flatten(q._translator.conditions), True) 63 | # self.assertEqual(Course.students.table in flatten(q._translator.conditions), True) 64 | def test4(self): 65 | q = select(g for g in Group if sum(g.students.gpa) > 5) 66 | self.assertEqual(Group._table_ not in flatten(q._translator.conditions), True) 67 | def test5(self): 68 | q = select(s for s in Student if s.group.number == 1 or s.group.major == '1') 69 | self.assertEqual(Group._table_ in flatten(q._translator.sqlquery.from_ast), True) 70 | # def test6(self): ### Broken with ExprEvalError: Group[101] raises ObjectNotFound: Group[101] 71 | # q = select(s for s in Student if s.group == Group[101]) 72 | # self.assertEqual(Group._table_ not in flatten(q._translator.sqlquery.from_ast), True) 73 | def test7(self): 74 | q = select(s for s in Student if sum(c.credits for c in Course if s.group.dept == c.dept) > 10) 75 | objects = q[:] 76 | student_table_name = 'Student' 77 | group_table_name = 'Group' 78 | if not (db.provider.dialect == 'SQLite' and pony.__version__ < '0.9'): 79 | student_table_name = student_table_name.lower() 80 | group_table_name = group_table_name.lower() 81 | self.assertEqual(q._translator.sqlquery.from_ast, [ 82 | 'FROM', ['s', 'TABLE', student_table_name], 83 | ['group', 'TABLE', group_table_name, 84 | ['EQ', ['COLUMN', 's', 'group'], ['COLUMN', 'group', 'number']] 85 | ] 86 | ]) 87 | 88 | 89 | if __name__ == '__main__': 90 | unittest.main() 91 | -------------------------------------------------------------------------------- /pony/orm/tests/test_declarative_object_flat_monad.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | from pony.orm.core import * 5 | from pony.orm.tests import setup_database, teardown_database 6 | 7 | db = Database() 8 | 9 | class Student(db.Entity): 10 | name = Required(str) 11 | scholarship = Optional(int) 12 | group = Required("Group") 13 | marks = Set("Mark") 14 | 15 | class Group(db.Entity): 16 | number = PrimaryKey(int) 17 | department = Required(int) 18 | students = Set(Student) 19 | subjects = Set("Subject") 20 | 21 | class Subject(db.Entity): 22 | name = PrimaryKey(str) 23 | groups = Set(Group) 24 | marks = Set("Mark") 25 | 26 | class Mark(db.Entity): 27 | value = Required(int) 28 | student = Required(Student) 29 | subject = Required(Subject) 30 | PrimaryKey(student, subject) 31 | 32 | 33 | class TestObjectFlatMonad(unittest.TestCase): 34 | @classmethod 35 | def setUpClass(self): 36 | setup_database(db) 37 | with db_session: 38 | Math = Subject(name="Math") 39 | Physics = Subject(name="Physics") 40 | History = Subject(name="History") 41 | 42 | g41 = Group(number=41, department=101, subjects=[Math, Physics, History]) 43 | g42 = Group(number=42, department=102, subjects=[Math, Physics]) 44 | g43 = Group(number=43, department=102, subjects=[Physics]) 45 | 46 | s1 = Student(id=1, name="Joe", scholarship=None, group=g41) 47 | s2 = Student(id=2, name="Bob", scholarship=100, group=g41) 48 | s3 = Student(id=3, name="Beth", scholarship=500, group=g41) 49 | s4 = Student(id=4, name="Jon", scholarship=500, group=g42) 50 | s5 = Student(id=5, name="Pete", scholarship=700, group=g42) 51 | 52 | Mark(value=5, student=s1, subject=Math) 53 | Mark(value=4, student=s2, subject=Physics) 54 | Mark(value=3, student=s2, subject=Math) 55 | Mark(value=2, student=s2, subject=History) 56 | Mark(value=1, student=s3, subject=History) 57 | Mark(value=2, student=s3, subject=Math) 58 | Mark(value=2, student=s4, subject=Math) 59 | 60 | @classmethod 61 | def tearDownClass(cls): 62 | teardown_database(db) 63 | 64 | @db_session 65 | def test1(self): 66 | result = set(select(s.groups for s in Subject if len(s.name) == 4)) 67 | self.assertEqual(result, {Group[41], Group[42]}) 68 | 69 | @db_session 70 | def test2(self): 71 | result = set(select(g.students for g in Group if g.department == 102)) 72 | self.assertEqual(result, {Student[5], Student[4]}) 73 | 74 | if __name__ == '__main__': 75 | unittest.main() 76 | -------------------------------------------------------------------------------- /pony/orm/tests/test_deduplication.py: -------------------------------------------------------------------------------- 1 | from io import StringIO 2 | 3 | from pony.orm import * 4 | from pony.orm.tests import setup_database, teardown_database 5 | 6 | import unittest 7 | 8 | db = Database() 9 | 10 | class A(db.Entity): 11 | id = PrimaryKey(int) 12 | x = Required(bool) 13 | y = Required(float) 14 | 15 | 16 | class TestDeduplication(unittest.TestCase): 17 | @classmethod 18 | def setUpClass(cls): 19 | setup_database(db) 20 | with db_session: 21 | a1 = A(id=1, x=False, y=3.0) 22 | a2 = A(id=2, x=True, y=4.0) 23 | a3 = A(id=3, x=False, y=1.0) 24 | 25 | @classmethod 26 | def tearDownClass(cls): 27 | teardown_database(db) 28 | 29 | @db_session 30 | def test_1(self): 31 | a2 = A.get(id=2) 32 | a1 = A.get(id=1) 33 | self.assertIs(a1.id, 1) 34 | 35 | @db_session 36 | def test_2(self): 37 | a3 = A.get(id=3) 38 | a1 = A.get(id=1) 39 | self.assertIs(a1.id, 1) 40 | 41 | @db_session 42 | def test_3(self): 43 | q = A.select().order_by(-1) 44 | stream = StringIO() 45 | q.show(stream=stream) 46 | s = stream.getvalue() 47 | self.assertEqual(s, 'id|x |y \n' 48 | '--+-----+---\n' 49 | '3 |False|1.0\n' 50 | '2 |True |4.0\n' 51 | '1 |False|3.0\n') 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /pony/orm/tests/test_distinct.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | 5 | from pony.orm.core import * 6 | from pony.orm.tests.testutils import * 7 | from pony.orm.tests import setup_database, teardown_database 8 | 9 | db = Database() 10 | 11 | class Department(db.Entity): 12 | number = PrimaryKey(int) 13 | groups = Set('Group') 14 | 15 | class Group(db.Entity): 16 | id = PrimaryKey(int) 17 | dept = Required('Department') 18 | students = Set('Student') 19 | 20 | class Student(db.Entity): 21 | name = Required(str) 22 | age = Required(int) 23 | group = Required('Group') 24 | scholarship = Required(int, default=0) 25 | courses = Set('Course') 26 | 27 | class Course(db.Entity): 28 | name = Required(str) 29 | semester = Required(int) 30 | PrimaryKey(name, semester) 31 | students = Set('Student') 32 | 33 | 34 | class TestDistinct(unittest.TestCase): 35 | @classmethod 36 | def setUpClass(cls): 37 | setup_database(db) 38 | with db_session: 39 | d1 = Department(number=1) 40 | d2 = Department(number=2) 41 | g1 = Group(id=1, dept=d1) 42 | g2 = Group(id=2, dept=d2) 43 | s1 = Student(id=1, name='S1', age=20, group=g1, scholarship=0) 44 | s2 = Student(id=2, name='S2', age=21, group=g1, scholarship=100) 45 | s3 = Student(id=3, name='S3', age=23, group=g1, scholarship=200) 46 | s4 = Student(id=4, name='S4', age=21, group=g1, scholarship=100) 47 | s5 = Student(id=5, name='S5', age=23, group=g2, scholarship=0) 48 | s6 = Student(id=6, name='S6', age=23, group=g2, scholarship=200) 49 | c1 = Course(name='C1', semester=1, students=[s1, s2, s3]) 50 | c2 = Course(name='C2', semester=1, students=[s2, s3, s5, s6]) 51 | c3 = Course(name='C3', semester=2, students=[s4, s5, s6]) 52 | 53 | @classmethod 54 | def tearDownClass(cls): 55 | teardown_database(db) 56 | 57 | def setUp(self): 58 | db_session.__enter__() 59 | 60 | def tearDown(self): 61 | db_session.__exit__() 62 | 63 | def test_group_by(self): 64 | result = set(select((s.age, sum(s.scholarship)) for s in Student if s.scholarship > 0)) 65 | self.assertEqual(result, {(21, 200), (23, 400)}) 66 | self.assertNotIn('distinct', db.last_sql.lower()) 67 | 68 | def test_group_by_having(self): 69 | result = set(select((s.age, sum(s.scholarship)) for s in Student if sum(s.scholarship) < 300)) 70 | self.assertEqual(result, {(20, 0), (21, 200)}) 71 | self.assertNotIn('distinct', db.last_sql.lower()) 72 | 73 | def test_aggregation_no_group_by_1(self): 74 | result = set(select(sum(s.scholarship) for s in Student if s.age < 23)) 75 | self.assertEqual(result, {200}) 76 | self.assertNotIn('distinct', db.last_sql.lower()) 77 | 78 | def test_aggregation_no_group_by_2(self): 79 | result = set(select((sum(s.scholarship), min(s.scholarship)) for s in Student if s.age < 23)) 80 | self.assertEqual(result, {(200, 0)}) 81 | self.assertNotIn('distinct', db.last_sql.lower()) 82 | 83 | def test_aggregation_no_group_by_3(self): 84 | result = set(select((sum(s.scholarship), min(s.scholarship)) 85 | for s in Student for g in Group 86 | if s.group == g and g.dept.number == 1)) 87 | self.assertEqual(result, {(400, 0)}) 88 | self.assertNotIn('distinct', db.last_sql.lower()) 89 | 90 | 91 | if __name__ == "__main__": 92 | unittest.main() 93 | -------------------------------------------------------------------------------- /pony/orm/tests/test_entity_init.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | from datetime import date, datetime 5 | from hashlib import md5 6 | 7 | from pony.orm.tests.testutils import raises_exception 8 | from pony.orm import * 9 | from pony.orm.tests import setup_database, teardown_database 10 | 11 | db = Database() 12 | 13 | 14 | class User(db.Entity): 15 | name = Required(str) 16 | password = Required(str) 17 | created_at = Required(datetime) 18 | 19 | def __init__(self, name, password): 20 | password = md5(password.encode('utf8')).hexdigest() 21 | super(User, self).__init__(name=name, password=password, created_at=datetime.now()) 22 | self.uppercase_name = name.upper() 23 | 24 | 25 | class TestCustomInit(unittest.TestCase): 26 | @classmethod 27 | def setUpClass(cls): 28 | setup_database(db) 29 | 30 | @classmethod 31 | def tearDownClass(self): 32 | teardown_database(db) 33 | 34 | def test1(self): 35 | with db_session: 36 | u1 = User('John', '123') 37 | u2 = User('Mike', '456') 38 | commit() 39 | self.assertEqual(u1.name, 'John') 40 | self.assertEqual(u1.uppercase_name, 'JOHN') 41 | self.assertEqual(u1.password, md5(b'123').hexdigest()) 42 | self.assertEqual(u2.name, 'Mike') 43 | self.assertEqual(u2.uppercase_name, 'MIKE') 44 | self.assertEqual(u2.password, md5(b'456').hexdigest()) 45 | 46 | with db_session: 47 | users = select(u for u in User).order_by(User.id) 48 | self.assertEqual(len(users), 2) 49 | u1, u2 = users 50 | self.assertEqual(u1.name, 'John') 51 | self.assertTrue(not hasattr(u1, 'uppercase_name')) 52 | self.assertEqual(u1.password, md5(b'123').hexdigest()) 53 | self.assertEqual(u2.name, 'Mike') 54 | self.assertTrue(not hasattr(u2, 'uppercase_name')) 55 | self.assertEqual(u2.password, md5(b'456').hexdigest()) 56 | 57 | if __name__ == '__main__': 58 | unittest.main() -------------------------------------------------------------------------------- /pony/orm/tests/test_entity_proxy.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pony.orm import * 4 | from pony.orm.tests.testutils import * 5 | from pony.orm.tests import setup_database, teardown_database 6 | 7 | db = Database() 8 | 9 | class Country(db.Entity): 10 | id = PrimaryKey(int) 11 | name = Required(str) 12 | persons = Set("Person") 13 | 14 | class Person(db.Entity): 15 | id = PrimaryKey(int) 16 | name = Required(str) 17 | country = Required(Country) 18 | 19 | class TestProxy(unittest.TestCase): 20 | def setUp(self): 21 | setup_database(db) 22 | with db_session: 23 | c1 = Country(id=1, name='Russia') 24 | c2 = Country(id=2, name='Japan') 25 | Person(id=1, name='Alexander Nevskiy', country=c1) 26 | Person(id=2, name='Raikou Minamoto', country=c2) 27 | Person(id=3, name='Ibaraki Douji', country=c2) 28 | 29 | def tearDown(self): 30 | teardown_database(db) 31 | 32 | def test_1(self): 33 | with db_session: 34 | p = make_proxy(Person[2]) 35 | 36 | with db_session: 37 | x1 = db.local_stats[None].db_count # number of queries 38 | # it is possible to access p attributes in a new db_session 39 | name = p.name 40 | country = p.country 41 | x2 = db.local_stats[None].db_count 42 | 43 | # p.name and p.country are loaded with a single query 44 | self.assertEqual(x1, x2-1) 45 | 46 | def test_2(self): 47 | with db_session: 48 | p = make_proxy(Person[2]) 49 | name = p.name 50 | country = p.country 51 | 52 | with db_session: 53 | x1 = db.local_stats[None].db_count 54 | name = p.name 55 | country = p.country 56 | x2 = db.local_stats[None].db_count 57 | 58 | # attribute values from the first db_session should be ignored and loaded again 59 | self.assertEqual(x1, x2-1) 60 | 61 | def test_3(self): 62 | with db_session: 63 | p = Person[2] 64 | proxy = make_proxy(p) 65 | 66 | with db_session: 67 | p2 = Person[2] 68 | name1 = 'Tamamo no Mae' 69 | # It is possible to assign new attribute values to a proxy object 70 | p2.name = name1 71 | name2 = proxy.name 72 | 73 | self.assertEqual(name1, name2) 74 | 75 | 76 | def test_4(self): 77 | with db_session: 78 | p = Person[2] 79 | proxy = make_proxy(p) 80 | 81 | with db_session: 82 | p2 = Person[2] 83 | name1 = 'Tamamo no Mae' 84 | p2.name = name1 85 | 86 | with db_session: 87 | # new attribute value was successfully stored in the database 88 | name2 = proxy.name 89 | 90 | self.assertEqual(name1, name2) 91 | 92 | def test_5(self): 93 | with db_session: 94 | p = Person[2] 95 | r = repr(p) 96 | self.assertEqual(r, 'Person[2]') 97 | 98 | proxy = make_proxy(p) 99 | r = repr(proxy) 100 | # proxy object has specific repr 101 | self.assertEqual(r, '') 102 | 103 | r = repr(proxy) 104 | # repr of proxy object can be used outside of db_session 105 | self.assertEqual(r, '') 106 | 107 | del p 108 | r = repr(proxy) 109 | # repr works even if the original object was deleted 110 | self.assertEqual(r, '') 111 | 112 | 113 | def test_6(self): 114 | with db_session: 115 | p = Person[2] 116 | proxy = make_proxy(p) 117 | proxy.name = 'Okita Souji' 118 | # after assignment, the attribute value is the same for the proxy and for the original object 119 | self.assertEqual(proxy.name, 'Okita Souji') 120 | self.assertEqual(p.name, 'Okita Souji') 121 | 122 | 123 | def test_7(self): 124 | with db_session: 125 | p = Person[2] 126 | proxy = make_proxy(p) 127 | proxy.name = 'Okita Souji' 128 | # after assignment, the attribute value is the same for the proxy and for the original object 129 | self.assertEqual(proxy.name, 'Okita Souji') 130 | self.assertEqual(p.name, 'Okita Souji') 131 | 132 | 133 | def test_8(self): 134 | with db_session: 135 | c1 = Country[1] 136 | c1_proxy = make_proxy(c1) 137 | p2 = Person[2] 138 | self.assertNotEqual(p2.country, c1) 139 | self.assertNotEqual(p2.country, c1_proxy) 140 | # proxy can be used in attribute assignment 141 | p2.country = c1_proxy 142 | self.assertEqual(p2.country, c1_proxy) 143 | self.assertIs(p2.country, c1) 144 | 145 | 146 | def test_9(self): 147 | with db_session: 148 | c2 = Country[2] 149 | c2_proxy = make_proxy(c2) 150 | persons = select(p for p in Person if p.country == c2_proxy) 151 | self.assertEqual({p.id for p in persons}, {2, 3}) 152 | 153 | if __name__ == '__main__': 154 | unittest.main() 155 | -------------------------------------------------------------------------------- /pony/orm/tests/test_exists.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pony.orm.core import * 4 | from pony.orm.tests.testutils import * 5 | from pony.orm.tests import setup_database, teardown_database 6 | 7 | db = Database() 8 | 9 | class Group(db.Entity): 10 | students = Set('Student') 11 | 12 | class Student(db.Entity): 13 | first_name = Required(str) 14 | last_name = Required(str) 15 | login = Optional(str, nullable=True) 16 | graduated = Optional(bool, default=False) 17 | group = Required(Group) 18 | passport = Optional('Passport', column='passport') 19 | 20 | class Passport(db.Entity): 21 | student = Optional(Student) 22 | 23 | 24 | class TestExists(unittest.TestCase): 25 | @classmethod 26 | def setUpClass(cls): 27 | setup_database(db) 28 | with db_session: 29 | g1 = Group(id=1) 30 | g2 = Group(id=2) 31 | 32 | p = Passport(id=1) 33 | 34 | Student(id=1, first_name='Mashu', last_name='Kyrielight', login='Shielder', group=g1) 35 | Student(id=2, first_name='Okita', last_name='Souji', login='Sakura', group=g1) 36 | Student(id=3, first_name='Francis', last_name='Drake', group=g2, graduated=True) 37 | Student(id=4, first_name='Oda', last_name='Nobunaga', group=g2, graduated=True) 38 | Student(id=5, first_name='William', last_name='Shakespeare', group=g2, graduated=True, passport=p) 39 | 40 | @classmethod 41 | def tearDownClass(cls): 42 | teardown_database(db) 43 | 44 | def setUp(self): 45 | rollback() 46 | db_session.__enter__() 47 | 48 | def tearDown(self): 49 | rollback() 50 | db_session.__exit__() 51 | 52 | def test_1(self): 53 | q = select(g for g in Group if exists(s.login for s in g.students))[:] 54 | self.assertEqual(q[0], Group[1]) 55 | 56 | def test_2(self): 57 | q = select(g for g in Group if exists(s.graduated for s in g.students))[:] 58 | self.assertEqual(q[0], Group[2]) 59 | 60 | def test_3(self): 61 | q = select(s for s in Student if 62 | exists(len(s2.first_name) == len(s.first_name) and s != s2 for s2 in Student))[:] 63 | self.assertEqual(set(q), {Student[1], Student[2], Student[3], Student[5]}) 64 | 65 | def test_4(self): 66 | q = select(g for g in Group if not exists(not s.graduated for s in g.students))[:] 67 | self.assertEqual(q[0], Group[2]) 68 | 69 | def test_5(self): 70 | q = select(g for g in Group if exists(s for s in g.students))[:] 71 | self.assertEqual(set(q), {Group[1], Group[2]}) 72 | 73 | def test_6(self): 74 | q = select(g for g in Group if exists(s.login for s in g.students if s.first_name != 'Okita') and g.id != 10)[:] 75 | self.assertEqual(q[0], Group[1]) 76 | 77 | def test_7(self): 78 | q = select(g for g in Group if exists(s.passport for s in g.students))[:] 79 | self.assertEqual(q[0], Group[2]) -------------------------------------------------------------------------------- /pony/orm/tests/test_f_strings.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from pony.orm.core import * 3 | from pony.orm.tests.testutils import * 4 | from pony.orm.tests import setup_database, teardown_database 5 | 6 | 7 | db = Database() 8 | 9 | class Person(db.Entity): 10 | first_name = Required(str) 11 | last_name = Required(str) 12 | age = Optional(int) 13 | value = Required(float) 14 | 15 | 16 | class TestFString(unittest.TestCase): 17 | @classmethod 18 | def setUpClass(cls): 19 | setup_database(db) 20 | with db_session: 21 | Person(id=1, first_name='Alexander', last_name='Tischenko', age=23, value=1.4) 22 | Person(id=2, first_name='Alexander', last_name='Kozlovskiy', age=42, value=1.2) 23 | Person(id=3, first_name='Arthur', last_name='Pendragon', age=54, value=1.33) 24 | Person(id=4, first_name='Okita', last_name='Souji', age=15, value=2.1) 25 | Person(id=5, first_name='Musashi', last_name='Miyamoto', age=None, value=0.9) 26 | Person(id=6, first_name='Jeanne', last_name="d'Arc", age=30, value=43.212) 27 | 28 | @classmethod 29 | def tearDownClass(cls): 30 | teardown_database(db) 31 | 32 | def setUp(self): 33 | rollback() 34 | db_session.__enter__() 35 | def tearDown(self): 36 | rollback() 37 | db_session.__exit__() 38 | 39 | def test_1(self): 40 | x = 'Alexander' 41 | y = 'Tischenko' 42 | 43 | q = select(p.id for p in Person if p.first_name + ' ' + p.last_name == f'{x} {y}') 44 | self.assertEqual(set(q), {1}) 45 | 46 | q2 = select("""p.id for p in Person if p.first_name + ' ' + p.last_name == f'{x} {y}'""") 47 | self.assertEqual(set(q2), {1}) 48 | 49 | def test_2(self): 50 | q = select(p.id for p in Person if f'{p.first_name} {p.last_name}' == 'Alexander Tischenko') 51 | self.assertEqual(set(q), {1}) 52 | 53 | q2 = select("""p.id for p in Person if f'{p.first_name} {p.last_name}' == 'Alexander Tischenko'""") 54 | self.assertEqual(set(q2), {1}) 55 | 56 | def test_3(self): 57 | x = 'Great' 58 | 59 | q = select(f'{p.first_name!s} the {x}' for p in Person if p.id == 1) 60 | self.assertEqual(set(q), {'Alexander the Great'}) 61 | 62 | q2 = select("""f'{p.first_name!s} the {x}' for p in Person if p.id == 1""") 63 | self.assertEqual(set(q2), {'Alexander the Great'}) 64 | 65 | def test_4(self): 66 | q = select(f'{p.first_name} {p.age}' for p in Person if p.id == 1) 67 | self.assertEqual(set(q), {'Alexander 23'}) 68 | 69 | q2 = select("""f'{p.first_name} {p.age}' for p in Person if p.id == 1""") 70 | self.assertEqual(set(q2), {'Alexander 23'}) 71 | 72 | def test_5(self): 73 | q = select(f'{p.first_name} {p.age}' for p in Person if p.id == 1) 74 | self.assertEqual(set(q), {'Alexander 23'}) 75 | 76 | q2 = select("""f'{p.first_name} {p.age}' for p in Person if p.id == 1""") 77 | self.assertEqual(set(q2), {'Alexander 23'}) 78 | 79 | @raises_exception(NotImplementedError, 'You cannot set width and precision for f-string expression in query') 80 | def test_6a(self): 81 | width = 3 82 | precision = 4 83 | q = select(p.id for p in Person if f'{p.value:{width}.{precision}}')[:] 84 | 85 | @raises_exception(NotImplementedError, 'You cannot set width and precision for f-string expression in query') 86 | def test_6b(self): 87 | width = 3 88 | precision = 4 89 | q = select("""p.id for p in Person if f'{p.value:{width}.{precision}}'""")[:] 90 | q.show() 91 | 92 | @raises_exception(NotImplementedError, 'You cannot specify conversion type for f-string expression in query') 93 | def test_7a(self): 94 | width = 3 95 | precision = 4 96 | q = select(p.id for p in Person if f'{p.value!r}')[:] 97 | 98 | @raises_exception(NotImplementedError, 'You cannot specify conversion type for f-string expression in query') 99 | def test_7b(self): 100 | width = 3 101 | precision = 4 102 | q = select("""p.id for p in Person if f'{p.value!r}'""")[:] 103 | q.show() 104 | 105 | def test_8(self): 106 | x = 'Tischenko' 107 | q = select(p.first_name + f"{' ' + x}" for p in Person if p.id == 1) 108 | self.assertEqual(set(q), {'Alexander Tischenko'}) 109 | 110 | q2 = select("""p.first_name + f"{' ' + x}" for p in Person if p.id == 1""") 111 | self.assertEqual(set(q2), {'Alexander Tischenko'}) 112 | -------------------------------------------------------------------------------- /pony/orm/tests/test_filter.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | 5 | from pony.orm.tests.model1 import * 6 | from pony.orm.tests import setup_database, teardown_database 7 | 8 | 9 | class TestFilter(unittest.TestCase): 10 | @classmethod 11 | def setUpClass(cls): 12 | setup_database(db) 13 | populate_db() 14 | @classmethod 15 | def tearDownClass(cls): 16 | teardown_database(db) 17 | def setUp(self): 18 | rollback() 19 | db_session.__enter__() 20 | def tearDown(self): 21 | rollback() 22 | db_session.__exit__() 23 | def test_filter_1(self): 24 | q = select(s for s in Student) 25 | result = set(q.filter(scholarship=0)) 26 | self.assertEqual(result, {Student[101], Student[103]}) 27 | def test_filter_2(self): 28 | q = select(s for s in Student) 29 | q2 = q.filter(scholarship=500) 30 | result = set(q2.filter(group=Group['3132'])) 31 | self.assertEqual(result, {Student[104]}) 32 | def test_filter_3(self): 33 | q = select(s for s in Student) 34 | q2 = q.filter(lambda s: s.scholarship > 500) 35 | result = set(q2.filter(lambda s: count(s.marks) > 0)) 36 | self.assertEqual(result, {Student[102]}) 37 | def test_filter_4(self): 38 | q = select(s for s in Student) 39 | q2 = q.filter(lambda s: s.scholarship != 500) 40 | q3 = q2.order_by(1) 41 | result = list(q3.filter(lambda s: count(s.marks) > 1)) 42 | self.assertEqual(result, [Student[101], Student[103]]) 43 | def test_filter_5(self): 44 | q = select(s for s in Student) 45 | q2 = q.filter(lambda s: s.scholarship != 500) 46 | q3 = q2.order_by(Student.name) 47 | result = list(q3.filter(lambda s: count(s.marks) > 1)) 48 | self.assertEqual(result, [Student[103], Student[101]]) 49 | def test_filter_6(self): 50 | q = select(s for s in Student) 51 | q2 = q.filter(lambda s: s.scholarship != 500) 52 | q3 = q2.order_by(lambda s: s.name) 53 | result = list(q3.filter(lambda s: count(s.marks) > 1)) 54 | self.assertEqual(result, [Student[103], Student[101]]) 55 | def test_filter_7(self): 56 | q = select(s for s in Student) 57 | q2 = q.filter(scholarship=0) 58 | result = set(q2.filter(lambda s: count(s.marks) > 1)) 59 | self.assertEqual(result, {Student[103], Student[101]}) 60 | def test_filter_8(self): 61 | q = select(s for s in Student) 62 | q2 = q.filter(lambda s: s.scholarship != 500) 63 | q3 = q2.order_by(lambda s: s.name) 64 | q4 = q3.order_by(None) 65 | result = set(q4.filter(lambda s: count(s.marks) > 1)) 66 | self.assertEqual(result, {Student[103], Student[101]}) 67 | -------------------------------------------------------------------------------- /pony/orm/tests/test_flush.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | 5 | from pony.orm.core import * 6 | from pony.orm.tests.testutils import * 7 | from pony.orm.tests import setup_database, teardown_database 8 | 9 | db = Database() 10 | 11 | 12 | class Person(db.Entity): 13 | name = Required(str) 14 | 15 | 16 | class TestFlush(unittest.TestCase): 17 | @classmethod 18 | def setUpClass(cls): 19 | setup_database(db) 20 | 21 | @classmethod 22 | def tearDownClass(self): 23 | teardown_database(db) 24 | 25 | def test1(self): 26 | with db_session: 27 | a = Person(name='A') 28 | b = Person(name='B') 29 | c = Person(name='C') 30 | self.assertEqual(a.id, None) 31 | self.assertEqual(b.id, None) 32 | self.assertEqual(c.id, None) 33 | 34 | b.flush() 35 | self.assertEqual(a.id, None) 36 | self.assertIsNotNone(b.id) 37 | b_id = b.id 38 | self.assertEqual(c.id, None) 39 | 40 | flush() 41 | self.assertIsNotNone(a.id) 42 | self.assertEqual(b.id, b_id) 43 | self.assertIsNotNone(c.id) 44 | self.assertEqual(len({a.id, b.id, c.id}), 3) 45 | -------------------------------------------------------------------------------- /pony/orm/tests/test_generator_db_session.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | 5 | from pony.orm.core import * 6 | from pony.orm.core import local 7 | from pony.orm.tests.testutils import * 8 | from pony.orm.tests import setup_database, teardown_database 9 | 10 | 11 | class TestGeneratorDbSession(unittest.TestCase): 12 | def setUp(self): 13 | db = Database() 14 | class Account(db.Entity): 15 | id = PrimaryKey(int) 16 | amount = Required(int) 17 | setup_database(db) 18 | 19 | self.db = db 20 | self.Account = Account 21 | 22 | with db_session: 23 | a1 = Account(id=1, amount=1000) 24 | a2 = Account(id=2, amount=2000) 25 | a3 = Account(id=3, amount=3000) 26 | 27 | def tearDown(self): 28 | teardown_database(self.db) 29 | assert local.db_session is None 30 | self.db = self.Account = None 31 | 32 | @raises_exception(TypeError, 'db_session with `retry` option cannot be applied to generator function') 33 | def test1(self): 34 | @db_session(retry=3) 35 | def f(): yield 36 | 37 | @raises_exception(TypeError, 'db_session with `ddl` option cannot be applied to generator function') 38 | def test2(self): 39 | @db_session(ddl=True) 40 | def f(): yield 41 | 42 | @raises_exception(TypeError, 'db_session with `serializable` option cannot be applied to generator function') 43 | def test3(self): 44 | @db_session(serializable=True) 45 | def f(): yield 46 | 47 | def test4(self): 48 | @db_session(immediate=True) 49 | def f(): yield 50 | 51 | @raises_exception(TransactionError, '@db_session-wrapped generator cannot be used inside another db_session') 52 | def test5(self): 53 | @db_session 54 | def f(): yield 55 | with db_session: 56 | next(f()) 57 | 58 | def test6(self): 59 | @db_session 60 | def f(): 61 | x = local.db_session 62 | self.assertTrue(x is not None) 63 | 64 | yield self.db._get_cache() 65 | self.assertEqual(local.db_session, x) 66 | 67 | a1 = self.Account[1] 68 | yield a1.amount 69 | self.assertEqual(local.db_session, x) 70 | 71 | a2 = self.Account[2] 72 | yield a2.amount 73 | 74 | gen = f() 75 | cache = next(gen) 76 | self.assertTrue(cache.is_alive) 77 | self.assertEqual(local.db_session, None) 78 | 79 | amount = next(gen) 80 | self.assertEqual(amount, 1000) 81 | self.assertEqual(local.db_session, None) 82 | 83 | amount = next(gen) 84 | self.assertEqual(amount, 2000) 85 | self.assertEqual(local.db_session, None) 86 | 87 | try: next(gen) 88 | except StopIteration: 89 | self.assertFalse(cache.is_alive) 90 | else: 91 | self.fail() 92 | 93 | def test7(self): 94 | @db_session 95 | def f(id1): 96 | a1 = self.Account[id1] 97 | id2 = yield a1.amount 98 | a2 = self.Account[id2] 99 | amount = yield a2.amount 100 | a1.amount -= amount 101 | a2.amount += amount 102 | commit() 103 | 104 | gen = f(1) 105 | 106 | amount1 = next(gen) 107 | self.assertEqual(amount1, 1000) 108 | 109 | amount2 = gen.send(2) 110 | self.assertEqual(amount2, 2000) 111 | 112 | try: 113 | gen.send(100) 114 | except StopIteration: 115 | pass 116 | else: 117 | self.fail() 118 | 119 | with db_session: 120 | a1 = self.Account[1] 121 | self.assertEqual(a1.amount, 900) 122 | a2 = self.Account[2] 123 | self.assertEqual(a2.amount, 2100) 124 | 125 | @raises_exception(TransactionError, 'You need to manually commit() changes before suspending the generator') 126 | def test8(self): 127 | @db_session 128 | def f(id1): 129 | a1 = self.Account[id1] 130 | a1.amount += 100 131 | yield a1.amount 132 | 133 | for amount in f(1): 134 | pass 135 | 136 | def test9(self): 137 | @db_session 138 | def f(id1): 139 | a1 = self.Account[id1] 140 | a1.amount += 100 141 | commit() 142 | yield a1.amount 143 | 144 | for amount in f(1): 145 | pass 146 | 147 | def test10(self): 148 | @db_session 149 | def f(id1): 150 | a1 = self.Account[id1] 151 | yield a1.amount 152 | a1.amount += 100 153 | 154 | with db_session: 155 | a = self.Account[1].amount 156 | for amount in f(1): 157 | pass 158 | with db_session: 159 | b = self.Account[1].amount 160 | 161 | self.assertEqual(b, a + 100) 162 | 163 | def test12(self): 164 | @db_session 165 | def f(id1): 166 | a1 = self.Account[id1] 167 | yield a1.amount 168 | 169 | gen = f(1) 170 | next(gen) 171 | gen.close() 172 | 173 | @raises_exception(TypeError, 'error message') 174 | def test13(self): 175 | @db_session 176 | def f(id1): 177 | a1 = self.Account[id1] 178 | yield a1.amount 179 | 180 | gen = f(1) 181 | next(gen) 182 | gen.throw(TypeError('error message')) 183 | 184 | if __name__ == '__main__': 185 | unittest.main() 186 | -------------------------------------------------------------------------------- /pony/orm/tests/test_get_pk.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from datetime import date 3 | 4 | from pony.orm import * 5 | from pony.orm.tests import setup_database, teardown_database 6 | 7 | day = date.today() 8 | 9 | db = Database() 10 | 11 | class A(db.Entity): 12 | b = Required("B") 13 | c = Required("C") 14 | PrimaryKey(b, c) 15 | 16 | class B(db.Entity): 17 | id = PrimaryKey(date) 18 | a_set = Set(A) 19 | 20 | class C(db.Entity): 21 | x = Required("X") 22 | y = Required("Y") 23 | a_set = Set(A) 24 | PrimaryKey(x, y) 25 | 26 | class X(db.Entity): 27 | id = PrimaryKey(int) 28 | c_set = Set(C) 29 | 30 | class Y(db.Entity): 31 | id = PrimaryKey(int) 32 | c_set = Set(C) 33 | 34 | 35 | class Test(unittest.TestCase): 36 | def setUp(self): 37 | setup_database(db) 38 | with db_session: 39 | x1 = X(id=123) 40 | y1 = Y(id=456) 41 | b1 = B(id=day) 42 | c1 = C(x=x1, y=y1) 43 | A(b=b1, c=c1) 44 | 45 | def tearDown(self): 46 | teardown_database(db) 47 | 48 | @db_session 49 | def test_1(self): 50 | a1 = A.select().first() 51 | a2 = A[a1.get_pk()] 52 | self.assertEqual(a1, a2) 53 | 54 | @db_session 55 | def test2(self): 56 | a = A.select().first() 57 | b = B.select().first() 58 | c = C.select().first() 59 | pk = (b.get_pk(), c._get_raw_pkval_()) 60 | self.assertTrue(a is A[pk]) 61 | 62 | @db_session 63 | def test3(self): 64 | a = A.select().first() 65 | c = C.select().first() 66 | pk = (day, c.get_pk()) 67 | self.assertTrue(a is A[pk]) 68 | -------------------------------------------------------------------------------- /pony/orm/tests/test_getattr.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pony.orm import * 4 | from pony import orm 5 | from pony.utils import cached_property 6 | from pony.orm.tests.testutils import raises_exception 7 | from pony.orm.tests import db_params, setup_database, teardown_database 8 | 9 | class Test(unittest.TestCase): 10 | 11 | @cached_property 12 | def db(self): 13 | return orm.Database() 14 | 15 | def setUp(self): 16 | db = self.db 17 | 18 | class Genre(db.Entity): 19 | name = orm.Required(str) 20 | artists = orm.Set('Artist') 21 | 22 | class Hobby(db.Entity): 23 | name = orm.Required(str) 24 | artists = orm.Set('Artist') 25 | 26 | class Artist(db.Entity): 27 | name = orm.Required(str) 28 | age = orm.Optional(int) 29 | hobbies = orm.Set(Hobby) 30 | genres = orm.Set(Genre) 31 | 32 | setup_database(db) 33 | 34 | with orm.db_session: 35 | pop = Genre(name='Pop') 36 | Artist(name='Sia', age=40, genres=[pop]) 37 | Hobby(name='Swimming') 38 | 39 | pony.options.INNER_JOIN_SYNTAX = True 40 | 41 | def tearDown(self): 42 | teardown_database(self.db) 43 | 44 | @db_session 45 | def test_no_caching(self): 46 | for attr_name, attr_type in zip(['name', 'age'], [str, int]): 47 | val = select(getattr(x, attr_name) for x in self.db.Artist).first() 48 | self.assertIsInstance(val, attr_type) 49 | 50 | @db_session 51 | def test_simple(self): 52 | val = select(getattr(x, 'age') for x in self.db.Artist).first() 53 | self.assertIsInstance(val, int) 54 | 55 | @db_session 56 | def test_expr(self): 57 | val = select(getattr(x, ''.join(['ag', 'e'])) for x in self.db.Artist).first() 58 | self.assertIsInstance(val, int) 59 | 60 | @db_session 61 | def test_external(self): 62 | class data: 63 | id = 1 64 | val = select(x.id for x in self.db.Artist if x.id >= getattr(data, 'id')).first() 65 | self.assertIsNotNone(val) 66 | 67 | @db_session 68 | def test_related(self): 69 | val = select(getattr(x.genres, 'name') for x in self.db.Artist).first() 70 | self.assertIsNotNone(val) 71 | 72 | @db_session 73 | def test_not_instance_iter(self): 74 | val = select(getattr(x.name, 'startswith')('S') for x in self.db.Artist).first() 75 | self.assertTrue(val) 76 | 77 | @raises_exception(TranslationError, 'Expression `getattr(x, x.name)` cannot be translated into SQL ' 78 | 'because x.name will be different for each row') 79 | @db_session 80 | def test_not_external(self): 81 | select(getattr(x, x.name) for x in self.db.Artist) 82 | 83 | @raises_exception(TypeError, 'In `getattr(x, 1)` second argument should be a string. Got: 1') 84 | @db_session 85 | def test_not_string(self): 86 | select(getattr(x, 1) for x in self.db.Artist) 87 | 88 | @raises_exception(TypeError, 'In `getattr(x, name)` second argument should be a string. Got: 1') 89 | @db_session 90 | def test_not_string(self): 91 | name = 1 92 | select(getattr(x, name) for x in self.db.Artist) 93 | 94 | @db_session 95 | def test_lambda_1(self): 96 | for name, value in [('name', 'Sia'), ('age', 40), ('name', 'Sia')]: 97 | result = self.db.Artist.select(lambda a: getattr(a, name) == value) 98 | self.assertEqual(set(obj.name for obj in result), {'Sia'}) 99 | 100 | @db_session 101 | def test_lambda_2(self): 102 | for entity, name, value in [ 103 | (self.db.Genre, 'name', 'Pop'), 104 | (self.db.Artist, 'age', 40), 105 | (self.db.Hobby, 'name', 'Swimming'), 106 | ]: 107 | result = entity.select(lambda a: getattr(a, name) == value) 108 | self.assertEqual(set(result[:]), {entity.select().first()}) 109 | -------------------------------------------------------------------------------- /pony/orm/tests/test_hooks.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | 5 | from pony.orm.core import * 6 | from pony.orm.tests import setup_database, teardown_database, db_params 7 | 8 | logged_events = [] 9 | 10 | db = Database() 11 | 12 | 13 | class Person(db.Entity): 14 | id = PrimaryKey(int) 15 | name = Required(str) 16 | age = Required(int) 17 | 18 | def before_insert(self): 19 | logged_events.append('BI_' + self.name) 20 | do_before_insert(self) 21 | 22 | def before_update(self): 23 | logged_events.append('BU_' + self.name) 24 | do_before_update(self) 25 | 26 | def before_delete(self): 27 | logged_events.append('BD_' + self.name) 28 | do_before_delete(self) 29 | 30 | def after_insert(self): 31 | logged_events.append('AI_' + self.name) 32 | do_after_insert(self) 33 | 34 | def after_update(self): 35 | logged_events.append('AU_' + self.name) 36 | do_after_update(self) 37 | 38 | def after_delete(self): 39 | logged_events.append('AD_' + self.name) 40 | do_after_delete(self) 41 | 42 | 43 | def do_nothing(person): 44 | pass 45 | 46 | 47 | def set_hooks_to_do_nothing(): 48 | global do_before_insert, do_before_update, do_before_delete 49 | global do_after_insert, do_after_update, do_after_delete 50 | do_before_insert = do_before_update = do_before_delete = do_nothing 51 | do_after_insert = do_after_update = do_after_delete = do_nothing 52 | 53 | 54 | db.bind(**db_params) 55 | db.generate_mapping(check_tables=False) 56 | 57 | set_hooks_to_do_nothing() 58 | 59 | 60 | def flush_for(*objects): 61 | for obj in objects: 62 | obj.flush() 63 | 64 | 65 | class TestHooks(unittest.TestCase): 66 | @classmethod 67 | def setUpClass(cls): 68 | setup_database(db) 69 | 70 | @classmethod 71 | def tearDownClass(cls): 72 | teardown_database(db) 73 | 74 | def setUp(self): 75 | set_hooks_to_do_nothing() 76 | with db_session: 77 | db.execute('delete from Person') 78 | p1 = Person(id=1, name='John', age=22) 79 | p2 = Person(id=2, name='Mary', age=18) 80 | p3 = Person(id=3, name='Mike', age=25) 81 | logged_events[:] = [] 82 | 83 | def tearDown(self): 84 | pass 85 | 86 | @db_session 87 | def test_1a(self): 88 | p4 = Person(id=4, name='Bob', age=16) 89 | p5 = Person(id=5, name='Lucy', age=23) 90 | self.assertEqual(logged_events, []) 91 | db.flush() 92 | self.assertEqual(logged_events, ['BI_Bob', 'BI_Lucy', 'AI_Bob', 'AI_Lucy']) 93 | 94 | @db_session 95 | def test_1b(self): 96 | p4 = Person(id=4, name='Bob', age=16) 97 | p5 = Person(id=5, name='Lucy', age=23) 98 | self.assertEqual(logged_events, []) 99 | flush_for(p4, p5) 100 | self.assertEqual(logged_events, ['BI_Bob', 'AI_Bob', 'BI_Lucy', 'AI_Lucy']) 101 | 102 | @db_session 103 | def test_2a(self): 104 | p4 = Person(id=4, name='Bob', age=16) 105 | p1 = Person[1] # auto-flush here 106 | p2 = Person[2] 107 | self.assertEqual(logged_events, ['BI_Bob', 'AI_Bob']) 108 | p2.age += 1 109 | p5 = Person(id=5, name='Lucy', age=23) 110 | db.flush() 111 | self.assertEqual(logged_events, ['BI_Bob', 'AI_Bob', 'BU_Mary', 'BI_Lucy', 'AU_Mary', 'AI_Lucy']) 112 | 113 | @db_session 114 | def test_2b(self): 115 | p4 = Person(id=4, name='Bob', age=16) 116 | p1 = Person[1] # auto-flush here 117 | p2 = Person[2] 118 | self.assertEqual(logged_events, ['BI_Bob', 'AI_Bob']) 119 | p2.age += 1 120 | p5 = Person(id=5, name='Lucy', age=23) 121 | flush_for(p4, p2, p5) 122 | self.assertEqual(logged_events, ['BI_Bob', 'AI_Bob', 'BU_Mary', 'AU_Mary', 'BI_Lucy', 'AI_Lucy']) 123 | 124 | @db_session 125 | def test_3(self): 126 | global do_before_insert 127 | def do_before_insert(person): 128 | some_person = Person.select().first() # should not cause infinite recursion 129 | p4 = Person(id=4, name='Bob', age=16) 130 | db.flush() 131 | 132 | @db_session 133 | def test_4(self): 134 | global do_before_insert 135 | def do_before_insert(person): 136 | some_person = Person.select().first() # creates nested prefetch_context 137 | p4 = Person(id=4, name='Bob', age=16) 138 | Person.select().first() 139 | 140 | 141 | if __name__ == '__main__': 142 | unittest.main() 143 | -------------------------------------------------------------------------------- /pony/orm/tests/test_indexes.py: -------------------------------------------------------------------------------- 1 | import sys, unittest 2 | from decimal import Decimal 3 | from datetime import date 4 | 5 | from pony.orm import * 6 | from pony.orm.tests.testutils import * 7 | from pony.orm.tests import db_params, teardown_database 8 | 9 | class TestIndexes(unittest.TestCase): 10 | def setUp(self): 11 | self.db = Database(**db_params) 12 | 13 | def tearDown(self): 14 | teardown_database(self.db) 15 | 16 | def test_1(self): 17 | db = self.db 18 | class Person(db.Entity): 19 | name = Required(str) 20 | age = Required(int) 21 | composite_key(name, 'age') 22 | db.generate_mapping(create_tables=True) 23 | 24 | i1, i2 = Person._indexes_ 25 | self.assertEqual(i1.attrs, (Person.id,)) 26 | self.assertEqual(i1.is_pk, True) 27 | self.assertEqual(i1.is_unique, True) 28 | self.assertEqual(i2.attrs, (Person.name, Person.age)) 29 | self.assertEqual(i2.is_pk, False) 30 | self.assertEqual(i2.is_unique, True) 31 | 32 | table_name = 'Person' if db.provider.dialect == 'SQLite' and pony.__version__ < '0.9' else 'person' 33 | table = db.schema.tables[table_name] 34 | name_column = table.column_dict['name'] 35 | age_column = table.column_dict['age'] 36 | self.assertEqual(len(table.indexes), 2) 37 | db_index = table.indexes[name_column, age_column] 38 | self.assertEqual(db_index.is_pk, False) 39 | self.assertEqual(db_index.is_unique, True) 40 | 41 | def test_2(self): 42 | db = self.db 43 | class Person(db.Entity): 44 | name = Required(str) 45 | age = Required(int) 46 | composite_index(name, 'age') 47 | db.generate_mapping(create_tables=True) 48 | 49 | i1, i2 = Person._indexes_ 50 | self.assertEqual(i1.attrs, (Person.id,)) 51 | self.assertEqual(i1.is_pk, True) 52 | self.assertEqual(i1.is_unique, True) 53 | self.assertEqual(i2.attrs, (Person.name, Person.age)) 54 | self.assertEqual(i2.is_pk, False) 55 | self.assertEqual(i2.is_unique, False) 56 | 57 | table_name = 'Person' if db.provider.dialect == 'SQLite' and pony.__version__ < '0.9' else 'person' 58 | table = db.schema.tables[table_name] 59 | name_column = table.column_dict['name'] 60 | age_column = table.column_dict['age'] 61 | self.assertEqual(len(table.indexes), 2) 62 | db_index = table.indexes[name_column, age_column] 63 | self.assertEqual(db_index.is_pk, False) 64 | self.assertEqual(db_index.is_unique, False) 65 | 66 | create_script = db.schema.generate_create_script() 67 | 68 | 69 | dialect = self.db.provider.dialect 70 | if pony.__version__ < '0.9': 71 | if dialect == 'SQLite': 72 | index_sql = 'CREATE INDEX "idx_person__name_age" ON "Person" ("name", "age")' 73 | else: 74 | index_sql = 'CREATE INDEX "idx_person__name_age" ON "person" ("name", "age")' 75 | elif dialect == 'MySQL' or dialect == 'SQLite': 76 | index_sql = 'CREATE INDEX `idx_person__name__age` ON `person` (`name`, `age`)' 77 | elif dialect == 'PostgreSQL': 78 | index_sql = 'CREATE INDEX "idx_person__name__age" ON "person" ("name", "age")' 79 | elif dialect == 'Oracle': 80 | index_sql = 'CREATE INDEX "IDX_PERSON__NAME__AGE" ON "PERSON" ("NAME", "AGE")' 81 | else: 82 | raise NotImplementedError 83 | self.assertIn(index_sql, create_script) 84 | 85 | def test_3(self): 86 | db = self.db 87 | class User(db.Entity): 88 | name = Required(str, unique=True) 89 | 90 | db.generate_mapping(create_tables=True) 91 | 92 | with db_session: 93 | u = User(id=1, name='A') 94 | 95 | with db_session: 96 | u = User[1] 97 | u.name = 'B' 98 | 99 | with db_session: 100 | u = User[1] 101 | self.assertEqual(u.name, 'B') 102 | 103 | def test_4(self): # issue 321 104 | db = self.db 105 | class Person(db.Entity): 106 | name = Required(str) 107 | age = Required(int) 108 | composite_key(name, age) 109 | 110 | db.generate_mapping(create_tables=True) 111 | with db_session: 112 | p1 = Person(id=1, name='John', age=19) 113 | 114 | with db_session: 115 | p1 = Person[1] 116 | p1.set(name='John', age=19) 117 | p1.delete() 118 | 119 | def test_5(self): 120 | db = self.db 121 | 122 | class Table1(db.Entity): 123 | name = Required(str) 124 | table2s = Set('Table2') 125 | 126 | class Table2(db.Entity): 127 | height = Required(int) 128 | length = Required(int) 129 | table1 = Optional('Table1') 130 | composite_key(height, length, table1) 131 | 132 | db.generate_mapping(create_tables=True) 133 | 134 | with db_session: 135 | Table2(height=2, length=1) 136 | Table2.exists(height=2, length=1) 137 | 138 | if __name__ == '__main__': 139 | unittest.main() 140 | -------------------------------------------------------------------------------- /pony/orm/tests/test_inner_join_syntax.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pony.orm import * 4 | from pony import orm 5 | from pony.orm.tests import setup_database, teardown_database, only_for 6 | 7 | db = Database() 8 | 9 | 10 | class Genre(db.Entity): 11 | name = orm.Optional(str) # TODO primary key 12 | artists = orm.Set('Artist') 13 | favorite = orm.Optional(bool) 14 | index = orm.Optional(int) 15 | 16 | 17 | class Hobby(db.Entity): 18 | name = orm.Required(str) 19 | artists = orm.Set('Artist') 20 | 21 | 22 | class Artist(db.Entity): 23 | name = orm.Required(str) 24 | age = orm.Optional(int) 25 | hobbies = orm.Set(Hobby) 26 | genres = orm.Set(Genre) 27 | 28 | pony.options.INNER_JOIN_SYNTAX = True 29 | 30 | 31 | @only_for('sqlite') 32 | class TestJoin(unittest.TestCase): 33 | exclude_fixtures = {'test': ['clear_tables']} 34 | @classmethod 35 | def setUpClass(cls): 36 | setup_database(db) 37 | 38 | with orm.db_session: 39 | pop = Genre(name='pop') 40 | rock = Genre(name='rock') 41 | Artist(name='Sia', age=40, genres=[pop, rock]) 42 | Artist(name='Lady GaGa', age=30, genres=[pop]) 43 | 44 | @classmethod 45 | def tearDownClass(cls): 46 | teardown_database(db) 47 | 48 | @db_session 49 | def test_join_1(self): 50 | result = select(g.id for g in db.Genre for a in g.artists if a.name.startswith('S'))[:] 51 | self.assertEqual(db.last_sql, """SELECT DISTINCT "g"."id" 52 | FROM "Genre" "g" 53 | INNER JOIN "Artist_Genre" "t-1" 54 | ON "g"."id" = "t-1"."genre" 55 | INNER JOIN "Artist" "a" 56 | ON "t-1"."artist" = "a"."id" 57 | WHERE "a"."name" LIKE 'S%'""") 58 | 59 | @db_session 60 | def test_join_2(self): 61 | result = select(g.id for g in db.Genre for a in db.Artist 62 | if JOIN(a in g.artists) and a.name.startswith('S'))[:] 63 | self.assertEqual(db.last_sql, """SELECT DISTINCT "g"."id" 64 | FROM "Genre" "g" 65 | INNER JOIN "Artist_Genre" "t-1" 66 | ON "g"."id" = "t-1"."genre", "Artist" "a" 67 | WHERE "t-1"."artist" = "a"."id" 68 | AND "a"."name" LIKE 'S%'""") 69 | 70 | 71 | @db_session 72 | def test_join_3(self): 73 | result = select(g.id for g in db.Genre for x in db.Artist for a in db.Artist 74 | if JOIN(a in g.artists) and a.name.startswith('S') and g.id == x.id)[:] 75 | self.assertEqual(db.last_sql, '''SELECT DISTINCT "g"."id" 76 | FROM "Genre" "g" 77 | INNER JOIN "Artist_Genre" "t-1" 78 | ON "g"."id" = "t-1"."genre", "Artist" "x", "Artist" "a" 79 | WHERE "t-1"."artist" = "a"."id" 80 | AND "a"."name" LIKE 'S%' 81 | AND "g"."id" = "x"."id"''') 82 | 83 | @db_session 84 | def test_join_4(self): 85 | result = select(g.id for g in db.Genre for a in db.Artist for x in db.Artist 86 | if JOIN(a in g.artists) and a.name.startswith('S') and g.id == x.id)[:] 87 | self.assertEqual(db.last_sql, '''SELECT DISTINCT "g"."id" 88 | FROM "Genre" "g" 89 | INNER JOIN "Artist_Genre" "t-1" 90 | ON "g"."id" = "t-1"."genre", "Artist" "a", "Artist" "x" 91 | WHERE "t-1"."artist" = "a"."id" 92 | AND "a"."name" LIKE 'S%' 93 | AND "g"."id" = "x"."id"''') 94 | 95 | if __name__ == '__main__': 96 | unittest.main() 97 | -------------------------------------------------------------------------------- /pony/orm/tests/test_int_converter.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | 5 | from pony import orm 6 | from pony.orm.tests.testutils import * 7 | from pony.orm.tests import setup_database, teardown_database 8 | 9 | class TestIntConverter1(unittest.TestCase): 10 | def setUp(self): 11 | self.db = db = orm.Database() 12 | 13 | class Foo(db.Entity): 14 | id = orm.PrimaryKey(int) 15 | x = orm.Required(int, size=8, unsigned=True) 16 | 17 | setup_database(db) 18 | 19 | with orm.db_session: 20 | foo = Foo(id=123, x=1) 21 | 22 | def tearDown(self): 23 | teardown_database(self.db) 24 | 25 | def test_1(self): 26 | with orm.db_session: 27 | foo = self.db.Foo[123] 28 | foo.x -= 1 29 | with orm.db_session: 30 | foo = self.db.Foo[123] 31 | self.assertEqual(foo.x, 0) 32 | 33 | @raises_exception(ValueError, "Value -1 of attr Foo.x is less than the minimum allowed value 0") 34 | @orm.db_session 35 | def test_2(self): 36 | foo = self.db.Foo[123] 37 | foo.x -= 2 38 | 39 | @orm.db_session 40 | def test_3(self): 41 | with orm.db_session: 42 | foo = self.db.Foo[123] 43 | foo.x += 254 44 | with orm.db_session: 45 | foo = self.db.Foo[123] 46 | self.assertEqual(foo.x, 255) 47 | 48 | @raises_exception(ValueError, "Value 256 of attr Foo.x is greater than the maximum allowed value 255") 49 | @orm.db_session 50 | def test_4(self): 51 | foo = self.db.Foo[123] 52 | foo.x += 255 53 | -------------------------------------------------------------------------------- /pony/orm/tests/test_interleave.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | 5 | from pony.orm.core import * 6 | from pony.orm.tests.testutils import raises_exception 7 | from pony.orm.tests import db_params, only_for 8 | 9 | @only_for(providers=['cockroach']) 10 | class TestDiag(unittest.TestCase): 11 | @raises_exception(TypeError, '`interleave` option cannot be specified for Set attribute Foo.x') 12 | def test_1(self): 13 | db = Database() 14 | class Foo(db.Entity): 15 | x = Set('Bar', interleave=True) 16 | class Bar(db.Entity): 17 | y = Required('Foo') 18 | 19 | @raises_exception(TypeError, "`interleave` option value should be True, False or None. Got: 'yes'") 20 | def test_2(self): 21 | db = Database() 22 | class Foo(db.Entity): 23 | x = Required('Bar', interleave='yes') 24 | class Bar(db.Entity): 25 | y = Set('Foo') 26 | 27 | @raises_exception(TypeError, 'only one attribute may be marked as interleave. Got: Foo.x, Foo.y') 28 | def test_3(self): 29 | db = Database() 30 | class Foo(db.Entity): 31 | x = Required(int, interleave=True) 32 | y = Required(int, interleave=True) 33 | 34 | @raises_exception(TypeError, 'Interleave attribute should be part of relationship. Got: Foo.x') 35 | def test_4(self): 36 | db = Database() 37 | class Foo(db.Entity): 38 | x = Required(int, interleave=True) 39 | 40 | def test_5(self): 41 | db = Database(**db_params) 42 | class Bar(db.Entity): 43 | y = Set('Foo') 44 | 45 | class Foo(db.Entity): 46 | x = Required('Bar', interleave=True) 47 | id = Required(int) 48 | PrimaryKey(x, id) 49 | 50 | db.generate_mapping(create_tables=True) 51 | s = ') INTERLEAVE IN PARENT "bar" ("x")' 52 | self.assertIn(s, db.schema.tables['foo'].get_create_command()) 53 | db.drop_all_tables() 54 | 55 | 56 | if __name__ == '__main__': 57 | unittest.main() -------------------------------------------------------------------------------- /pony/orm/tests/test_isinstance.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | from decimal import Decimal 3 | 4 | import unittest 5 | 6 | from pony.orm import * 7 | from pony.orm.tests.testutils import * 8 | from pony.orm.tests import setup_database, teardown_database, only_for 9 | 10 | db = Database() 11 | 12 | 13 | class Person(db.Entity): 14 | id = PrimaryKey(int, auto=True) 15 | name = Required(str) 16 | dob = Optional(date) 17 | ssn = Required(str, unique=True) 18 | 19 | 20 | class Student(Person): 21 | group = Required("Group") 22 | mentor = Optional("Teacher") 23 | attend_courses = Set("Course") 24 | 25 | 26 | class Teacher(Person): 27 | teach_courses = Set("Course") 28 | apprentices = Set("Student") 29 | salary = Required(Decimal) 30 | 31 | 32 | class Assistant(Student, Teacher): 33 | pass 34 | 35 | 36 | class Professor(Teacher): 37 | position = Required(str) 38 | 39 | 40 | class Group(db.Entity): 41 | number = PrimaryKey(int) 42 | students = Set("Student") 43 | 44 | 45 | class Course(db.Entity): 46 | name = Required(str) 47 | semester = Required(int) 48 | students = Set(Student) 49 | teachers = Set(Teacher) 50 | PrimaryKey(name, semester) 51 | 52 | 53 | class TestVolatile(unittest.TestCase): 54 | @classmethod 55 | def setUpClass(cls): 56 | setup_database(db) 57 | with db_session: 58 | p = Person(name='Person1', ssn='SSN1') 59 | g = Group(number=123) 60 | prof = Professor(name='Professor1', salary=1000, position='position1', ssn='SSN5') 61 | a1 = Assistant(name='Assistant1', group=g, salary=100, ssn='SSN4', mentor=prof) 62 | a2 = Assistant(name='Assistant2', group=g, salary=200, ssn='SSN6', mentor=prof) 63 | s1 = Student(name='Student1', group=g, ssn='SSN2', mentor=a1) 64 | s2 = Student(name='Student2', group=g, ssn='SSN3') 65 | 66 | @classmethod 67 | def tearDownClass(cls): 68 | teardown_database(db) 69 | 70 | @db_session 71 | def test_1(self): 72 | q = select(p.name for p in Person if isinstance(p, Student)) 73 | self.assertEqual(set(q), {'Student1', 'Student2', 'Assistant1', 'Assistant2'}) 74 | 75 | @db_session 76 | def test_2(self): 77 | q = select(p.name for p in Person if not isinstance(p, Student)) 78 | self.assertEqual(set(q), {'Person1', 'Professor1'}) 79 | 80 | @db_session 81 | def test_3(self): 82 | q = select(p.name for p in Student if isinstance(p, Professor)) 83 | self.assertEqual(set(q), set()) 84 | 85 | @db_session 86 | def test_4(self): 87 | q = select(p.name for p in Person if not isinstance(p, Person)) 88 | self.assertEqual(set(q), set()) 89 | 90 | @db_session 91 | def test_5(self): 92 | q = select(p.name for p in Person if isinstance(p, (Student, Teacher))) 93 | self.assertEqual(set(q), {'Student1', 'Student2', 'Assistant1', 'Assistant2', 'Professor1'}) 94 | 95 | @db_session 96 | def test_6(self): 97 | q = select(p.name for p in Person if isinstance(p, Student) and isinstance(p, Teacher)) 98 | self.assertEqual(set(q), {'Assistant1', 'Assistant2'}) 99 | 100 | @db_session 101 | def test_7(self): 102 | q = select(p.name for p in Person 103 | if (isinstance(p, Student) and p.ssn == 'SSN2') 104 | or (isinstance(p, Professor) and p.salary > 500)) 105 | self.assertEqual(set(q), {'Student1', 'Professor1'}) 106 | 107 | @db_session 108 | def test_8(self): 109 | q = select(p.name for p in Person if isinstance(p, Person)) 110 | self.assertEqual(set(q), {'Person1', 'Student1', 'Student2', 'Assistant1', 'Assistant2', 'Professor1'}) 111 | 112 | @db_session 113 | def test_9(self): 114 | q = select(g.number for g in Group if isinstance(g, Group)) 115 | self.assertEqual(set(q), {123}) 116 | 117 | 118 | if __name__ == '__main__': 119 | unittest.main() 120 | -------------------------------------------------------------------------------- /pony/orm/tests/test_lambda.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from datetime import datetime, timedelta 3 | 4 | from pony.orm import * 5 | from pony.orm.tests import setup_database, teardown_database 6 | 7 | db = Database() 8 | 9 | 10 | class User(db.Entity): 11 | id = PrimaryKey(int) 12 | login = Required(str) 13 | password = Required(str) 14 | created_at = Required(datetime, default=datetime.now()) 15 | 16 | 17 | class TestLambda(unittest.TestCase): 18 | @classmethod 19 | def setUpClass(cls) -> None: 20 | setup_database(db) 21 | 22 | @classmethod 23 | def setUp(self) -> None: 24 | with db_session: 25 | User(id=1, login='test', password='123456', created_at=datetime(2012, 12, 13, 5, 25, 30)) 26 | User(id=2, login='test2', password='123456', created_at=datetime(2015, 12, 13, 5, 25, 30)) 27 | User(id=3, login='test3', password='123456') 28 | 29 | @classmethod 30 | def tearDownClass(cls) -> None: 31 | teardown_database(db) 32 | 33 | @classmethod 34 | def tearDown(self) -> None: 35 | with db_session: 36 | User.select().delete() 37 | 38 | @db_session 39 | def test_select(self): 40 | result = User.select(lambda u: u.created_at < datetime.now() - timedelta(days=365))[:] 41 | self.assertEqual([u.id for u in result], [1, 2]) 42 | 43 | @db_session 44 | def test_order_by_1(self): 45 | result = User.select().order_by(lambda u: u.id) 46 | self.assertEqual([u.id for u in result], [1, 2, 3]) 47 | 48 | @db_session 49 | def test_order_by_2(self): 50 | result = User.select().order_by(lambda u: desc(u.id)) 51 | self.assertEqual([u.id for u in result], [3, 2, 1]) 52 | 53 | @db_session 54 | def test_order_by_3(self): 55 | result = User.select().order_by(lambda u: (u.login, u.id)) 56 | self.assertEqual([u.id for u in result], [1, 2, 3]) 57 | 58 | @db_session 59 | def test_order_by_4(self): 60 | result = User.select().order_by(lambda u: (desc(u.login), desc(u.id))) 61 | self.assertEqual([u.id for u in result], [3, 2, 1]) 62 | 63 | -------------------------------------------------------------------------------- /pony/orm/tests/test_lazy.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | 5 | from pony.orm.core import * 6 | from pony.orm.tests import setup_database, teardown_database 7 | 8 | 9 | class TestLazy(unittest.TestCase): 10 | def setUp(self): 11 | db = self.db = Database() 12 | class X(self.db.Entity): 13 | a = Required(int) 14 | b = Required(str, lazy=True) 15 | self.X = X 16 | setup_database(db) 17 | with db_session: 18 | x1 = X(id=1, a=1, b='first') 19 | x2 = X(id=2, a=2, b='second') 20 | x3 = X(id=3, a=3, b='third') 21 | 22 | def tearDown(self): 23 | teardown_database(self.db) 24 | 25 | @db_session 26 | def test_lazy_1(self): 27 | X = self.X 28 | x1 = X[1] 29 | self.assertTrue(X.a in x1._vals_) 30 | self.assertTrue(X.b not in x1._vals_) 31 | b = x1.b 32 | self.assertEqual(b, 'first') 33 | 34 | @db_session 35 | def test_lazy_2(self): 36 | X = self.X 37 | x1 = X[1] 38 | x2 = X[2] 39 | x3 = X[3] 40 | self.assertTrue(X.b not in x1._vals_) 41 | self.assertTrue(X.b not in x2._vals_) 42 | self.assertTrue(X.b not in x3._vals_) 43 | b = x1.b 44 | self.assertTrue(X.b in x1._vals_) 45 | self.assertTrue(X.b not in x2._vals_) 46 | self.assertTrue(X.b not in x3._vals_) 47 | 48 | @db_session 49 | def test_lazy_3(self): # coverage of https://github.com/ponyorm/pony/issues/49 50 | X = self.X 51 | x1 = X.get(b='first') 52 | self.assertTrue(X._bits_[X.b] & x1._rbits_) 53 | self.assertTrue(X.b, x1._vals_) 54 | 55 | @db_session 56 | def test_lazy_4(self): # coverage of https://github.com/ponyorm/pony/issues/49 57 | X = self.X 58 | result = select(x for x in X if x.b == 'first')[:] 59 | for x in result: 60 | self.assertTrue(X._bits_[X.b] & x._rbits_) 61 | self.assertTrue(X.b in x._vals_) 62 | 63 | @db_session 64 | def test_lazy_5(self): # coverage of https://github.com/ponyorm/pony/issues/49 65 | X = self.X 66 | result = select(x for x in X if x.b == 'first' if count() > 0)[:] 67 | for x in result: 68 | self.assertFalse(X._bits_[X.b] & x._rbits_) 69 | self.assertTrue(X.b not in x._vals_) 70 | -------------------------------------------------------------------------------- /pony/orm/tests/test_objects_to_save_cleanup.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pony.orm import * 4 | from pony.orm.tests import setup_database, teardown_database 5 | 6 | class EntityStatusTestCase(object): 7 | @classmethod 8 | def setUpClass(cls): 9 | db = cls.db = Database() 10 | 11 | class TestPost(db.Entity): 12 | category = Optional('TestCategory') 13 | name = Optional(str, default='Noname') 14 | 15 | class TestCategory(db.Entity): 16 | posts = Set(TestPost) 17 | 18 | setup_database(db) 19 | 20 | @classmethod 21 | def tearDownClass(cls): 22 | teardown_database(cls.db) 23 | 24 | def make_flush(self, obj=None): 25 | raise NotImplementedError 26 | 27 | @db_session 28 | def test_delete_updated(self): 29 | p = self.db.TestPost() 30 | self.make_flush(p) 31 | p.name = 'Pony' 32 | self.assertEqual(p._status_, 'modified') 33 | self.make_flush(p) 34 | self.assertEqual(p._status_, 'updated') 35 | p.delete() 36 | self.assertEqual(p._status_, 'marked_to_delete') 37 | self.make_flush(p) 38 | self.assertEqual(p._status_, 'deleted') 39 | 40 | @db_session 41 | def test_delete_inserted(self): 42 | p = self.db.TestPost() 43 | self.assertEqual(p._status_, 'created') 44 | self.make_flush(p) 45 | self.assertEqual(p._status_, 'inserted') 46 | p.delete() 47 | 48 | @db_session 49 | def test_cancelled(self): 50 | p = self.db.TestPost() 51 | self.assertEqual(p._status_, 'created') 52 | p.delete() 53 | self.assertEqual(p._status_, 'cancelled') 54 | self.make_flush(p) 55 | self.assertEqual(p._status_, 'cancelled') 56 | 57 | 58 | class EntityStatusTestCase_ObjectFlush(EntityStatusTestCase, 59 | unittest.TestCase): 60 | 61 | def make_flush(self, obj=None): 62 | obj.flush() 63 | 64 | 65 | class EntityStatusTestCase_FullFlush(EntityStatusTestCase, 66 | unittest.TestCase): 67 | 68 | def make_flush(self, obj=None): 69 | flush() # full flush 70 | -------------------------------------------------------------------------------- /pony/orm/tests/test_random.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pony.orm import * 4 | from pony.orm.tests.testutils import * 5 | from pony.orm.tests import setup_database, teardown_database 6 | 7 | db = Database() 8 | 9 | 10 | class Person(db.Entity): 11 | id = PrimaryKey(int) 12 | name = Required(str) 13 | 14 | 15 | class TestRandom(unittest.TestCase): 16 | @classmethod 17 | def setUpClass(cls): 18 | setup_database(db) 19 | with db_session: 20 | Person(id=1, name='John') 21 | Person(id=2, name='Mary') 22 | Person(id=3, name='Bob') 23 | Person(id=4, name='Mike') 24 | Person(id=5, name='Ann') 25 | 26 | @classmethod 27 | def tearDownClass(cls): 28 | teardown_database(db) 29 | 30 | @db_session 31 | def test_1(self): 32 | persons = Person.select().random(2) 33 | self.assertEqual(len(persons), 2) 34 | p1, p2 = persons 35 | self.assertNotEqual(p1.id, p2.id) 36 | self.assertTrue(p1.id in range(1, 6)) 37 | self.assertTrue(p2.id in range(1, 6)) 38 | 39 | @db_session 40 | def test_2(self): 41 | persons = Person.select_random(2) 42 | self.assertEqual(len(persons), 2) 43 | p1, p2 = persons 44 | self.assertNotEqual(p1.id, p2.id) 45 | self.assertTrue(p1.id in range(1, 6)) 46 | self.assertTrue(p2.id in range(1, 6)) 47 | 48 | if __name__ == '__main__': 49 | unittest.main() 50 | -------------------------------------------------------------------------------- /pony/orm/tests/test_relations_one2one3.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | 5 | from pony.orm.core import * 6 | from pony.orm.tests.testutils import * 7 | from pony.orm.tests import setup_database, teardown_database, only_for 8 | 9 | 10 | @only_for('sqlite') 11 | class TestOneToOne3(unittest.TestCase): 12 | def setUp(self): 13 | self.db = Database() 14 | 15 | class Person(self.db.Entity): 16 | name = Required(str) 17 | passport = Optional("Passport", cascade_delete=True) 18 | 19 | class Passport(self.db.Entity): 20 | code = Required(str) 21 | person = Required("Person") 22 | 23 | setup_database(self.db) 24 | 25 | with db_session: 26 | p1 = Person(name='John') 27 | Passport(code='123', person=p1) 28 | 29 | def tearDown(self): 30 | teardown_database(self.db) 31 | 32 | @db_session 33 | def test_1(self): 34 | obj = select(p for p in self.db.Person if p.passport.id).first() 35 | self.assertEqual(obj.name, 'John') 36 | self.assertEqual(obj.passport.code, '123') 37 | 38 | @db_session 39 | def test_2(self): 40 | select(p for p in self.db.Person if p.passport is None)[:] 41 | sql = self.db.last_sql 42 | self.assertEqual(sql, '''SELECT "p"."id", "p"."name" 43 | FROM "Person" "p" 44 | LEFT JOIN "Passport" "passport" 45 | ON "p"."id" = "passport"."person" 46 | WHERE "passport"."id" IS NULL''') 47 | 48 | @db_session 49 | def test_3(self): 50 | select(p for p in self.db.Person if not p.passport)[:] 51 | sql = self.db.last_sql 52 | self.assertEqual(sql, '''SELECT "p"."id", "p"."name" 53 | FROM "Person" "p" 54 | LEFT JOIN "Passport" "passport" 55 | ON "p"."id" = "passport"."person" 56 | WHERE "passport"."id" IS NULL''') 57 | 58 | @db_session 59 | def test_4(self): 60 | select(p for p in self.db.Person if p.passport)[:] 61 | sql = self.db.last_sql 62 | self.assertEqual(sql, '''SELECT "p"."id", "p"."name" 63 | FROM "Person" "p" 64 | LEFT JOIN "Passport" "passport" 65 | ON "p"."id" = "passport"."person" 66 | WHERE "passport"."id" IS NOT NULL''') 67 | 68 | @db_session 69 | def test_5(self): 70 | p = self.db.Person.get(name='John') 71 | p.delete() 72 | flush() 73 | sql = self.db.last_sql 74 | self.assertEqual(sql, '''DELETE FROM "Person" 75 | WHERE "id" = ?''') 76 | 77 | @raises_exception(ConstraintError, 'Cannot unlink Passport[1] from previous Person[1] object, because Passport.person attribute is required') 78 | @db_session 79 | def test_6(self): 80 | p = self.db.Person.get(name='John') 81 | self.db.Passport(code='456', person=p) 82 | 83 | @raises_exception(ConstraintError, 'Cannot unlink Passport[1] from previous Person[1] object, because Passport.person attribute is required') 84 | @db_session 85 | def test7(self): 86 | p2 = self.db.Person(name='Mike') 87 | pas2 = self.db.Passport(code='456', person=p2) 88 | commit() 89 | p1 = self.db.Person.get(name='John') 90 | pas2.person = p1 91 | 92 | if __name__ == '__main__': 93 | unittest.main() 94 | -------------------------------------------------------------------------------- /pony/orm/tests/test_relations_one2one4.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | 5 | from pony.orm.core import * 6 | from pony.orm.tests.testutils import * 7 | from pony.orm.tests import setup_database, teardown_database 8 | 9 | db = Database() 10 | 11 | class Person(db.Entity): 12 | name = Required(str) 13 | passport = Optional("Passport") 14 | 15 | class Passport(db.Entity): 16 | code = Required(str) 17 | person = Required("Person") 18 | 19 | class TestOneToOne4(unittest.TestCase): 20 | def setUp(self): 21 | setup_database(db) 22 | with db_session: 23 | p1 = Person(id=1, name='John') 24 | Passport(id=1, code='123', person=p1) 25 | 26 | def tearDown(self): 27 | teardown_database(db) 28 | 29 | @raises_exception(ConstraintError, 'Cannot unlink Passport[1] from previous Person[1] object, because Passport.person attribute is required') 30 | @db_session 31 | def test1(self): 32 | p2 = Person(id=2, name='Mike') 33 | pas2 = Passport(id=2, code='456', person=p2) 34 | commit() 35 | p1 = Person.get(name='John') 36 | pas2.person = p1 37 | 38 | if __name__ == '__main__': 39 | unittest.main() 40 | -------------------------------------------------------------------------------- /pony/orm/tests/test_relations_symmetric_m2m.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | from pony.orm.core import * 5 | from pony.orm.tests import setup_database, teardown_database 6 | 7 | db = Database() 8 | 9 | 10 | class Person(db.Entity): 11 | name = Required(str) 12 | friends = Set('Person', reverse='friends') 13 | 14 | 15 | class TestSymmetricM2M(unittest.TestCase): 16 | @classmethod 17 | def setUpClass(cls): 18 | setup_database(db) 19 | 20 | @classmethod 21 | def tearDownClass(cls): 22 | teardown_database(db) 23 | 24 | def setUp(self): 25 | with db_session: 26 | for p in Person.select(): p.delete() 27 | with db_session: 28 | db.insert(Person, id=1, name='A') 29 | db.insert(Person, id=2, name='B') 30 | db.insert(Person, id=3, name='C') 31 | db.insert(Person, id=4, name='D') 32 | db.insert(Person, id=5, name='E') 33 | db.insert(Person.friends, person=1, person_2=2) 34 | db.insert(Person.friends, person=2, person_2=1) 35 | db.insert(Person.friends, person=1, person_2=3) 36 | db.insert(Person.friends, person=3, person_2=1) 37 | db_session.__enter__() 38 | def tearDown(self): 39 | rollback() 40 | db_session.__exit__() 41 | def test1a(self): 42 | p1 = Person[1] 43 | p4 = Person[4] 44 | p1.friends.add(p4) 45 | self.assertEqual(set(p4.friends), {p1}) 46 | def test1b(self): 47 | p1 = Person[1] 48 | p4 = Person[4] 49 | p1.friends.add(p4) 50 | self.assertEqual(set(p1.friends), {Person[2], Person[3], p4}) 51 | def test1c(self): 52 | p1 = Person[1] 53 | p4 = Person[4] 54 | p1.friends.add(p4) 55 | commit() 56 | rows = db.select("* from person_friends order by person, person_2") 57 | self.assertEqual(rows, [(1,2), (1,3), (1,4), (2,1), (3,1), (4,1)]) 58 | def test2a(self): 59 | p1 = Person[1] 60 | p2 = Person[2] 61 | p1.friends.remove(p2) 62 | self.assertEqual(set(p1.friends), {Person[3]}) 63 | def test2b(self): 64 | p1 = Person[1] 65 | p2 = Person[2] 66 | p1.friends.remove(p2) 67 | self.assertEqual(set(Person[3].friends), {p1}) 68 | def test2c(self): 69 | p1 = Person[1] 70 | p2 = Person[2] 71 | p1.friends.remove(p2) 72 | self.assertEqual(set(p2.friends), set()) 73 | def test2d(self): 74 | p1 = Person[1] 75 | p2 = Person[2] 76 | p1.friends.remove(p2) 77 | commit() 78 | rows = db.select("* from person_friends order by person, person_2") 79 | self.assertEqual(rows, [(1,3), (3,1)]) 80 | def test3a(self): 81 | db.execute('delete from person_friends') 82 | db.insert(Person.friends, person=1, person_2=2) 83 | p1 = Person[1] 84 | p2 = Person[2] 85 | p2_friends = set(p2.friends) 86 | self.assertEqual(p2_friends, set()) 87 | try: p1_friends = set(p1.friends) 88 | except UnrepeatableReadError as e: self.assertEqual(e.args[0], 89 | "Phantom object Person[1] appeared in collection Person[2].friends") 90 | else: self.fail() 91 | def test3b(self): 92 | db.execute('delete from person_friends') 93 | db.insert(Person.friends, person=1, person_2=2) 94 | p1 = Person[1] 95 | p2 = Person[2] 96 | p1_friends = set(p1.friends) 97 | self.assertEqual(p1_friends, {p2}) 98 | try: p2_friends = set(p2.friends) 99 | except UnrepeatableReadError as e: self.assertEqual(e.args[0], 100 | "Phantom object Person[1] disappeared from collection Person[2].friends") 101 | else: self.fail() 102 | 103 | if __name__ == '__main__': 104 | unittest.main() 105 | -------------------------------------------------------------------------------- /pony/orm/tests/test_relations_symmetric_one2one.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | 5 | from pony.orm.core import * 6 | from pony.orm.tests.testutils import raises_exception 7 | from pony.orm.tests import setup_database, teardown_database, only_for 8 | 9 | db = Database() 10 | 11 | 12 | class Person(db.Entity): 13 | name = Required(str) 14 | spouse = Optional('Person', reverse='spouse') 15 | 16 | 17 | class TestSymmetricOne2One(unittest.TestCase): 18 | @classmethod 19 | def setUpClass(cls): 20 | setup_database(db) 21 | 22 | @classmethod 23 | def tearDownClass(cls): 24 | teardown_database(db) 25 | 26 | def setUp(self): 27 | with db_session: 28 | db.execute('update person set spouse=null') 29 | db.execute('delete from person') 30 | db.insert(Person, id=1, name='A') 31 | db.insert(Person, id=2, name='B', spouse=1) 32 | db.execute('update person set spouse=2 where id=1') 33 | db.insert(Person, id=3, name='C') 34 | db.insert(Person, id=4, name='D', spouse=3) 35 | db.execute('update person set spouse=4 where id=3') 36 | db.insert(Person, id=5, name='E', spouse=None) 37 | db_session.__enter__() 38 | def tearDown(self): 39 | db_session.__exit__() 40 | def test1(self): 41 | p1 = Person[1] 42 | p2 = Person[2] 43 | p5 = Person[5] 44 | p1.spouse = p5 45 | commit() 46 | self.assertEqual(p1._vals_.get(Person.spouse), p5) 47 | self.assertEqual(p5._vals_.get(Person.spouse), p1) 48 | self.assertEqual(p2._vals_.get(Person.spouse), None) 49 | data = db.select('spouse from person order by id') 50 | self.assertEqual([5, None, 4, 3, 1], data) 51 | def test2(self): 52 | p1 = Person[1] 53 | p2 = Person[2] 54 | p1.spouse = None 55 | commit() 56 | self.assertEqual(p1._vals_.get(Person.spouse), None) 57 | self.assertEqual(p2._vals_.get(Person.spouse), None) 58 | data = db.select('spouse from person order by id') 59 | self.assertEqual([None, None, 4, 3, None], data) 60 | def test3(self): 61 | p1 = Person[1] 62 | p2 = Person[2] 63 | p3 = Person[3] 64 | p4 = Person[4] 65 | p1.spouse = p3 66 | commit() 67 | self.assertEqual(p1._vals_.get(Person.spouse), p3) 68 | self.assertEqual(p2._vals_.get(Person.spouse), None) 69 | self.assertEqual(p3._vals_.get(Person.spouse), p1) 70 | self.assertEqual(p4._vals_.get(Person.spouse), None) 71 | data = db.select('spouse from person order by id') 72 | self.assertEqual([3, None, 1, None, None], data) 73 | def test4(self): 74 | persons = set(select(p for p in Person if p.spouse.name in ('B', 'D'))) 75 | self.assertEqual(persons, {Person[1], Person[3]}) 76 | @raises_exception(UnrepeatableReadError, 'Multiple Person objects linked with the same Person[2] object. ' 77 | 'Maybe Person.spouse attribute should be Set instead of Optional') 78 | def test5(self): 79 | db.execute('update person set spouse = 3 where id = 2') 80 | p1 = Person[1] 81 | p1.spouse 82 | p2 = Person[2] 83 | p2.name 84 | def test6(self): 85 | db.execute('update person set spouse = 3 where id = 2') 86 | p1 = Person[1] 87 | p2 = Person[2] 88 | p2.name 89 | p1.spouse 90 | self.assertEqual(p2._vals_.get(Person.spouse), p1) 91 | 92 | if __name__ == '__main__': 93 | unittest.main() 94 | -------------------------------------------------------------------------------- /pony/orm/tests/test_seeds.py: -------------------------------------------------------------------------------- 1 | 2 | from __future__ import absolute_import, print_function, division 3 | 4 | import unittest 5 | 6 | from pony.orm.core import * 7 | from pony.orm.tests.testutils import * 8 | from pony.orm.tests import teardown_database, setup_database 9 | 10 | db = Database() 11 | 12 | 13 | class Group(db.Entity): 14 | id = PrimaryKey(int) 15 | number = Required(str, unique=True) 16 | students = Set("Student") 17 | 18 | 19 | class Student(db.Entity): 20 | id = PrimaryKey(int) 21 | name = Required(str) 22 | group = Required("Group") 23 | 24 | 25 | class TestCRUD(unittest.TestCase): 26 | @classmethod 27 | def setUpClass(cls): 28 | setup_database(db) 29 | with db_session: 30 | g1 = Group(id=1, number='g111') 31 | g2 = Group(id=2, number='g222') 32 | s1 = Student(id=1, name='S1', group=g1) 33 | s2 = Student(id=2, name='S2', group=g1) 34 | s3 = Student(id=3, name='S3', group=g2) 35 | 36 | @classmethod 37 | def tearDownClass(cls): 38 | teardown_database(db) 39 | 40 | def setUp(self): 41 | rollback() 42 | db_session.__enter__() 43 | 44 | def tearDown(self): 45 | rollback() 46 | db_session.__exit__() 47 | 48 | def test_unique_load(self): 49 | s1 = Student[1] 50 | g1 = s1.group 51 | g1.number = 'g123' 52 | self.assertEqual(g1.number, 'g123') 53 | -------------------------------------------------------------------------------- /pony/orm/tests/test_show.py: -------------------------------------------------------------------------------- 1 | import io, sys, unittest 2 | import contextlib 3 | from decimal import Decimal 4 | from datetime import date 5 | 6 | from pony.orm import * 7 | from pony.orm.tests.testutils import * 8 | from pony.orm.tests import setup_database, teardown_database 9 | 10 | db = Database() 11 | 12 | 13 | class Student(db.Entity): 14 | name = Required(str) 15 | scholarship = Optional(int) 16 | gpa = Optional(Decimal, 3, 1) 17 | dob = Optional(date) 18 | group = Required('Group') 19 | courses = Set('Course') 20 | biography = Optional(LongUnicode) 21 | 22 | class Group(db.Entity): 23 | number = PrimaryKey(int) 24 | students = Set(Student) 25 | 26 | class Course(db.Entity): 27 | name = Required(str, unique=True) 28 | students = Set(Student) 29 | 30 | 31 | normal_stdout = sys.stdout 32 | 33 | 34 | class TestShow(unittest.TestCase): 35 | @classmethod 36 | def setUpClass(cls): 37 | setup_database(db) 38 | 39 | with db_session: 40 | g1 = Group(number=1) 41 | g2 = Group(number=2) 42 | c1 = Course(name='Math') 43 | c2 = Course(name='Physics') 44 | c3 = Course(name='Computer Science') 45 | Student(id=1, name='S1', group=g1, gpa=3.1, courses=[c1, c2], biography='some text') 46 | Student(id=2, name='S2', group=g1, gpa=3.2, scholarship=100, dob=date(2000, 1, 1)) 47 | Student(id=3, name='S3', group=g1, gpa=3.3, scholarship=200, dob=date(2001, 1, 2), courses=[c2, c3]) 48 | 49 | @classmethod 50 | def tearDownClass(cls): 51 | teardown_database(db) 52 | 53 | def setUp(self): 54 | rollback() 55 | db_session.__enter__() 56 | 57 | def tearDown(self): 58 | rollback() 59 | db_session.__exit__() 60 | 61 | def test_1(self): 62 | f = io.StringIO() 63 | with contextlib.redirect_stdout(f): 64 | Student.select().show() 65 | self.assertEqual('\n' + f.getvalue().replace(' ', '~'), ''' 66 | id|name|scholarship|gpa|dob~~~~~~~|group~~~ 67 | --+----+-----------+---+----------+-------- 68 | 1~|S1~~|None~~~~~~~|3.1|None~~~~~~|Group[1] 69 | 2~|S2~~|100~~~~~~~~|3.2|2000-01-01|Group[1] 70 | 3~|S3~~|200~~~~~~~~|3.3|2001-01-02|Group[1] 71 | ''') 72 | 73 | def test_2(self): 74 | f = io.StringIO() 75 | with contextlib.redirect_stdout(f): 76 | Group.select().show() 77 | self.assertEqual('\n' + f.getvalue().replace(' ', '~'), ''' 78 | number 79 | ------ 80 | 1~~~~~ 81 | 2~~~~~ 82 | ''') 83 | 84 | 85 | if __name__ == '__main__': 86 | unittest.main() 87 | -------------------------------------------------------------------------------- /pony/orm/tests/test_sqlbuilding_formatstyles.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | from pony.orm.sqlbuilding import SQLBuilder 5 | from pony.orm.dbapiprovider import DBAPIProvider 6 | from pony.orm.tests.testutils import TestPool 7 | 8 | 9 | class TestFormatStyles(unittest.TestCase): 10 | def setUp(self): 11 | self.key1 = 'KEY1' 12 | self.key2 = 'KEY2' 13 | self.provider = DBAPIProvider(_database=None, pony_pool_mockup=TestPool(None)) 14 | self.ast = [ 'SELECT', [ 'ALL', ['COLUMN', None, 'A']], [ 'FROM', [None, 'TABLE', 'T1']], 15 | [ 'WHERE', [ 'EQ', ['COLUMN', None, 'B'], [ 'PARAM', self.key1 ] ], 16 | [ 'EQ', ['COLUMN', None, 'C'], [ 'PARAM', self.key2 ] ], 17 | [ 'EQ', ['COLUMN', None, 'D'], [ 'PARAM', self.key2 ] ], 18 | [ 'EQ', ['COLUMN', None, 'E'], [ 'PARAM', self.key1 ] ] 19 | ] 20 | ] 21 | def test_qmark(self): 22 | self.provider.paramstyle = 'qmark' 23 | b = SQLBuilder(self.provider, self.ast) 24 | self.assertEqual(b.sql, 'SELECT "A"\n' 25 | 'FROM "T1"\n' 26 | 'WHERE "B" = ?\n AND "C" = ?\n AND "D" = ?\n AND "E" = ?') 27 | self.assertEqual(b.layout, [self.key1, self.key2, self.key2, self.key1]) 28 | def test_numeric(self): 29 | self.provider.paramstyle = 'numeric' 30 | b = SQLBuilder(self.provider, self.ast) 31 | self.assertEqual(b.sql, 'SELECT "A"\n' 32 | 'FROM "T1"\n' 33 | 'WHERE "B" = :1\n AND "C" = :2\n AND "D" = :2\n AND "E" = :1') 34 | self.assertEqual(b.layout, [self.key1, self.key2, self.key2, self.key1]) 35 | def test_named(self): 36 | self.provider.paramstyle = 'named' 37 | b = SQLBuilder(self.provider, self.ast) 38 | self.assertEqual(b.sql, 'SELECT "A"\n' 39 | 'FROM "T1"\n' 40 | 'WHERE "B" = :p1\n AND "C" = :p2\n AND "D" = :p2\n AND "E" = :p1') 41 | self.assertEqual(b.layout, [self.key1, self.key2, self.key2, self.key1]) 42 | def test_format(self): 43 | self.provider.paramstyle = 'format' 44 | b = SQLBuilder(self.provider, self.ast) 45 | self.assertEqual(b.sql, 'SELECT "A"\n' 46 | 'FROM "T1"\n' 47 | 'WHERE "B" = %s\n AND "C" = %s\n AND "D" = %s\n AND "E" = %s') 48 | self.assertEqual(b.layout, [self.key1, self.key2, self.key2, self.key1]) 49 | def test_pyformat(self): 50 | self.provider.paramstyle = 'pyformat' 51 | b = SQLBuilder(self.provider, self.ast) 52 | self.assertEqual(b.sql, 'SELECT "A"\n' 53 | 'FROM "T1"\n' 54 | 'WHERE "B" = %(p1)s\n AND "C" = %(p2)s\n AND "D" = %(p2)s\n AND "E" = %(p1)s') 55 | self.assertEqual(b.layout, [self.key1, self.key2, self.key2, self.key1]) 56 | 57 | 58 | if __name__ == "__main__": 59 | unittest.main() 60 | -------------------------------------------------------------------------------- /pony/orm/tests/test_sqlbuilding_sqlast.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import unittest 4 | from pony.orm.core import Database, db_session 5 | from pony.orm.sqlsymbols import * 6 | from pony.orm.tests import setup_database, only_for 7 | 8 | 9 | @only_for('sqlite') 10 | class TestSQLAST(unittest.TestCase): 11 | def setUp(self): 12 | self.db = Database() 13 | setup_database(self.db) 14 | with db_session: 15 | conn = self.db.get_connection() 16 | conn.executescript(""" 17 | create table if not exists T1( 18 | a integer primary key, 19 | b varchar(20) not null 20 | ); 21 | insert or ignore into T1 values(1, 'abc'); 22 | """) 23 | 24 | def tearDown(self): 25 | with db_session: 26 | conn = self.db.get_connection() 27 | conn.executescript("""drop table T1 28 | """) 29 | 30 | @db_session 31 | def test_alias(self): 32 | sql_ast = [SELECT, [ALL, [COLUMN, "Group", "a"]], 33 | [FROM, ["Group", TABLE, "T1" ]]] 34 | sql, adapter = self.db._ast2sql(sql_ast) 35 | cursor = self.db._exec_sql(sql) 36 | @db_session 37 | def test_alias2(self): 38 | sql_ast = [SELECT, [ALL, [COLUMN, None, "a"]], 39 | [FROM, [None, TABLE, "T1"]]] 40 | sql, adapter = self.db._ast2sql(sql_ast) 41 | cursor = self.db._exec_sql(sql) 42 | 43 | 44 | if __name__ == "__main__": 45 | unittest.main() 46 | -------------------------------------------------------------------------------- /pony/orm/tests/test_sqlite_shared_memory_db.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import threading 4 | import unittest 5 | 6 | from pony.orm.core import * 7 | 8 | 9 | db = Database('sqlite', ':sharedmemory:') 10 | 11 | 12 | class Person(db.Entity): 13 | name = Required(str) 14 | 15 | db.generate_mapping(create_tables=True) 16 | 17 | with db_session: 18 | Person(name='John') 19 | Person(name='Mike') 20 | 21 | 22 | class TestThread(threading.Thread): 23 | def __init__(self, *args, **kwargs): 24 | super().__init__(*args, *kwargs) 25 | self.result = [] 26 | def run(self): 27 | with db_session: 28 | persons = Person.select().fetch() 29 | self.result.extend(p.name for p in persons) 30 | 31 | 32 | class TestFlush(unittest.TestCase): 33 | def test1(self): 34 | thread1 = TestThread() 35 | thread1.start() 36 | thread1.join() 37 | self.assertEqual(set(thread1.result), {'John', 'Mike'}) 38 | -------------------------------------------------------------------------------- /pony/orm/tests/test_sqlite_str_functions.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | from __future__ import absolute_import, print_function, division 4 | 5 | from binascii import unhexlify 6 | import unittest 7 | 8 | from pony.orm.core import * 9 | from pony.orm.tests.testutils import * 10 | from pony.orm.tests import only_for 11 | 12 | db = Database('sqlite', ':memory:') 13 | 14 | 15 | class Person(db.Entity): 16 | name = Required(str) 17 | age = Optional(int) 18 | image = Optional(buffer) 19 | 20 | 21 | db.generate_mapping(create_tables=True) 22 | 23 | with db_session: 24 | p1 = Person(name='John', age=20, image=unhexlify('abcdef')) 25 | p2 = Person(name=u'Иван') # u'\u0418\u0432\u0430\u043d' 26 | 27 | 28 | @only_for('sqlite') 29 | class TestUnicode(unittest.TestCase): 30 | @db_session 31 | def test1(self): 32 | names = select(p.name for p in Person).order_by(lambda: p.id)[:] 33 | self.assertEqual(names, ['John', u'Иван']) 34 | 35 | @db_session 36 | def test2(self): 37 | names = select(p.name.upper() for p in Person).order_by(lambda: p.id)[:] 38 | self.assertEqual(names, ['JOHN', u'ИВАН']) # u'\u0418\u0412\u0410\u041d' 39 | 40 | @db_session 41 | def test3(self): 42 | names = select(p.name.lower() for p in Person).order_by(lambda: p.id)[:] 43 | self.assertEqual(names, ['john', u'иван']) # u'\u0438\u0432\u0430\u043d' 44 | 45 | @db_session 46 | def test4(self): 47 | ages = db.select('select py_upper(age) from person') 48 | self.assertEqual(ages, ['20', None]) 49 | 50 | @db_session 51 | def test5(self): 52 | ages = db.select('select py_lower(age) from person') 53 | self.assertEqual(ages, ['20', None]) 54 | 55 | @db_session 56 | def test6(self): 57 | ages = db.select('select py_upper(image) from person') 58 | self.assertEqual(ages, [u'ABCDEF', None]) 59 | 60 | @db_session 61 | def test7(self): 62 | ages = db.select('select py_lower(image) from person') 63 | self.assertEqual(ages, [u'abcdef', None]) 64 | 65 | 66 | if __name__ == '__main__': 67 | unittest.main() 68 | -------------------------------------------------------------------------------- /pony/orm/tests/test_tracked_value.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from pony.orm.ormtypes import TrackedList, TrackedDict, TrackedValue 4 | 5 | class Object(object): 6 | def __init__(self): 7 | self.on_attr_changed = None 8 | def _attr_changed_(self, attr): 9 | if self.on_attr_changed is not None: 10 | self.on_attr_changed(attr) 11 | 12 | 13 | class Attr(object): 14 | pass 15 | 16 | 17 | class TestTrackedValue(unittest.TestCase): 18 | 19 | def test_make(self): 20 | obj = Object() 21 | attr = Attr() 22 | value = {'items': ['one', 'two', 'three']} 23 | tracked_value = TrackedValue.make(obj, attr, value) 24 | self.assertEqual(type(tracked_value), TrackedDict) 25 | self.assertEqual(type(tracked_value['items']), TrackedList) 26 | 27 | def test_dict_setitem(self): 28 | obj = Object() 29 | attr = Attr() 30 | value = {'items': ['one', 'two', 'three']} 31 | tracked_value = TrackedValue.make(obj, attr, value) 32 | log = [] 33 | obj.on_attr_changed = lambda x: log.append(x) 34 | tracked_value['items'] = [1, 2, 3] 35 | self.assertEqual(log, [attr]) 36 | 37 | def test_list_append(self): 38 | obj = Object() 39 | attr = Attr() 40 | value = {'items': ['one', 'two', 'three']} 41 | tracked_value = TrackedValue.make(obj, attr, value) 42 | log = [] 43 | obj.on_attr_changed = lambda x: log.append(x) 44 | tracked_value['items'].append('four') 45 | self.assertEqual(log, [attr]) 46 | 47 | def test_list_setslice(self): 48 | obj = Object() 49 | attr = Attr() 50 | value = {'items': ['one', 'two', 'three']} 51 | tracked_value = TrackedValue.make(obj, attr, value) 52 | log = [] 53 | obj.on_attr_changed = lambda x: log.append(x) 54 | tracked_value['items'][1:2] = ['a', 'b', 'c'] 55 | self.assertEqual(log, [attr]) 56 | self.assertEqual(tracked_value['items'], ['one', 'a', 'b', 'c', 'three']) 57 | -------------------------------------------------------------------------------- /pony/orm/tests/test_transaction_lock.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | 4 | from pony.orm import * 5 | from pony.orm.tests import setup_database, teardown_database 6 | 7 | db = Database() 8 | 9 | 10 | class TestPost(db.Entity): 11 | category = Optional('TestCategory') 12 | name = Optional(str, default='Noname') 13 | 14 | 15 | class TestCategory(db.Entity): 16 | posts = Set(TestPost) 17 | 18 | 19 | class TransactionLockTestCase(unittest.TestCase): 20 | @classmethod 21 | def setUpClass(cls): 22 | setup_database(db) 23 | with db_session: 24 | cls.post = TestPost(id=1) 25 | 26 | @classmethod 27 | def tearDownClass(cls): 28 | teardown_database(db) 29 | 30 | __call__ = db_session(unittest.TestCase.__call__) 31 | 32 | def tearDown(self): 33 | rollback() 34 | 35 | def test_create(self): 36 | p = TestPost(id=2) 37 | p.flush() 38 | cache = db._get_cache() 39 | self.assertEqual(cache.immediate, True) 40 | self.assertEqual(cache.in_transaction, True) 41 | 42 | def test_update(self): 43 | p = TestPost[self.post.id] 44 | p.name = 'Trash' 45 | p.flush() 46 | cache = db._get_cache() 47 | self.assertEqual(cache.immediate, True) 48 | self.assertEqual(cache.in_transaction, True) 49 | 50 | def test_delete(self): 51 | p = TestPost[self.post.id] 52 | p.delete() 53 | flush() 54 | cache = db._get_cache() 55 | self.assertEqual(cache.immediate, True) 56 | self.assertEqual(cache.in_transaction, True) 57 | -------------------------------------------------------------------------------- /pony/orm/tests/test_validate.py: -------------------------------------------------------------------------------- 1 | import unittest, warnings 2 | 3 | from pony.orm import * 4 | from pony.orm import core 5 | from pony.orm.tests.testutils import raises_exception 6 | from pony.orm.tests import db_params, teardown_database 7 | 8 | db = Database() 9 | 10 | class Person(db.Entity): 11 | id = PrimaryKey(int) 12 | name = Required(str) 13 | tel = Optional(str) 14 | 15 | 16 | table_name = 'person' 17 | 18 | class TestValidate(unittest.TestCase): 19 | @classmethod 20 | def setUpClass(cls): 21 | db.bind(**db_params) 22 | db.generate_mapping(check_tables=False) 23 | db.drop_all_tables(with_all_data=True) 24 | with db_session(ddl=True): 25 | db.execute(""" 26 | create table "%s"( 27 | id int primary key, 28 | name text, 29 | tel text 30 | ) 31 | """ % table_name) 32 | 33 | @classmethod 34 | def tearDownClass(cls): 35 | teardown_database(db) 36 | 37 | @db_session 38 | def setUp(self): 39 | db.execute('delete from "%s"' % table_name) 40 | registry = getattr(core, '__warningregistry__', {}) 41 | for key in list(registry): 42 | if type(key) is not tuple: continue 43 | text, category, lineno = key 44 | if category is DatabaseContainsIncorrectEmptyValue: 45 | del registry[key] 46 | 47 | @db_session 48 | def test_1a(self): 49 | with warnings.catch_warnings(): 50 | warnings.simplefilter('ignore', DatabaseContainsIncorrectEmptyValue) 51 | db.insert(table_name, id=1, name='', tel='111') 52 | p = Person.get(id=1) 53 | self.assertEqual(p.name, '') 54 | 55 | @raises_exception(DatabaseContainsIncorrectEmptyValue, 56 | 'Database contains empty string for required attribute Person.name') 57 | @db_session 58 | def test_1b(self): 59 | with warnings.catch_warnings(): 60 | warnings.simplefilter('error', DatabaseContainsIncorrectEmptyValue) 61 | db.insert(table_name, id=1, name='', tel='111') 62 | p = Person.get(id=1) 63 | 64 | @db_session 65 | def test_2a(self): 66 | with warnings.catch_warnings(): 67 | warnings.simplefilter('ignore', DatabaseContainsIncorrectEmptyValue) 68 | db.insert(table_name, id=1, name=None, tel='111') 69 | p = Person.get(id=1) 70 | self.assertEqual(p.name, None) 71 | 72 | @raises_exception(DatabaseContainsIncorrectEmptyValue, 73 | 'Database contains NULL for required attribute Person.name') 74 | @db_session 75 | def test_2b(self): 76 | with warnings.catch_warnings(): 77 | warnings.simplefilter('error', DatabaseContainsIncorrectEmptyValue) 78 | db.insert(table_name, id=1, name=None, tel='111') 79 | p = Person.get(id=1) 80 | 81 | 82 | if __name__ == '__main__': 83 | unittest.main() 84 | -------------------------------------------------------------------------------- /pony/orm/tests/test_volatile.py: -------------------------------------------------------------------------------- 1 | import sys, unittest 2 | 3 | from pony.orm import * 4 | from pony.orm.tests.testutils import * 5 | from pony.orm.tests import setup_database, teardown_database 6 | 7 | 8 | class TestVolatile1(unittest.TestCase): 9 | def setUp(self): 10 | db = self.db = Database() 11 | 12 | class Item(self.db.Entity): 13 | name = Required(str) 14 | index = Required(int, volatile=True) 15 | 16 | setup_database(db) 17 | 18 | with db_session: 19 | Item(id=1, name='A', index=1) 20 | Item(id=2, name='B', index=2) 21 | Item(id=3, name='C', index=3) 22 | 23 | def tearDown(self): 24 | teardown_database(self.db) 25 | 26 | @db_session 27 | def test_1(self): 28 | db = self.db 29 | Item = db.Item 30 | db.execute('update "item" set "index" = "index" + 1') 31 | items = Item.select(lambda item: item.index > 0).order_by(Item.id)[:] 32 | a, b, c = items 33 | self.assertEqual(a.index, 2) 34 | self.assertEqual(b.index, 3) 35 | self.assertEqual(c.index, 4) 36 | c.index = 1 37 | items = Item.select()[:] # force re-read from the database 38 | self.assertEqual(c.index, 1) 39 | self.assertEqual(a.index, 2) 40 | self.assertEqual(b.index, 3) 41 | 42 | 43 | @db_session 44 | def test_2(self): 45 | Item = self.db.Item 46 | item = Item[1] 47 | item.name = 'X' 48 | item.flush() 49 | self.assertEqual(item.index, 1) 50 | 51 | 52 | class TestVolatile2(unittest.TestCase): 53 | def setUp(self): 54 | db = self.db = Database() 55 | 56 | class Group(db.Entity): 57 | number = PrimaryKey(int) 58 | students = Set('Student', volatile=True) 59 | 60 | class Student(db.Entity): 61 | id = PrimaryKey(int) 62 | name = Required(str) 63 | group = Required('Group') 64 | courses = Set('Course') 65 | 66 | class Course(db.Entity): 67 | id = PrimaryKey(int) 68 | name = Required(str) 69 | students = Set('Student', volatile=True) 70 | 71 | setup_database(db) 72 | 73 | with db_session: 74 | g1 = Group(number=123) 75 | s1 = Student(id=1, name='A', group=g1) 76 | s2 = Student(id=2, name='B', group=g1) 77 | c1 = Course(id=1, name='C1', students=[s1, s2]) 78 | c2 = Course(id=2, name='C1', students=[s1]) 79 | 80 | self.Group = Group 81 | self.Student = Student 82 | self.Course = Course 83 | 84 | def tearDown(self): 85 | teardown_database(self.db) 86 | 87 | def test_1(self): 88 | self.assertTrue(self.Group.students.is_volatile) 89 | self.assertTrue(self.Student.group.is_volatile) 90 | self.assertTrue(self.Student.courses.is_volatile) 91 | self.assertTrue(self.Course.students.is_volatile) 92 | 93 | def test_2(self): 94 | with db_session: 95 | g1 = self.Group[123] 96 | students = set(s.id for s in g1.students) 97 | self.assertEqual(students, {1, 2}) 98 | self.db.execute('''insert into student values(3, 'C', 123)''') 99 | g1.students.load() 100 | students = set(s.id for s in g1.students) 101 | self.assertEqual(students, {1, 2, 3}) 102 | 103 | def test_3(self): 104 | with db_session: 105 | g1 = self.Group[123] 106 | students = set(s.id for s in g1.students) 107 | self.assertEqual(students, {1, 2}) 108 | self.db.execute("insert into student values(3, 'C', 123)") 109 | s3 = self.Student[3] 110 | students = set(s.id for s in g1.students) 111 | self.assertEqual(students, {1, 2, 3}) 112 | 113 | def test_4(self): 114 | with db_session: 115 | c1 = self.Course[1] 116 | students = set(s.id for s in c1.students) 117 | self.assertEqual(students, {1, 2}) 118 | self.db.execute("insert into student values(3, 'C', 123)") 119 | attr = self.Student.courses 120 | self.db.execute("insert into %s values(1, 3)" % attr.table) 121 | c1.students.load() 122 | students = set(s.id for s in c1.students) 123 | self.assertEqual(students, {1, 2, 3}) 124 | 125 | 126 | if __name__ == '__main__': 127 | unittest.main() 128 | -------------------------------------------------------------------------------- /pony/orm/tests/testutils.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function, division 2 | 3 | import re 4 | from contextlib import contextmanager 5 | 6 | from pony.orm.core import Database 7 | from pony.utils import import_module 8 | 9 | def check_exception_msg(test_case, exc_msg, test_msg=None): 10 | if test_msg is None: return 11 | error_template = "incorrect exception message. expected '%s', got '%s'" 12 | error_msg = error_template % (test_msg, exc_msg) 13 | assert test_msg not in ('...', '....', '.....', '......') 14 | if '...' not in test_msg: 15 | test_case.assertEqual(test_msg, exc_msg, error_msg) 16 | else: 17 | pattern = ''.join( 18 | '[%s]' % char for char in test_msg.replace('\\', '\\\\') 19 | .replace('[', '\\[') 20 | ).replace('[.][.][.]', '.*') 21 | regex = re.compile(pattern) 22 | if not regex.match(exc_msg): 23 | test_case.fail(error_template % (test_msg, exc_msg)) 24 | 25 | def raises_exception(exc_class, test_msg=None): 26 | def decorator(func): 27 | def wrapper(test_case, *args, **kwargs): 28 | try: 29 | func(test_case, *args, **kwargs) 30 | test_case.fail("Expected exception %s wasn't raised" % exc_class.__name__) 31 | except exc_class as e: 32 | if not e.args: test_case.assertEqual(test_msg, None) 33 | else: check_exception_msg(test_case, str(e), test_msg) 34 | wrapper.__name__ = func.__name__ 35 | return wrapper 36 | return decorator 37 | 38 | @contextmanager 39 | def raises_if(test_case, cond, exc_class, test_msg=None): 40 | try: 41 | yield 42 | except exc_class as e: 43 | test_case.assertTrue(cond) 44 | check_exception_msg(test_case, str(e), test_msg) 45 | else: 46 | test_case.assertFalse(cond, "Expected exception %s wasn't raised" % exc_class.__name__) 47 | 48 | def flatten(x): 49 | result = [] 50 | for el in x: 51 | if hasattr(el, "__iter__") and not isinstance(el, str): 52 | result.extend(flatten(el)) 53 | else: 54 | result.append(el) 55 | return result 56 | 57 | class TestConnection(object): 58 | def __init__(con, database): 59 | con.database = database 60 | if database and database.provider_name == 'postgres': 61 | con.autocommit = True 62 | def commit(con): 63 | pass 64 | def rollback(con): 65 | pass 66 | def cursor(con): 67 | return test_cursor 68 | 69 | class TestCursor(object): 70 | def __init__(cursor): 71 | cursor.description = [] 72 | cursor.rowcount = 0 73 | def execute(cursor, sql, args=None): 74 | pass 75 | def fetchone(cursor): 76 | return None 77 | def fetchmany(cursor, size): 78 | return [] 79 | def fetchall(cursor): 80 | return [] 81 | 82 | test_cursor = TestCursor() 83 | 84 | class TestPool(object): 85 | def __init__(pool, database): 86 | pool.database = database 87 | def connect(pool): 88 | return TestConnection(pool.database), True 89 | def release(pool, con): 90 | pass 91 | def drop(pool, con): 92 | pass 93 | def disconnect(pool): 94 | pass 95 | 96 | class TestDatabase(Database): 97 | real_provider_name = None 98 | raw_server_version = None 99 | sql = None 100 | def bind(self, provider, *args, **kwargs): 101 | provider_name = provider 102 | assert isinstance(provider_name, str) 103 | if self.real_provider_name is not None: 104 | provider_name = self.real_provider_name 105 | self.provider_name = provider_name 106 | provider_module = import_module('pony.orm.dbproviders.' + provider_name) 107 | provider_cls = provider_module.provider_cls 108 | raw_server_version = self.raw_server_version 109 | 110 | if raw_server_version is None: 111 | if provider_name == 'sqlite': raw_server_version = '3.7.17' 112 | elif provider_name in ('postgres', 'pygresql'): raw_server_version = '9.2' 113 | elif provider_name == 'oracle': raw_server_version = '11.2.0.2.0' 114 | elif provider_name == 'mysql': raw_server_version = '5.6.11' 115 | else: assert False, provider_name # pragma: no cover 116 | 117 | t = [ int(component) for component in raw_server_version.split('.') ] 118 | if len(t) == 2: t.append(0) 119 | server_version = tuple(t) 120 | if provider_name in ('postgres', 'pygresql'): 121 | server_version = int('%d%02d%02d' % server_version) 122 | 123 | class TestProvider(provider_cls): 124 | json1_available = False # for SQLite 125 | def inspect_connection(provider, connection): 126 | pass 127 | TestProvider.server_version = server_version 128 | 129 | kwargs['pony_check_connection'] = False 130 | kwargs['pony_pool_mockup'] = TestPool(self) 131 | Database.bind(self, TestProvider, *args, **kwargs) 132 | def _execute(database, sql, globals, locals, frame_depth): 133 | assert False # pragma: no cover 134 | def _exec_sql(database, sql, arguments=None, returning_id=False): 135 | assert type(arguments) is not list and not returning_id 136 | database.sql = sql 137 | database.arguments = arguments 138 | return test_cursor 139 | def generate_mapping(database, filename=None, check_tables=True, create_tables=False): 140 | return Database.generate_mapping(database, filename, create_tables=False, check_tables=False) 141 | -------------------------------------------------------------------------------- /pony/py23compat.py: -------------------------------------------------------------------------------- 1 | import sys, platform 2 | 3 | PYPY = platform.python_implementation() == 'PyPy' 4 | PY36 = sys.version_info[:2] >= (3, 6) 5 | PY37 = sys.version_info[:2] >= (3, 7) 6 | PY38 = sys.version_info[:2] >= (3, 8) 7 | PY39 = sys.version_info[:2] >= (3, 9) 8 | PY310 = sys.version_info[:2] >= (3, 10) 9 | PY311 = sys.version_info[:2] >= (3, 11) 10 | PY312 = sys.version_info[:2] >= (3, 12) 11 | 12 | unicode = str 13 | buffer = bytes 14 | int_types = (int,) 15 | 16 | def cmp(a, b): 17 | return (a > b) - (a < b) 18 | -------------------------------------------------------------------------------- /pony/thirdparty/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ponyorm/pony/b9375605edacde9e68e3fc5c578a4b090a36cb8d/pony/thirdparty/__init__.py -------------------------------------------------------------------------------- /pony/utils/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from .utils import * 4 | from .properties import * -------------------------------------------------------------------------------- /pony/utils/properties.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class cached_property(object): 4 | """ 5 | A property that is only computed once per instance and then replaces itself 6 | with an ordinary attribute. Deleting the attribute resets the property. 7 | Source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76 8 | """ # noqa 9 | 10 | def __init__(self, func): 11 | self.__doc__ = getattr(func, '__doc__') 12 | self.func = func 13 | 14 | def __get__(self, obj, cls): 15 | if obj is None: 16 | return self 17 | value = obj.__dict__[self.func.__name__] = self.func(obj) 18 | return value 19 | 20 | 21 | class class_property(object): 22 | """ 23 | Read-only class property 24 | """ 25 | 26 | def __init__(self, func): 27 | self.func = func 28 | 29 | def __get__(self, instance, cls): 30 | return self.func(cls) 31 | 32 | class class_cached_property(object): 33 | 34 | def __init__(self, func): 35 | self.func = func 36 | 37 | def __get__(self, obj, cls): 38 | value = self.func(cls) 39 | setattr(cls, self.func.__name__, value) 40 | return value -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | from setuptools import setup 4 | import sys 5 | 6 | import unittest 7 | 8 | def test_suite(): 9 | test_loader = unittest.TestLoader() 10 | test_suite = test_loader.discover('pony.orm.tests', pattern='test_*.py') 11 | return test_suite 12 | 13 | name = "pony" 14 | version = __import__('pony').__version__ 15 | description = "Pony Object-Relational Mapper" 16 | long_description = """ 17 | About 18 | ========= 19 | Pony ORM is easy to use and powerful object-relational mapper for Python. 20 | Using Pony, developers can create and maintain database-oriented software applications 21 | faster and with less effort. One of the most interesting features of Pony is 22 | its ability to write queries to the database using generator expressions. 23 | Pony then analyzes the abstract syntax tree of a generator and translates it 24 | to its SQL equivalent. 25 | 26 | Following is an example of a query in Pony:: 27 | 28 | select(p for p in Product if p.name.startswith('A') and p.cost <= 1000) 29 | 30 | Such approach simplify the code and allows a programmer to concentrate 31 | on the business logic of the application. 32 | 33 | Pony translates queries to SQL using a specific database dialect. 34 | Currently Pony works with SQLite, MySQL, PostgreSQL and Oracle databases. 35 | 36 | The package `pony.orm.examples `_ 37 | contains several examples. 38 | 39 | Installation 40 | ================= 41 | :: 42 | 43 | pip install pony 44 | 45 | Entity-Relationship Diagram Editor 46 | ============================================= 47 | `Pony online ER Diagram Editor `_ is a great tool for prototyping. 48 | You can draw your ER diagram online, generate Pony entity declarations or SQL script for 49 | creating database schema based on the diagram and start working with the database in seconds. 50 | 51 | Pony ORM Links: 52 | ================= 53 | - Main site: https://ponyorm.com 54 | - Documentation: https://docs.ponyorm.com 55 | - GitHub: https://github.com/ponyorm/pony 56 | - Mailing list: http://ponyorm-list.ponyorm.com 57 | - ER Diagram Editor: https://editor.ponyorm.com 58 | - Blog: https://blog.ponyorm.com 59 | """ 60 | 61 | classifiers = [ 62 | 'Development Status :: 4 - Beta', 63 | 'Intended Audience :: Developers', 64 | 'License :: OSI Approved :: Apache Software License', 65 | 'Operating System :: OS Independent', 66 | 'Programming Language :: Python', 67 | 'Programming Language :: Python :: 3', 68 | 'Programming Language :: Python :: 3.8', 69 | 'Programming Language :: Python :: 3.9', 70 | 'Programming Language :: Python :: 3.10', 71 | 'Programming Language :: Python :: 3.11', 72 | 'Programming Language :: Python :: 3.12', 73 | 'Programming Language :: Python :: Implementation :: PyPy', 74 | 'Topic :: Software Development :: Libraries', 75 | 'Topic :: Database' 76 | ] 77 | 78 | author = ', '.join([ 79 | 'Alexander Kozlovsky ', 80 | 'Alexey Malashkevich ', 81 | 'Alexander Tischenko ' 82 | ]) 83 | author_email = "team@ponyorm.com" 84 | url = "https://ponyorm.com" 85 | project_urls = { 86 | "Documentation": "https://docs.ponyorm.org", 87 | "Source": "https://github.com/ponyorm/pony", 88 | } 89 | licence = "Apache License Version 2.0" 90 | 91 | packages = [ 92 | "pony", 93 | "pony.flask", 94 | "pony.flask.example", 95 | "pony.orm", 96 | "pony.orm.dbproviders", 97 | "pony.orm.examples", 98 | "pony.orm.integration", 99 | "pony.orm.tests", 100 | "pony.thirdparty", 101 | "pony.utils" 102 | ] 103 | 104 | package_data = { 105 | 'pony.flask.example': ['templates/*.html'], 106 | 'pony.orm.tests': ['queries.txt'] 107 | } 108 | 109 | download_url = "http://pypi.python.org/pypi/pony/" 110 | 111 | if __name__ == "__main__": 112 | pv = sys.version_info[:2] 113 | if pv < (3, 8) or pv > (3, 12): 114 | s = "Sorry, but %s %s requires Python of one of the following versions: 3.8-3.12." \ 115 | " You have version %s" 116 | print(s % (name, version, sys.version.split(' ', 1)[0])) 117 | sys.exit(1) 118 | 119 | setup( 120 | name=name, 121 | version=version, 122 | description=description, 123 | long_description=long_description, 124 | classifiers=classifiers, 125 | author=author, 126 | author_email=author_email, 127 | url=url, 128 | project_urls=project_urls, 129 | license=licence, 130 | packages=packages, 131 | package_data=package_data, 132 | download_url=download_url, 133 | test_suite='setup.test_suite' 134 | ) 135 | --------------------------------------------------------------------------------