Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reworked the neuron.hclass3 module #1096

Merged
merged 31 commits into from
Apr 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
0286454
added pyenv's .python-version to gitignore
Mar 20, 2021
e447ce7
prevent import py2/3 module in py3/2. removed `exec` wrapper from hclass
Mar 20, 2021
3d996e5
Changed comment and removed non-existing `nonlocal_hclass` import
Mar 20, 2021
046fab4
Removed traling whitespaces and double newline at eof
Mar 20, 2021
d0876c7
Removed the MetaHocObject metaclass and added `nonlocal_hclass` factory
Mar 20, 2021
9d5c8f3
New `HocBaseObject`; (nonlocal_)hclass uses this new base.
Mar 20, 2021
cc31bff
Added dev note to demystify quintessential link between HOC & Python
Mar 20, 2021
3b59b2f
moved __all__ to PEP8 location
Mar 20, 2021
23e3064
Fixed error with grandchildren of `HocBaseObject`
Mar 20, 2021
20a6e95
Apply changes only to Python 3.6+ where metaclass alternative is availbl
Mar 20, 2021
475e981
fixed import typo
Mar 20, 2021
d2063bf
hclass of hoc_type should precede use of hoc.HocObject API's
Mar 20, 2021
3c5b4b2
Fixed usage of module_name
Mar 20, 2021
080f14a
added hclass35.py to Makefile, excessive trailing newlines.
Mar 20, 2021
9bb623c
`module` does not exist, see details on mixed approaches in PR#1096
Mar 20, 2021
ff1d739
black formatting & updated hclass2 derived docstrings
Mar 27, 2021
98d43cc
Store dummy modules on `neuron` module to better emulate submodules
Mar 27, 2021
6a52d62
Add a TypeError if init but not new has been given (see #1129)
Mar 27, 2021
091bced
Added _pyobj_enabled flag to check whether Python object interface is up
Mar 27, 2021
696f63c
Explicitly defined __new__ for 3.6+ pyobj compatibility
Mar 27, 2021
c0847f1
Class composition is allowed if HOC types are the same
Mar 27, 2021
2977551
added tests for HOC type Python classes, test only in Python 3.6+
Mar 27, 2021
bdff470
Merge branch 'master' into hclass-nometa-nonlocal
Helveg Mar 27, 2021
7cf60ad
Removed 'super()' call for Python 2
Mar 27, 2021
bb9bc43
Merge branch 'master' into hclass-nometa-nonlocal
Helveg Apr 1, 2021
b5152a4
Merge branch 'master' into hclass-nometa-nonlocal
ramcdougal Apr 13, 2021
4ffeb35
Revert "added hclass35.py to Makefile, excessive trailing newlines."
Mar 20, 2021
987e799
Added hclass35 to Makefile
Helveg Apr 16, 2021
393939b
Revert "Removed traling whitespaces and double newline at eof"
Mar 20, 2021
b6d25bc
Reinstated deprecation messages
Helveg Apr 16, 2021
3722763
Merged hclass and nonlocal_hclass
Helveg Apr 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ x86_64
__pycache__
venv
virtualenv
*.o
.python-version
*.o
*.lo

# These files are generated at build time
Expand Down
1 change: 1 addition & 0 deletions share/lib/python/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ neuron/units.py \
neuron/gui.py \
neuron/hclass2.py \
neuron/hclass3.py \
neuron/hclass35.py \
neuron/__init__.py \
neuron/psection.py \
neuron/sections.py \
Expand Down
77 changes: 45 additions & 32 deletions share/lib/python/neuron/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,24 @@ def test_rxd(exitOnError=True):
# using the idiom self.basemethod = self.baseattr('methodname')
# ------------------------------------------------------------------------------

import sys, types

# Flag for the Python objects interface
_pyobj_enabled = False
# Load the `hclass` factory for the correct Python version 2/3 and prevent the
# incorrect module source code from being opened by creating an empty module.
Helveg marked this conversation as resolved.
Show resolved Hide resolved
if sys.version_info[0] == 2:
hclass3 = sys.modules["neuron.hclass3"] = types.ModuleType("neuron.hclass3")
from neuron.hclass2 import hclass
else:
from neuron.hclass3 import hclass
hclass2 = sys.modules["neuron.hclass2"] = types.ModuleType("neuron.hclass2")
if sys.version_info[0] == 3 and sys.version_info[1] < 6:
import neuron.hclass35
hclass = neuron.hclass35.hclass
hclass3 = neuron.hclass35
else:
from neuron.hclass3 import HocBaseObject, hclass
_pyobj_enabled = True

# global list of paths already loaded by load_mechanisms
nrn_dll_loaded = []
Expand Down Expand Up @@ -370,13 +384,13 @@ def xopen(*args, **kwargs):


Description:
``h.xopen()`` executes the commands in ``hocfile``. This is a convenient way
to define user functions and procedures.
An optional second argument is the RCS revision number in the form of a
string. The RCS file with that revision number is checked out into a
temporary file and executed. The temporary file is then removed. A file
of the same primary name is unaffected.
``h.xopen()`` executes the commands in ``hocfile``. This is a convenient way
to define user functions and procedures.
An optional second argument is the RCS revision number in the form of a
string. The RCS file with that revision number is checked out into a
temporary file and executed. The temporary file is then removed. A file
of the same primary name is unaffected.

This function is deprecated and will be removed in a future release.
Use ``h.xopen`` instead.
"""
Expand All @@ -386,7 +400,7 @@ def xopen(*args, **kwargs):

def quit(*args, **kwargs):
"""
Exits the program. Can be used as the action of a button. If edit buffers
Exits the program. Can be used as the action of a button. If edit buffers
are open you will be asked if you wish to save them before the final exit.

This function is deprecated and will be removed in a future release.
Expand All @@ -395,7 +409,7 @@ def quit(*args, **kwargs):
"""
warnings.warn("neuron.quit() is deprecated; use h.quit() or sys.exit() instead", DeprecationWarning, stacklevel=2)
return h.quit(*args, **kwargs)



def hoc_execute(hoc_commands, comment=None):
Expand Down Expand Up @@ -447,55 +461,55 @@ def init():

By default, the units used by h.finitialize are in mV, but you can be explicit using
NEURON's unit's library, e.g.

.. code-block:: python

from neuron.units import mV
h.finitialize(-65 * mV)

https://www.neuron.yale.edu/neuron/static/py_doc/simctrl/programmatic.html?#finitialize

"""
warnings.warn("neuron.init() is deprecated; use h.init() instead", DeprecationWarning, stacklevel=2)

h.finitialize()

def run(tstop):
"""
function run(tstop)

Run the simulation (advance the solver) until tstop [ms]

`h.run()` and `h.continuerun(tstop)` are more powerful solutions defined in the `stdrun.hoc` library.

** This function exists for historical purposes. Use in new code is not recommended. **

This function is deprecated and will be removed in a future
release.
release.

For running a simulation, consider doing the following instead:

Begin your code with

.. code-block:: python

from neuron import h
from neuron.units import ms, mV
h.load_file('stdrun.hoc')

Then when it is time to initialize and run the simulation:

.. code-block:: python

h.finitialize(-65 * mV)
h.continuerun(100 * ms)

where the initial membrane potential and the simulation run time are adjusted as appropriate
for your model.

"""
warnings.warn("neuron.run(tstop) is deprecated; use h.stdinit() and h.continuerun(tstop) instead", DeprecationWarning, stacklevel=2)

h('tstop = %g' % tstop)
h('while (t < tstop) { fadvance() }')
# what about pc.psolve(tstop)?
Expand Down Expand Up @@ -667,7 +681,7 @@ def _declare_contour(secobj, obj, name):
center_vec = secobj.contourcenter(secobj.raw.getrow(0), secobj.raw.getrow(1), secobj.raw.getrow(2))
x0, y0, z0 = [center_vec.x[i] for i in range(3)]
# store a couple of points to check if the section has been moved
pts = [(sec.x3d(i),sec.y3d(i),sec.z3d(i)) for i in [0, sec.n3d()-1]]
pts = [(sec.x3d(i),sec.y3d(i),sec.z3d(i)) for i in [0, sec.n3d()-1]]
# (is_stack, x, y, z, xcenter, ycenter, zcenter)
_sec_db[sec.hoc_internal_name()] = (True if secobj.contour_list else False, secobj.raw.getrow(0).c(j), secobj.raw.getrow(1).c(j), secobj.raw.getrow(2).c(j), x0, y0, z0, pts)

Expand Down Expand Up @@ -796,7 +810,7 @@ class _RangeVarPlot(_WrapperPlot):
fig.show()

pyplot.show()
Helveg marked this conversation as resolved.
Show resolved Hide resolved

# plotnine/ggplot
p9.ggplot() + r.plot(p9)

Expand Down Expand Up @@ -1060,10 +1074,10 @@ def mark(self, segment, marker='or', **kwargs):
if secs is None:
secs = list(h.allsec())


if variable is None:
kwargs.setdefault('color', 'black')

data = []
for sec in secs:
xs = [sec.x3d(i) for i in range(sec.n3d())]
Expand Down Expand Up @@ -1392,7 +1406,7 @@ def _nrnpy_rvp_pyobj_callback(f):
f_type = str(type(f))
if f_type not in ("<class 'neuron.rxd.species.SpeciesOnRegion'>", "<class 'neuron.rxd.species.Species'>"):
return f

# if we're here, f is an rxd variable, and we return a function that looks
# up the weighted average concentration given an x and h.cas()
# this is not particularly efficient so it is probably better to use this for
Expand Down Expand Up @@ -1432,4 +1446,3 @@ def clear_gui_callback():
nrnpy_set_gui_callback(None)
except:
pass

62 changes: 37 additions & 25 deletions share/lib/python/neuron/hclass2.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,53 @@
#Python2 only
# Python2 only
# ------------------------------------------------------------------------------
# class factory for subclassing h.anyclass
# h.anyclass methods may be overridden. If so the base method can be called
# using the idiom self.basemethod = self.baseattr('methodname')
# ------------------------------------------------------------------------------

from neuron import h, hoc
import nrn

#avoid syntax error if compiled by python 3
exec('''

class MetaHocObject(type):
"""Provides Exception for Inheritance of multiple HocObject"""
def __new__(cls, name, bases, attrs):
#print cls, name, bases
m = []
for b in bases:
if issubclass(b, hoc.HocObject):
m.append(b.__name__)
if (len(m) > 1):
raise TypeError('Multiple Inheritance of HocObject in %s' % name
+ ' through %s not allowed' % ','.join(m))
#note that join(b.__name__ for b in m) is not valid for Python 2.3

return type.__new__(cls, name, bases, attrs)
"""
Provides error when trying to compose a class of multiple HOC types.
"""

def __new__(cls, name, bases, attrs):
m = []
for b in bases:
if issubclass(b, hoc.HocObject):
m.append(b.__name__)
if len(m) > 1:
raise TypeError(
"Multiple Inheritance of HocObject in %s" % name
+ " through %s not allowed" % ",".join(m)
)

return type.__new__(cls, name, bases, attrs)


def hclass(c):
"""Class factory for subclassing h.anyclass. E.g. class MyList(hclass(h.List)):..."""
if c == h.Section :
"""
Class factory for subclassing any HOC type.

Example:

.. code-block:: python

class MyList(hclass(h.List)):
pass
"""
if c == h.Section:
return nrn.Section
#class hc(hoc.HocObject, metaclass=MetaHocObject):

class hc(hoc.HocObject):
def __new__(cls, *args, **kwds):
kwds2 = {'hocbase': cls.htype}
if 'sec' in kwds:
kwds2['sec'] = kwds['sec']
kwds2 = {"hocbase": cls.htype}
if "sec" in kwds:
kwds2["sec"] = kwds["sec"]
return hoc.HocObject.__new__(cls, *args, **kwds2)
setattr(hc, 'htype', c)

setattr(hc, "htype", c)
return hc
''')
Loading